4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1010 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1011 T CST Timezone setting of the machine running the code
1012 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1015 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d')); //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1020 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1023 * Here are some standard date/time patterns that you might find helpful. They
1024 * are not part of the source of Date.js, but to use them you can simply copy this
1025 * block of code into any script that is included after Date.js and they will also become
1026 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1029 ISO8601Long:"Y-m-d H:i:s",
1030 ISO8601Short:"Y-m-d",
1032 LongDate: "l, F d, Y",
1033 FullDateTime: "l, F d, Y g:i:s A",
1036 LongTime: "g:i:s A",
1037 SortableDateTime: "Y-m-d\\TH:i:s",
1038 UniversalSortableDateTime: "Y-m-d H:i:sO",
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1051 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052 * They generate precompiled functions from date formats instead of parsing and
1053 * processing the pattern every time you format a date. These functions are available
1054 * on every Date object (any javascript function).
1056 * The original article and download are here:
1057 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064 Returns the number of milliseconds between this date and date
1065 @param {Date} date (optional) Defaults to now
1066 @return {Number} The diff in milliseconds
1067 @member Date getElapsed
1069 Date.prototype.getElapsed = function(date) {
1070 return Math.abs((date || new Date()).getTime()-this.getTime());
1072 // was in date file..
1076 Date.parseFunctions = {count:0};
1078 Date.parseRegexes = [];
1080 Date.formatFunctions = {count:0};
1083 Date.prototype.dateFormat = function(format) {
1084 if (Date.formatFunctions[format] == null) {
1085 Date.createNewFormat(format);
1087 var func = Date.formatFunctions[format];
1088 return this[func]();
1093 * Formats a date given the supplied format string
1094 * @param {String} format The format string
1095 * @return {String} The formatted date
1098 Date.prototype.format = Date.prototype.dateFormat;
1101 Date.createNewFormat = function(format) {
1102 var funcName = "format" + Date.formatFunctions.count++;
1103 Date.formatFunctions[format] = funcName;
1104 var code = "Date.prototype." + funcName + " = function(){return ";
1105 var special = false;
1107 for (var i = 0; i < format.length; ++i) {
1108 ch = format.charAt(i);
1109 if (!special && ch == "\\") {
1114 code += "'" + String.escape(ch) + "' + ";
1117 code += Date.getFormatCode(ch);
1120 /** eval:var:zzzzzzzzzzzzz */
1121 eval(code.substring(0, code.length - 3) + ";}");
1125 Date.getFormatCode = function(character) {
1126 switch (character) {
1128 return "String.leftPad(this.getDate(), 2, '0') + ";
1130 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1132 return "this.getDate() + ";
1134 return "Date.dayNames[this.getDay()] + ";
1136 return "this.getSuffix() + ";
1138 return "this.getDay() + ";
1140 return "this.getDayOfYear() + ";
1142 return "this.getWeekOfYear() + ";
1144 return "Date.monthNames[this.getMonth()] + ";
1146 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1148 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1150 return "(this.getMonth() + 1) + ";
1152 return "this.getDaysInMonth() + ";
1154 return "(this.isLeapYear() ? 1 : 0) + ";
1156 return "this.getFullYear() + ";
1158 return "('' + this.getFullYear()).substring(2, 4) + ";
1160 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1162 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1164 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1166 return "this.getHours() + ";
1168 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1170 return "String.leftPad(this.getHours(), 2, '0') + ";
1172 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1174 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1176 return "this.getGMTOffset() + ";
1178 return "this.getGMTColonOffset() + ";
1180 return "this.getTimezone() + ";
1182 return "(this.getTimezoneOffset() * -60) + ";
1184 return "'" + String.escape(character) + "' + ";
1189 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1191 * the date format that is not specified will default to the current date value for that part. Time parts can also
1192 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1193 * string or the parse operation will fail.
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1208 * @param {String} input The unparsed date as a string
1209 * @param {String} format The format the date is in
1210 * @return {Date} The parsed date
1213 Date.parseDate = function(input, format) {
1214 if (Date.parseFunctions[format] == null) {
1215 Date.createParser(format);
1217 var func = Date.parseFunctions[format];
1218 return Date[func](input);
1223 Date.createParser = function(format) {
1224 var funcName = "parse" + Date.parseFunctions.count++;
1225 var regexNum = Date.parseRegexes.length;
1226 var currentGroup = 1;
1227 Date.parseFunctions[format] = funcName;
1229 var code = "Date." + funcName + " = function(input){\n"
1230 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231 + "var d = new Date();\n"
1232 + "y = d.getFullYear();\n"
1233 + "m = d.getMonth();\n"
1234 + "d = d.getDate();\n"
1235 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236 + "if (results && results.length > 0) {";
1239 var special = false;
1241 for (var i = 0; i < format.length; ++i) {
1242 ch = format.charAt(i);
1243 if (!special && ch == "\\") {
1248 regex += String.escape(ch);
1251 var obj = Date.formatCodeToRegex(ch, currentGroup);
1252 currentGroup += obj.g;
1254 if (obj.g && obj.c) {
1260 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261 + "{v = new Date(y, m, d, h, i, s);}\n"
1262 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265 + "{v = new Date(y, m, d, h);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267 + "{v = new Date(y, m, d);}\n"
1268 + "else if (y >= 0 && m >= 0)\n"
1269 + "{v = new Date(y, m);}\n"
1270 + "else if (y >= 0)\n"
1271 + "{v = new Date(y);}\n"
1272 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278 /** eval:var:zzzzzzzzzzzzz */
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284 switch (character) {
1288 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292 s:"(\\d{1,2})"}; // day of month without leading zeroes
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{2})"}; // day of month with leading zeroes
1300 s:"(?:" + Date.dayNames.join("|") + ")"};
1304 s:"(?:st|nd|rd|th)"};
1319 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320 s:"(" + Date.monthNames.join("|") + ")"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1343 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1347 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1352 c:"if (results[" + currentGroup + "] == 'am') {\n"
1353 + "if (h == 12) { h = 0; }\n"
1354 + "} else { if (h < 12) { h += 12; }}",
1358 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1365 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1374 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1378 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383 "o = results[", currentGroup, "];\n",
1384 "var sn = o.substring(0,1);\n", // get + / - sign
1385 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1390 s:"([+\-]\\d{2,4})"};
1396 "o = results[", currentGroup, "];\n",
1397 "var sn = o.substring(0,1);\n",
1398 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1399 "var mn = o.substring(4,6) % 60;\n",
1400 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1401 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1411 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1412 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1416 s:String.escape(character)};
1421 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1422 * @return {String} The abbreviated timezone name (e.g. 'CST')
1424 Date.prototype.getTimezone = function() {
1425 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1429 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1430 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1432 Date.prototype.getGMTOffset = function() {
1433 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1434 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1435 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1439 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1440 * @return {String} 2-characters representing hours and 2-characters representing minutes
1441 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1443 Date.prototype.getGMTColonOffset = function() {
1444 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1445 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1447 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1451 * Get the numeric day number of the year, adjusted for leap year.
1452 * @return {Number} 0 through 364 (365 in leap years)
1454 Date.prototype.getDayOfYear = function() {
1456 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1457 for (var i = 0; i < this.getMonth(); ++i) {
1458 num += Date.daysInMonth[i];
1460 return num + this.getDate() - 1;
1464 * Get the string representation of the numeric week number of the year
1465 * (equivalent to the format specifier 'W').
1466 * @return {String} '00' through '52'
1468 Date.prototype.getWeekOfYear = function() {
1469 // Skip to Thursday of this week
1470 var now = this.getDayOfYear() + (4 - this.getDay());
1471 // Find the first Thursday of the year
1472 var jan1 = new Date(this.getFullYear(), 0, 1);
1473 var then = (7 - jan1.getDay() + 4);
1474 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1478 * Whether or not the current date is in a leap year.
1479 * @return {Boolean} True if the current date is in a leap year, else false
1481 Date.prototype.isLeapYear = function() {
1482 var year = this.getFullYear();
1483 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1487 * Get the first day of the current month, adjusted for leap year. The returned value
1488 * is the numeric day index within the week (0-6) which can be used in conjunction with
1489 * the {@link #monthNames} array to retrieve the textual day name.
1492 var dt = new Date('1/10/2007');
1493 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1495 * @return {Number} The day number (0-6)
1497 Date.prototype.getFirstDayOfMonth = function() {
1498 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1499 return (day < 0) ? (day + 7) : day;
1503 * Get the last day of the current month, adjusted for leap year. The returned value
1504 * is the numeric day index within the week (0-6) which can be used in conjunction with
1505 * the {@link #monthNames} array to retrieve the textual day name.
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1511 * @return {Number} The day number (0-6)
1513 Date.prototype.getLastDayOfMonth = function() {
1514 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1515 return (day < 0) ? (day + 7) : day;
1520 * Get the first date of this date's month
1523 Date.prototype.getFirstDateOfMonth = function() {
1524 return new Date(this.getFullYear(), this.getMonth(), 1);
1528 * Get the last date of this date's month
1531 Date.prototype.getLastDateOfMonth = function() {
1532 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 * Get the number of days in the current month, adjusted for leap year.
1536 * @return {Number} The number of days in the month
1538 Date.prototype.getDaysInMonth = function() {
1539 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1540 return Date.daysInMonth[this.getMonth()];
1544 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1545 * @return {String} 'st, 'nd', 'rd' or 'th'
1547 Date.prototype.getSuffix = function() {
1548 switch (this.getDate()) {
1565 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568 * An array of textual month names.
1569 * Override these values for international dates, for example...
1570 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1589 * An array of textual day names.
1590 * Override these values for international dates, for example...
1591 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1607 Date.monthNumbers = {
1622 * Creates and returns a new Date instance with the exact same date value as the called instance.
1623 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1624 * variable will also be changed. When the intention is to create a new variable that will not
1625 * modify the original instance, you should create a clone.
1627 * Example of correctly cloning a date:
1630 var orig = new Date('10/1/2006');
1633 document.write(orig); //returns 'Thu Oct 05 2006'!
1636 var orig = new Date('10/1/2006');
1637 var copy = orig.clone();
1639 document.write(orig); //returns 'Thu Oct 01 2006'
1641 * @return {Date} The new Date instance
1643 Date.prototype.clone = function() {
1644 return new Date(this.getTime());
1648 * Clears any time information from this date
1649 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1650 @return {Date} this or the clone
1652 Date.prototype.clearTime = function(clone){
1654 return this.clone().clearTime();
1659 this.setMilliseconds(0);
1664 // safari setMonth is broken
1666 Date.brokenSetMonth = Date.prototype.setMonth;
1667 Date.prototype.setMonth = function(num){
1669 var n = Math.ceil(-num);
1670 var back_year = Math.ceil(n/12);
1671 var month = (n % 12) ? 12 - n % 12 : 0 ;
1672 this.setFullYear(this.getFullYear() - back_year);
1673 return Date.brokenSetMonth.call(this, month);
1675 return Date.brokenSetMonth.apply(this, arguments);
1680 /** Date interval constant
1684 /** Date interval constant
1688 /** Date interval constant
1692 /** Date interval constant
1696 /** Date interval constant
1700 /** Date interval constant
1704 /** Date interval constant
1710 * Provides a convenient method of performing basic date arithmetic. This method
1711 * does not modify the Date instance being called - it creates and returns
1712 * a new Date instance containing the resulting date value.
1717 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1718 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1720 //Negative values will subtract correctly:
1721 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1722 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1724 //You can even chain several calls together in one line!
1725 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1726 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729 * @param {String} interval A valid date interval enum value
1730 * @param {Number} value The amount to add to the current date
1731 * @return {Date} The new Date instance
1733 Date.prototype.add = function(interval, value){
1734 var d = this.clone();
1735 if (!interval || value === 0) return d;
1736 switch(interval.toLowerCase()){
1738 d.setMilliseconds(this.getMilliseconds() + value);
1741 d.setSeconds(this.getSeconds() + value);
1744 d.setMinutes(this.getMinutes() + value);
1747 d.setHours(this.getHours() + value);
1750 d.setDate(this.getDate() + value);
1753 var day = this.getDate();
1755 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758 d.setMonth(this.getMonth() + value);
1761 d.setFullYear(this.getFullYear() + value);
1768 * Ext JS Library 1.1.1
1769 * Copyright(c) 2006-2007, Ext JS, LLC.
1771 * Originally Released Under LGPL - original licence link has changed is not relivant.
1774 * <script type="text/javascript">
1778 * @class Roo.lib.Dom
1781 * Dom utils (from YIU afaik)
1786 * Get the view width
1787 * @param {Boolean} full True will get the full document, otherwise it's the view width
1788 * @return {Number} The width
1791 getViewWidth : function(full) {
1792 return full ? this.getDocumentWidth() : this.getViewportWidth();
1795 * Get the view height
1796 * @param {Boolean} full True will get the full document, otherwise it's the view height
1797 * @return {Number} The height
1799 getViewHeight : function(full) {
1800 return full ? this.getDocumentHeight() : this.getViewportHeight();
1803 getDocumentHeight: function() {
1804 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1805 return Math.max(scrollHeight, this.getViewportHeight());
1808 getDocumentWidth: function() {
1809 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1810 return Math.max(scrollWidth, this.getViewportWidth());
1813 getViewportHeight: function() {
1814 var height = self.innerHeight;
1815 var mode = document.compatMode;
1817 if ((mode || Roo.isIE) && !Roo.isOpera) {
1818 height = (mode == "CSS1Compat") ?
1819 document.documentElement.clientHeight :
1820 document.body.clientHeight;
1826 getViewportWidth: function() {
1827 var width = self.innerWidth;
1828 var mode = document.compatMode;
1830 if (mode || Roo.isIE) {
1831 width = (mode == "CSS1Compat") ?
1832 document.documentElement.clientWidth :
1833 document.body.clientWidth;
1838 isAncestor : function(p, c) {
1845 if (p.contains && !Roo.isSafari) {
1846 return p.contains(c);
1847 } else if (p.compareDocumentPosition) {
1848 return !!(p.compareDocumentPosition(c) & 16);
1850 var parent = c.parentNode;
1855 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858 parent = parent.parentNode;
1864 getRegion : function(el) {
1865 return Roo.lib.Region.getRegion(el);
1868 getY : function(el) {
1869 return this.getXY(el)[1];
1872 getX : function(el) {
1873 return this.getXY(el)[0];
1876 getXY : function(el) {
1877 var p, pe, b, scroll, bd = document.body;
1878 el = Roo.getDom(el);
1879 var fly = Roo.lib.AnimBase.fly;
1880 if (el.getBoundingClientRect) {
1881 b = el.getBoundingClientRect();
1882 scroll = fly(document).getScroll();
1883 return [b.left + scroll.left, b.top + scroll.top];
1889 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1896 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1903 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1904 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1911 if (p != el && pe.getStyle('overflow') != 'visible') {
1919 if (Roo.isSafari && hasAbsolute) {
1924 if (Roo.isGecko && !hasAbsolute) {
1926 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1927 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1931 while (p && p != bd) {
1932 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1944 setXY : function(el, xy) {
1945 el = Roo.fly(el, '_setXY');
1947 var pts = el.translatePoints(xy);
1948 if (xy[0] !== false) {
1949 el.dom.style.left = pts.left + "px";
1951 if (xy[1] !== false) {
1952 el.dom.style.top = pts.top + "px";
1956 setX : function(el, x) {
1957 this.setXY(el, [x, false]);
1960 setY : function(el, y) {
1961 this.setXY(el, [false, y]);
1965 * Portions of this file are based on pieces of Yahoo User Interface Library
1966 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1967 * YUI licensed under the BSD License:
1968 * http://developer.yahoo.net/yui/license.txt
1969 * <script type="text/javascript">
1973 Roo.lib.Event = function() {
1974 var loadComplete = false;
1976 var unloadListeners = [];
1978 var onAvailStack = [];
1980 var lastError = null;
1993 startInterval: function() {
1994 if (!this._interval) {
1996 var callback = function() {
1997 self._tryPreloadAttach();
1999 this._interval = setInterval(callback, this.POLL_INTERVAL);
2004 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2005 onAvailStack.push({ id: p_id,
2008 override: p_override,
2009 checkReady: false });
2011 retryCount = this.POLL_RETRYS;
2012 this.startInterval();
2016 addListener: function(el, eventName, fn) {
2017 el = Roo.getDom(el);
2022 if ("unload" == eventName) {
2023 unloadListeners[unloadListeners.length] =
2024 [el, eventName, fn];
2028 var wrappedFn = function(e) {
2029 return fn(Roo.lib.Event.getEvent(e));
2032 var li = [el, eventName, fn, wrappedFn];
2034 var index = listeners.length;
2035 listeners[index] = li;
2037 this.doAdd(el, eventName, wrappedFn, false);
2043 removeListener: function(el, eventName, fn) {
2046 el = Roo.getDom(el);
2049 return this.purgeElement(el, false, eventName);
2053 if ("unload" == eventName) {
2055 for (i = 0,len = unloadListeners.length; i < len; i++) {
2056 var li = unloadListeners[i];
2059 li[1] == eventName &&
2061 unloadListeners.splice(i, 1);
2069 var cacheItem = null;
2072 var index = arguments[3];
2074 if ("undefined" == typeof index) {
2075 index = this._getCacheIndex(el, eventName, fn);
2079 cacheItem = listeners[index];
2082 if (!el || !cacheItem) {
2086 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2088 delete listeners[index][this.WFN];
2089 delete listeners[index][this.FN];
2090 listeners.splice(index, 1);
2097 getTarget: function(ev, resolveTextNode) {
2098 ev = ev.browserEvent || ev;
2099 var t = ev.target || ev.srcElement;
2100 return this.resolveTextNode(t);
2104 resolveTextNode: function(node) {
2105 if (Roo.isSafari && node && 3 == node.nodeType) {
2106 return node.parentNode;
2113 getPageX: function(ev) {
2114 ev = ev.browserEvent || ev;
2116 if (!x && 0 !== x) {
2117 x = ev.clientX || 0;
2120 x += this.getScroll()[1];
2128 getPageY: function(ev) {
2129 ev = ev.browserEvent || ev;
2131 if (!y && 0 !== y) {
2132 y = ev.clientY || 0;
2135 y += this.getScroll()[0];
2144 getXY: function(ev) {
2145 ev = ev.browserEvent || ev;
2146 return [this.getPageX(ev), this.getPageY(ev)];
2150 getRelatedTarget: function(ev) {
2151 ev = ev.browserEvent || ev;
2152 var t = ev.relatedTarget;
2154 if (ev.type == "mouseout") {
2156 } else if (ev.type == "mouseover") {
2161 return this.resolveTextNode(t);
2165 getTime: function(ev) {
2166 ev = ev.browserEvent || ev;
2168 var t = new Date().getTime();
2172 this.lastError = ex;
2181 stopEvent: function(ev) {
2182 this.stopPropagation(ev);
2183 this.preventDefault(ev);
2187 stopPropagation: function(ev) {
2188 ev = ev.browserEvent || ev;
2189 if (ev.stopPropagation) {
2190 ev.stopPropagation();
2192 ev.cancelBubble = true;
2197 preventDefault: function(ev) {
2198 ev = ev.browserEvent || ev;
2199 if(ev.preventDefault) {
2200 ev.preventDefault();
2202 ev.returnValue = false;
2207 getEvent: function(e) {
2208 var ev = e || window.event;
2210 var c = this.getEvent.caller;
2212 ev = c.arguments[0];
2213 if (ev && Event == ev.constructor) {
2223 getCharCode: function(ev) {
2224 ev = ev.browserEvent || ev;
2225 return ev.charCode || ev.keyCode || 0;
2229 _getCacheIndex: function(el, eventName, fn) {
2230 for (var i = 0,len = listeners.length; i < len; ++i) {
2231 var li = listeners[i];
2233 li[this.FN] == fn &&
2234 li[this.EL] == el &&
2235 li[this.TYPE] == eventName) {
2247 getEl: function(id) {
2248 return document.getElementById(id);
2252 clearCache: function() {
2256 _load: function(e) {
2257 loadComplete = true;
2258 var EU = Roo.lib.Event;
2262 EU.doRemove(window, "load", EU._load);
2267 _tryPreloadAttach: function() {
2276 var tryAgain = !loadComplete;
2278 tryAgain = (retryCount > 0);
2283 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2284 var item = onAvailStack[i];
2286 var el = this.getEl(item.id);
2289 if (!item.checkReady ||
2292 (document && document.body)) {
2295 if (item.override) {
2296 if (item.override === true) {
2299 scope = item.override;
2302 item.fn.call(scope, item.obj);
2303 onAvailStack[i] = null;
2306 notAvail.push(item);
2311 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2315 this.startInterval();
2317 clearInterval(this._interval);
2318 this._interval = null;
2321 this.locked = false;
2328 purgeElement: function(el, recurse, eventName) {
2329 var elListeners = this.getListeners(el, eventName);
2331 for (var i = 0,len = elListeners.length; i < len; ++i) {
2332 var l = elListeners[i];
2333 this.removeListener(el, l.type, l.fn);
2337 if (recurse && el && el.childNodes) {
2338 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2339 this.purgeElement(el.childNodes[i], recurse, eventName);
2345 getListeners: function(el, eventName) {
2346 var results = [], searchLists;
2348 searchLists = [listeners, unloadListeners];
2349 } else if (eventName == "unload") {
2350 searchLists = [unloadListeners];
2352 searchLists = [listeners];
2355 for (var j = 0; j < searchLists.length; ++j) {
2356 var searchList = searchLists[j];
2357 if (searchList && searchList.length > 0) {
2358 for (var i = 0,len = searchList.length; i < len; ++i) {
2359 var l = searchList[i];
2360 if (l && l[this.EL] === el &&
2361 (!eventName || eventName === l[this.TYPE])) {
2366 adjust: l[this.ADJ_SCOPE],
2374 return (results.length) ? results : null;
2378 _unload: function(e) {
2380 var EU = Roo.lib.Event, i, j, l, len, index;
2382 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2383 l = unloadListeners[i];
2386 if (l[EU.ADJ_SCOPE]) {
2387 if (l[EU.ADJ_SCOPE] === true) {
2390 scope = l[EU.ADJ_SCOPE];
2393 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2394 unloadListeners[i] = null;
2400 unloadListeners = null;
2402 if (listeners && listeners.length > 0) {
2403 j = listeners.length;
2406 l = listeners[index];
2408 EU.removeListener(l[EU.EL], l[EU.TYPE],
2418 EU.doRemove(window, "unload", EU._unload);
2423 getScroll: function() {
2424 var dd = document.documentElement, db = document.body;
2425 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2426 return [dd.scrollTop, dd.scrollLeft];
2428 return [db.scrollTop, db.scrollLeft];
2435 doAdd: function () {
2436 if (window.addEventListener) {
2437 return function(el, eventName, fn, capture) {
2438 el.addEventListener(eventName, fn, (capture));
2440 } else if (window.attachEvent) {
2441 return function(el, eventName, fn, capture) {
2442 el.attachEvent("on" + eventName, fn);
2451 doRemove: function() {
2452 if (window.removeEventListener) {
2453 return function (el, eventName, fn, capture) {
2454 el.removeEventListener(eventName, fn, (capture));
2456 } else if (window.detachEvent) {
2457 return function (el, eventName, fn) {
2458 el.detachEvent("on" + eventName, fn);
2470 var E = Roo.lib.Event;
2471 E.on = E.addListener;
2472 E.un = E.removeListener;
2474 if (document && document.body) {
2477 E.doAdd(window, "load", E._load);
2479 E.doAdd(window, "unload", E._unload);
2480 E._tryPreloadAttach();
2484 * Portions of this file are based on pieces of Yahoo User Interface Library
2485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2486 * YUI licensed under the BSD License:
2487 * http://developer.yahoo.net/yui/license.txt
2488 * <script type="text/javascript">
2494 * @class Roo.lib.Ajax
2501 request : function(method, uri, cb, data, options) {
2503 var hs = options.headers;
2506 if(hs.hasOwnProperty(h)){
2507 this.initHeader(h, hs[h], false);
2511 if(options.xmlData){
2512 this.initHeader('Content-Type', 'text/xml', false);
2514 data = options.xmlData;
2518 return this.asyncRequest(method, uri, cb, data);
2521 serializeForm : function(form) {
2522 if(typeof form == 'string') {
2523 form = (document.getElementById(form) || document.forms[form]);
2526 var el, name, val, disabled, data = '', hasSubmit = false;
2527 for (var i = 0; i < form.elements.length; i++) {
2528 el = form.elements[i];
2529 disabled = form.elements[i].disabled;
2530 name = form.elements[i].name;
2531 val = form.elements[i].value;
2533 if (!disabled && name){
2537 case 'select-multiple':
2538 for (var j = 0; j < el.options.length; j++) {
2539 if (el.options[j].selected) {
2541 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2544 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2565 if(hasSubmit == false) {
2566 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2571 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2576 data = data.substr(0, data.length - 1);
2584 useDefaultHeader:true,
2586 defaultPostHeader:'application/x-www-form-urlencoded',
2588 useDefaultXhrHeader:true,
2590 defaultXhrHeader:'XMLHttpRequest',
2592 hasDefaultHeaders:true,
2604 setProgId:function(id)
2606 this.activeX.unshift(id);
2609 setDefaultPostHeader:function(b)
2611 this.useDefaultHeader = b;
2614 setDefaultXhrHeader:function(b)
2616 this.useDefaultXhrHeader = b;
2619 setPollingInterval:function(i)
2621 if (typeof i == 'number' && isFinite(i)) {
2622 this.pollInterval = i;
2626 createXhrObject:function(transactionId)
2632 http = new XMLHttpRequest();
2634 obj = { conn:http, tId:transactionId };
2638 for (var i = 0; i < this.activeX.length; ++i) {
2642 http = new ActiveXObject(this.activeX[i]);
2644 obj = { conn:http, tId:transactionId };
2657 getConnectionObject:function()
2660 var tId = this.transactionId;
2664 o = this.createXhrObject(tId);
2666 this.transactionId++;
2677 asyncRequest:function(method, uri, callback, postData)
2679 var o = this.getConnectionObject();
2685 o.conn.open(method, uri, true);
2687 if (this.useDefaultXhrHeader) {
2688 if (!this.defaultHeaders['X-Requested-With']) {
2689 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2693 if(postData && this.useDefaultHeader){
2694 this.initHeader('Content-Type', this.defaultPostHeader);
2697 if (this.hasDefaultHeaders || this.hasHeaders) {
2701 this.handleReadyState(o, callback);
2702 o.conn.send(postData || null);
2708 handleReadyState:function(o, callback)
2712 if (callback && callback.timeout) {
2713 this.timeout[o.tId] = window.setTimeout(function() {
2714 oConn.abort(o, callback, true);
2715 }, callback.timeout);
2718 this.poll[o.tId] = window.setInterval(
2720 if (o.conn && o.conn.readyState == 4) {
2721 window.clearInterval(oConn.poll[o.tId]);
2722 delete oConn.poll[o.tId];
2724 if(callback && callback.timeout) {
2725 window.clearTimeout(oConn.timeout[o.tId]);
2726 delete oConn.timeout[o.tId];
2729 oConn.handleTransactionResponse(o, callback);
2732 , this.pollInterval);
2735 handleTransactionResponse:function(o, callback, isAbort)
2739 this.releaseObject(o);
2743 var httpStatus, responseObject;
2747 if (o.conn.status !== undefined && o.conn.status != 0) {
2748 httpStatus = o.conn.status;
2760 if (httpStatus >= 200 && httpStatus < 300) {
2761 responseObject = this.createResponseObject(o, callback.argument);
2762 if (callback.success) {
2763 if (!callback.scope) {
2764 callback.success(responseObject);
2769 callback.success.apply(callback.scope, [responseObject]);
2774 switch (httpStatus) {
2782 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2783 if (callback.failure) {
2784 if (!callback.scope) {
2785 callback.failure(responseObject);
2788 callback.failure.apply(callback.scope, [responseObject]);
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.failure) {
2795 if (!callback.scope) {
2796 callback.failure(responseObject);
2799 callback.failure.apply(callback.scope, [responseObject]);
2805 this.releaseObject(o);
2806 responseObject = null;
2809 createResponseObject:function(o, callbackArg)
2816 var headerStr = o.conn.getAllResponseHeaders();
2817 var header = headerStr.split('\n');
2818 for (var i = 0; i < header.length; i++) {
2819 var delimitPos = header[i].indexOf(':');
2820 if (delimitPos != -1) {
2821 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2829 obj.status = o.conn.status;
2830 obj.statusText = o.conn.statusText;
2831 obj.getResponseHeader = headerObj;
2832 obj.getAllResponseHeaders = headerStr;
2833 obj.responseText = o.conn.responseText;
2834 obj.responseXML = o.conn.responseXML;
2836 if (typeof callbackArg !== undefined) {
2837 obj.argument = callbackArg;
2843 createExceptionObject:function(tId, callbackArg, isAbort)
2846 var COMM_ERROR = 'communication failure';
2847 var ABORT_CODE = -1;
2848 var ABORT_ERROR = 'transaction aborted';
2854 obj.status = ABORT_CODE;
2855 obj.statusText = ABORT_ERROR;
2858 obj.status = COMM_CODE;
2859 obj.statusText = COMM_ERROR;
2863 obj.argument = callbackArg;
2869 initHeader:function(label, value, isDefault)
2871 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2873 if (headerObj[label] === undefined) {
2874 headerObj[label] = value;
2879 headerObj[label] = value + "," + headerObj[label];
2883 this.hasDefaultHeaders = true;
2886 this.hasHeaders = true;
2891 setHeader:function(o)
2893 if (this.hasDefaultHeaders) {
2894 for (var prop in this.defaultHeaders) {
2895 if (this.defaultHeaders.hasOwnProperty(prop)) {
2896 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2901 if (this.hasHeaders) {
2902 for (var prop in this.headers) {
2903 if (this.headers.hasOwnProperty(prop)) {
2904 o.conn.setRequestHeader(prop, this.headers[prop]);
2908 this.hasHeaders = false;
2912 resetDefaultHeaders:function() {
2913 delete this.defaultHeaders;
2914 this.defaultHeaders = {};
2915 this.hasDefaultHeaders = false;
2918 abort:function(o, callback, isTimeout)
2920 if(this.isCallInProgress(o)) {
2922 window.clearInterval(this.poll[o.tId]);
2923 delete this.poll[o.tId];
2925 delete this.timeout[o.tId];
2928 this.handleTransactionResponse(o, callback, true);
2938 isCallInProgress:function(o)
2941 return o.conn.readyState != 4 && o.conn.readyState != 0;
2950 releaseObject:function(o)
2959 'MSXML2.XMLHTTP.3.0',
2967 * Portions of this file are based on pieces of Yahoo User Interface Library
2968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2969 * YUI licensed under the BSD License:
2970 * http://developer.yahoo.net/yui/license.txt
2971 * <script type="text/javascript">
2975 Roo.lib.Region = function(t, r, b, l) {
2985 Roo.lib.Region.prototype = {
2986 contains : function(region) {
2987 return ( region.left >= this.left &&
2988 region.right <= this.right &&
2989 region.top >= this.top &&
2990 region.bottom <= this.bottom );
2994 getArea : function() {
2995 return ( (this.bottom - this.top) * (this.right - this.left) );
2998 intersect : function(region) {
2999 var t = Math.max(this.top, region.top);
3000 var r = Math.min(this.right, region.right);
3001 var b = Math.min(this.bottom, region.bottom);
3002 var l = Math.max(this.left, region.left);
3004 if (b >= t && r >= l) {
3005 return new Roo.lib.Region(t, r, b, l);
3010 union : function(region) {
3011 var t = Math.min(this.top, region.top);
3012 var r = Math.max(this.right, region.right);
3013 var b = Math.max(this.bottom, region.bottom);
3014 var l = Math.min(this.left, region.left);
3016 return new Roo.lib.Region(t, r, b, l);
3019 adjust : function(t, l, b, r) {
3028 Roo.lib.Region.getRegion = function(el) {
3029 var p = Roo.lib.Dom.getXY(el);
3032 var r = p[0] + el.offsetWidth;
3033 var b = p[1] + el.offsetHeight;
3036 return new Roo.lib.Region(t, r, b, l);
3039 * Portions of this file are based on pieces of Yahoo User Interface Library
3040 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3041 * YUI licensed under the BSD License:
3042 * http://developer.yahoo.net/yui/license.txt
3043 * <script type="text/javascript">
3046 //@@dep Roo.lib.Region
3049 Roo.lib.Point = function(x, y) {
3050 if (x instanceof Array) {
3054 this.x = this.right = this.left = this[0] = x;
3055 this.y = this.top = this.bottom = this[1] = y;
3058 Roo.lib.Point.prototype = new Roo.lib.Region();
3060 * Portions of this file are based on pieces of Yahoo User Interface Library
3061 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3062 * YUI licensed under the BSD License:
3063 * http://developer.yahoo.net/yui/license.txt
3064 * <script type="text/javascript">
3071 scroll : function(el, args, duration, easing, cb, scope) {
3072 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3075 motion : function(el, args, duration, easing, cb, scope) {
3076 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3079 color : function(el, args, duration, easing, cb, scope) {
3080 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3083 run : function(el, args, duration, easing, cb, scope, type) {
3084 type = type || Roo.lib.AnimBase;
3085 if (typeof easing == "string") {
3086 easing = Roo.lib.Easing[easing];
3088 var anim = new type(el, args, duration, easing);
3089 anim.animateX(function() {
3090 Roo.callback(cb, scope);
3096 * Portions of this file are based on pieces of Yahoo User Interface Library
3097 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3098 * YUI licensed under the BSD License:
3099 * http://developer.yahoo.net/yui/license.txt
3100 * <script type="text/javascript">
3108 if (!libFlyweight) {
3109 libFlyweight = new Roo.Element.Flyweight();
3111 libFlyweight.dom = el;
3112 return libFlyweight;
3115 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3119 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3121 this.init(el, attributes, duration, method);
3125 Roo.lib.AnimBase.fly = fly;
3129 Roo.lib.AnimBase.prototype = {
3131 toString: function() {
3132 var el = this.getEl();
3133 var id = el.id || el.tagName;
3134 return ("Anim " + id);
3138 noNegatives: /width|height|opacity|padding/i,
3139 offsetAttribute: /^((width|height)|(top|left))$/,
3140 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3141 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3145 doMethod: function(attr, start, end) {
3146 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3150 setAttribute: function(attr, val, unit) {
3151 if (this.patterns.noNegatives.test(attr)) {
3152 val = (val > 0) ? val : 0;
3155 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3159 getAttribute: function(attr) {
3160 var el = this.getEl();
3161 var val = fly(el).getStyle(attr);
3163 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3164 return parseFloat(val);
3167 var a = this.patterns.offsetAttribute.exec(attr) || [];
3168 var pos = !!( a[3] );
3169 var box = !!( a[2] );
3172 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3173 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3182 getDefaultUnit: function(attr) {
3183 if (this.patterns.defaultUnit.test(attr)) {
3190 animateX : function(callback, scope) {
3191 var f = function() {
3192 this.onComplete.removeListener(f);
3193 if (typeof callback == "function") {
3194 callback.call(scope || this, this);
3197 this.onComplete.addListener(f, this);
3202 setRuntimeAttribute: function(attr) {
3205 var attributes = this.attributes;
3207 this.runtimeAttributes[attr] = {};
3209 var isset = function(prop) {
3210 return (typeof prop !== 'undefined');
3213 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3217 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3220 if (isset(attributes[attr]['to'])) {
3221 end = attributes[attr]['to'];
3222 } else if (isset(attributes[attr]['by'])) {
3223 if (start.constructor == Array) {
3225 for (var i = 0, len = start.length; i < len; ++i) {
3226 end[i] = start[i] + attributes[attr]['by'][i];
3229 end = start + attributes[attr]['by'];
3233 this.runtimeAttributes[attr].start = start;
3234 this.runtimeAttributes[attr].end = end;
3237 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3241 init: function(el, attributes, duration, method) {
3243 var isAnimated = false;
3246 var startTime = null;
3249 var actualFrames = 0;
3252 el = Roo.getDom(el);
3255 this.attributes = attributes || {};
3258 this.duration = duration || 1;
3261 this.method = method || Roo.lib.Easing.easeNone;
3264 this.useSeconds = true;
3267 this.currentFrame = 0;
3270 this.totalFrames = Roo.lib.AnimMgr.fps;
3273 this.getEl = function() {
3278 this.isAnimated = function() {
3283 this.getStartTime = function() {
3287 this.runtimeAttributes = {};
3290 this.animate = function() {
3291 if (this.isAnimated()) {
3295 this.currentFrame = 0;
3297 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3299 Roo.lib.AnimMgr.registerElement(this);
3303 this.stop = function(finish) {
3305 this.currentFrame = this.totalFrames;
3306 this._onTween.fire();
3308 Roo.lib.AnimMgr.stop(this);
3311 var onStart = function() {
3312 this.onStart.fire();
3314 this.runtimeAttributes = {};
3315 for (var attr in this.attributes) {
3316 this.setRuntimeAttribute(attr);
3321 startTime = new Date();
3325 var onTween = function() {
3327 duration: new Date() - this.getStartTime(),
3328 currentFrame: this.currentFrame
3331 data.toString = function() {
3333 'duration: ' + data.duration +
3334 ', currentFrame: ' + data.currentFrame
3338 this.onTween.fire(data);
3340 var runtimeAttributes = this.runtimeAttributes;
3342 for (var attr in runtimeAttributes) {
3343 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3349 var onComplete = function() {
3350 var actual_duration = (new Date() - startTime) / 1000 ;
3353 duration: actual_duration,
3354 frames: actualFrames,
3355 fps: actualFrames / actual_duration
3358 data.toString = function() {
3360 'duration: ' + data.duration +
3361 ', frames: ' + data.frames +
3362 ', fps: ' + data.fps
3368 this.onComplete.fire(data);
3372 this._onStart = new Roo.util.Event(this);
3373 this.onStart = new Roo.util.Event(this);
3374 this.onTween = new Roo.util.Event(this);
3375 this._onTween = new Roo.util.Event(this);
3376 this.onComplete = new Roo.util.Event(this);
3377 this._onComplete = new Roo.util.Event(this);
3378 this._onStart.addListener(onStart);
3379 this._onTween.addListener(onTween);
3380 this._onComplete.addListener(onComplete);
3385 * Portions of this file are based on pieces of Yahoo User Interface Library
3386 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3387 * YUI licensed under the BSD License:
3388 * http://developer.yahoo.net/yui/license.txt
3389 * <script type="text/javascript">
3393 Roo.lib.AnimMgr = new function() {
3410 this.registerElement = function(tween) {
3411 queue[queue.length] = tween;
3413 tween._onStart.fire();
3418 this.unRegister = function(tween, index) {
3419 tween._onComplete.fire();
3420 index = index || getIndex(tween);
3422 queue.splice(index, 1);
3426 if (tweenCount <= 0) {
3432 this.start = function() {
3433 if (thread === null) {
3434 thread = setInterval(this.run, this.delay);
3439 this.stop = function(tween) {
3441 clearInterval(thread);
3443 for (var i = 0, len = queue.length; i < len; ++i) {
3444 if (queue[0].isAnimated()) {
3445 this.unRegister(queue[0], 0);
3454 this.unRegister(tween);
3459 this.run = function() {
3460 for (var i = 0, len = queue.length; i < len; ++i) {
3461 var tween = queue[i];
3462 if (!tween || !tween.isAnimated()) {
3466 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3468 tween.currentFrame += 1;
3470 if (tween.useSeconds) {
3471 correctFrame(tween);
3473 tween._onTween.fire();
3476 Roo.lib.AnimMgr.stop(tween, i);
3481 var getIndex = function(anim) {
3482 for (var i = 0, len = queue.length; i < len; ++i) {
3483 if (queue[i] == anim) {
3491 var correctFrame = function(tween) {
3492 var frames = tween.totalFrames;
3493 var frame = tween.currentFrame;
3494 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3495 var elapsed = (new Date() - tween.getStartTime());
3498 if (elapsed < tween.duration * 1000) {
3499 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3501 tweak = frames - (frame + 1);
3503 if (tweak > 0 && isFinite(tweak)) {
3504 if (tween.currentFrame + tweak >= frames) {
3505 tweak = frames - (frame + 1);
3508 tween.currentFrame += tweak;
3512 * Portions of this file are based on pieces of Yahoo User Interface Library
3513 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3514 * YUI licensed under the BSD License:
3515 * http://developer.yahoo.net/yui/license.txt
3516 * <script type="text/javascript">
3519 Roo.lib.Bezier = new function() {
3521 this.getPosition = function(points, t) {
3522 var n = points.length;
3525 for (var i = 0; i < n; ++i) {
3526 tmp[i] = [points[i][0], points[i][1]];
3529 for (var j = 1; j < n; ++j) {
3530 for (i = 0; i < n - j; ++i) {
3531 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3532 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3536 return [ tmp[0][0], tmp[0][1] ];
3540 * Portions of this file are based on pieces of Yahoo User Interface Library
3541 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3542 * YUI licensed under the BSD License:
3543 * http://developer.yahoo.net/yui/license.txt
3544 * <script type="text/javascript">
3549 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3550 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3553 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3555 var fly = Roo.lib.AnimBase.fly;
3557 var superclass = Y.ColorAnim.superclass;
3558 var proto = Y.ColorAnim.prototype;
3560 proto.toString = function() {
3561 var el = this.getEl();
3562 var id = el.id || el.tagName;
3563 return ("ColorAnim " + id);
3566 proto.patterns.color = /color$/i;
3567 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3568 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3569 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3570 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3573 proto.parseColor = function(s) {
3574 if (s.length == 3) {
3578 var c = this.patterns.hex.exec(s);
3579 if (c && c.length == 4) {
3580 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3583 c = this.patterns.rgb.exec(s);
3584 if (c && c.length == 4) {
3585 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3588 c = this.patterns.hex3.exec(s);
3589 if (c && c.length == 4) {
3590 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3595 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3596 proto.getAttribute = function(attr) {
3597 var el = this.getEl();
3598 if (this.patterns.color.test(attr)) {
3599 var val = fly(el).getStyle(attr);
3601 if (this.patterns.transparent.test(val)) {
3602 var parent = el.parentNode;
3603 val = fly(parent).getStyle(attr);
3605 while (parent && this.patterns.transparent.test(val)) {
3606 parent = parent.parentNode;
3607 val = fly(parent).getStyle(attr);
3608 if (parent.tagName.toUpperCase() == 'HTML') {
3614 val = superclass.getAttribute.call(this, attr);
3619 proto.getAttribute = function(attr) {
3620 var el = this.getEl();
3621 if (this.patterns.color.test(attr)) {
3622 var val = fly(el).getStyle(attr);
3624 if (this.patterns.transparent.test(val)) {
3625 var parent = el.parentNode;
3626 val = fly(parent).getStyle(attr);
3628 while (parent && this.patterns.transparent.test(val)) {
3629 parent = parent.parentNode;
3630 val = fly(parent).getStyle(attr);
3631 if (parent.tagName.toUpperCase() == 'HTML') {
3637 val = superclass.getAttribute.call(this, attr);
3643 proto.doMethod = function(attr, start, end) {
3646 if (this.patterns.color.test(attr)) {
3648 for (var i = 0, len = start.length; i < len; ++i) {
3649 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3652 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3655 val = superclass.doMethod.call(this, attr, start, end);
3661 proto.setRuntimeAttribute = function(attr) {
3662 superclass.setRuntimeAttribute.call(this, attr);
3664 if (this.patterns.color.test(attr)) {
3665 var attributes = this.attributes;
3666 var start = this.parseColor(this.runtimeAttributes[attr].start);
3667 var end = this.parseColor(this.runtimeAttributes[attr].end);
3669 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3670 end = this.parseColor(attributes[attr].by);
3672 for (var i = 0, len = start.length; i < len; ++i) {
3673 end[i] = start[i] + end[i];
3677 this.runtimeAttributes[attr].start = start;
3678 this.runtimeAttributes[attr].end = end;
3684 * Portions of this file are based on pieces of Yahoo User Interface Library
3685 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3686 * YUI licensed under the BSD License:
3687 * http://developer.yahoo.net/yui/license.txt
3688 * <script type="text/javascript">
3694 easeNone: function (t, b, c, d) {
3695 return c * t / d + b;
3699 easeIn: function (t, b, c, d) {
3700 return c * (t /= d) * t + b;
3704 easeOut: function (t, b, c, d) {
3705 return -c * (t /= d) * (t - 2) + b;
3709 easeBoth: function (t, b, c, d) {
3710 if ((t /= d / 2) < 1) {
3711 return c / 2 * t * t + b;
3714 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3718 easeInStrong: function (t, b, c, d) {
3719 return c * (t /= d) * t * t * t + b;
3723 easeOutStrong: function (t, b, c, d) {
3724 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3728 easeBothStrong: function (t, b, c, d) {
3729 if ((t /= d / 2) < 1) {
3730 return c / 2 * t * t * t * t + b;
3733 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3738 elasticIn: function (t, b, c, d, a, p) {
3742 if ((t /= d) == 1) {
3749 if (!a || a < Math.abs(c)) {
3754 var s = p / (2 * Math.PI) * Math.asin(c / a);
3757 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3761 elasticOut: function (t, b, c, d, a, p) {
3765 if ((t /= d) == 1) {
3772 if (!a || a < Math.abs(c)) {
3777 var s = p / (2 * Math.PI) * Math.asin(c / a);
3780 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3784 elasticBoth: function (t, b, c, d, a, p) {
3789 if ((t /= d / 2) == 2) {
3797 if (!a || a < Math.abs(c)) {
3802 var s = p / (2 * Math.PI) * Math.asin(c / a);
3806 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3807 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3809 return a * Math.pow(2, -10 * (t -= 1)) *
3810 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3815 backIn: function (t, b, c, d, s) {
3816 if (typeof s == 'undefined') {
3819 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3823 backOut: function (t, b, c, d, s) {
3824 if (typeof s == 'undefined') {
3827 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3831 backBoth: function (t, b, c, d, s) {
3832 if (typeof s == 'undefined') {
3836 if ((t /= d / 2 ) < 1) {
3837 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3839 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3843 bounceIn: function (t, b, c, d) {
3844 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3848 bounceOut: function (t, b, c, d) {
3849 if ((t /= d) < (1 / 2.75)) {
3850 return c * (7.5625 * t * t) + b;
3851 } else if (t < (2 / 2.75)) {
3852 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3853 } else if (t < (2.5 / 2.75)) {
3854 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3856 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3860 bounceBoth: function (t, b, c, d) {
3862 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3864 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3867 * Portions of this file are based on pieces of Yahoo User Interface Library
3868 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3869 * YUI licensed under the BSD License:
3870 * http://developer.yahoo.net/yui/license.txt
3871 * <script type="text/javascript">
3875 Roo.lib.Motion = function(el, attributes, duration, method) {
3877 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3881 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3885 var superclass = Y.Motion.superclass;
3886 var proto = Y.Motion.prototype;
3888 proto.toString = function() {
3889 var el = this.getEl();
3890 var id = el.id || el.tagName;
3891 return ("Motion " + id);
3894 proto.patterns.points = /^points$/i;
3896 proto.setAttribute = function(attr, val, unit) {
3897 if (this.patterns.points.test(attr)) {
3898 unit = unit || 'px';
3899 superclass.setAttribute.call(this, 'left', val[0], unit);
3900 superclass.setAttribute.call(this, 'top', val[1], unit);
3902 superclass.setAttribute.call(this, attr, val, unit);
3906 proto.getAttribute = function(attr) {
3907 if (this.patterns.points.test(attr)) {
3909 superclass.getAttribute.call(this, 'left'),
3910 superclass.getAttribute.call(this, 'top')
3913 val = superclass.getAttribute.call(this, attr);
3919 proto.doMethod = function(attr, start, end) {
3922 if (this.patterns.points.test(attr)) {
3923 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3924 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3926 val = superclass.doMethod.call(this, attr, start, end);
3931 proto.setRuntimeAttribute = function(attr) {
3932 if (this.patterns.points.test(attr)) {
3933 var el = this.getEl();
3934 var attributes = this.attributes;
3936 var control = attributes['points']['control'] || [];
3940 if (control.length > 0 && !(control[0] instanceof Array)) {
3941 control = [control];
3944 for (i = 0,len = control.length; i < len; ++i) {
3945 tmp[i] = control[i];
3950 Roo.fly(el).position();
3952 if (isset(attributes['points']['from'])) {
3953 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3956 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3959 start = this.getAttribute('points');
3962 if (isset(attributes['points']['to'])) {
3963 end = translateValues.call(this, attributes['points']['to'], start);
3965 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3966 for (i = 0,len = control.length; i < len; ++i) {
3967 control[i] = translateValues.call(this, control[i], start);
3971 } else if (isset(attributes['points']['by'])) {
3972 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3974 for (i = 0,len = control.length; i < len; ++i) {
3975 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3979 this.runtimeAttributes[attr] = [start];
3981 if (control.length > 0) {
3982 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3985 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3988 superclass.setRuntimeAttribute.call(this, attr);
3992 var translateValues = function(val, start) {
3993 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3994 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3999 var isset = function(prop) {
4000 return (typeof prop !== 'undefined');
4004 * Portions of this file are based on pieces of Yahoo User Interface Library
4005 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4006 * YUI licensed under the BSD License:
4007 * http://developer.yahoo.net/yui/license.txt
4008 * <script type="text/javascript">
4012 Roo.lib.Scroll = function(el, attributes, duration, method) {
4014 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4018 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4022 var superclass = Y.Scroll.superclass;
4023 var proto = Y.Scroll.prototype;
4025 proto.toString = function() {
4026 var el = this.getEl();
4027 var id = el.id || el.tagName;
4028 return ("Scroll " + id);
4031 proto.doMethod = function(attr, start, end) {
4034 if (attr == 'scroll') {
4036 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4037 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4041 val = superclass.doMethod.call(this, attr, start, end);
4046 proto.getAttribute = function(attr) {
4048 var el = this.getEl();
4050 if (attr == 'scroll') {
4051 val = [ el.scrollLeft, el.scrollTop ];
4053 val = superclass.getAttribute.call(this, attr);
4059 proto.setAttribute = function(attr, val, unit) {
4060 var el = this.getEl();
4062 if (attr == 'scroll') {
4063 el.scrollLeft = val[0];
4064 el.scrollTop = val[1];
4066 superclass.setAttribute.call(this, attr, val, unit);
4072 * Ext JS Library 1.1.1
4073 * Copyright(c) 2006-2007, Ext JS, LLC.
4075 * Originally Released Under LGPL - original licence link has changed is not relivant.
4078 * <script type="text/javascript">
4082 // nasty IE9 hack - what a pile of crap that is..
4084 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4085 Range.prototype.createContextualFragment = function (html) {
4086 var doc = window.document;
4087 var container = doc.createElement("div");
4088 container.innerHTML = html;
4089 var frag = doc.createDocumentFragment(), n;
4090 while ((n = container.firstChild)) {
4091 frag.appendChild(n);
4098 * @class Roo.DomHelper
4099 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4100 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4103 Roo.DomHelper = function(){
4104 var tempTableEl = null;
4105 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4106 var tableRe = /^table|tbody|tr|td$/i;
4108 // build as innerHTML where available
4110 var createHtml = function(o){
4111 if(typeof o == 'string'){
4120 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4121 if(attr == "style"){
4123 if(typeof s == "function"){
4126 if(typeof s == "string"){
4127 b += ' style="' + s + '"';
4128 }else if(typeof s == "object"){
4131 if(typeof s[key] != "function"){
4132 b += key + ":" + s[key] + ";";
4139 b += ' class="' + o["cls"] + '"';
4140 }else if(attr == "htmlFor"){
4141 b += ' for="' + o["htmlFor"] + '"';
4143 b += " " + attr + '="' + o[attr] + '"';
4147 if(emptyTags.test(o.tag)){
4151 var cn = o.children || o.cn;
4153 //http://bugs.kde.org/show_bug.cgi?id=71506
4154 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4155 for(var i = 0, len = cn.length; i < len; i++) {
4156 b += createHtml(cn[i], b);
4159 b += createHtml(cn, b);
4165 b += "</" + o.tag + ">";
4172 var createDom = function(o, parentNode){
4174 // defininition craeted..
4176 if (o.ns && o.ns != 'html') {
4178 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4179 xmlns[o.ns] = o.xmlns;
4182 if (typeof(xmlns[o.ns]) == 'undefined') {
4183 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4189 if (typeof(o) == 'string') {
4190 return parentNode.appendChild(document.createTextNode(o));
4192 o.tag = o.tag || div;
4193 if (o.ns && Roo.isIE) {
4195 o.tag = o.ns + ':' + o.tag;
4198 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4199 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4202 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4203 attr == "style" || typeof o[attr] == "function") continue;
4205 if(attr=="cls" && Roo.isIE){
4206 el.className = o["cls"];
4208 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4209 else el[attr] = o[attr];
4212 Roo.DomHelper.applyStyles(el, o.style);
4213 var cn = o.children || o.cn;
4215 //http://bugs.kde.org/show_bug.cgi?id=71506
4216 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4217 for(var i = 0, len = cn.length; i < len; i++) {
4218 createDom(cn[i], el);
4225 el.innerHTML = o.html;
4228 parentNode.appendChild(el);
4233 var ieTable = function(depth, s, h, e){
4234 tempTableEl.innerHTML = [s, h, e].join('');
4235 var i = -1, el = tempTableEl;
4242 // kill repeat to save bytes
4246 tbe = '</tbody>'+te,
4252 * Nasty code for IE's broken table implementation
4254 var insertIntoTable = function(tag, where, el, html){
4256 tempTableEl = document.createElement('div');
4261 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4264 if(where == 'beforebegin'){
4268 before = el.nextSibling;
4271 node = ieTable(4, trs, html, tre);
4273 else if(tag == 'tr'){
4274 if(where == 'beforebegin'){
4277 node = ieTable(3, tbs, html, tbe);
4278 } else if(where == 'afterend'){
4279 before = el.nextSibling;
4281 node = ieTable(3, tbs, html, tbe);
4282 } else{ // INTO a TR
4283 if(where == 'afterbegin'){
4284 before = el.firstChild;
4286 node = ieTable(4, trs, html, tre);
4288 } else if(tag == 'tbody'){
4289 if(where == 'beforebegin'){
4292 node = ieTable(2, ts, html, te);
4293 } else if(where == 'afterend'){
4294 before = el.nextSibling;
4296 node = ieTable(2, ts, html, te);
4298 if(where == 'afterbegin'){
4299 before = el.firstChild;
4301 node = ieTable(3, tbs, html, tbe);
4304 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4307 if(where == 'afterbegin'){
4308 before = el.firstChild;
4310 node = ieTable(2, ts, html, te);
4312 el.insertBefore(node, before);
4317 /** True to force the use of DOM instead of html fragments @type Boolean */
4321 * Returns the markup for the passed Element(s) config
4322 * @param {Object} o The Dom object spec (and children)
4325 markup : function(o){
4326 return createHtml(o);
4330 * Applies a style specification to an element
4331 * @param {String/HTMLElement} el The element to apply styles to
4332 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4333 * a function which returns such a specification.
4335 applyStyles : function(el, styles){
4338 if(typeof styles == "string"){
4339 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4341 while ((matches = re.exec(styles)) != null){
4342 el.setStyle(matches[1], matches[2]);
4344 }else if (typeof styles == "object"){
4345 for (var style in styles){
4346 el.setStyle(style, styles[style]);
4348 }else if (typeof styles == "function"){
4349 Roo.DomHelper.applyStyles(el, styles.call());
4355 * Inserts an HTML fragment into the Dom
4356 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4357 * @param {HTMLElement} el The context element
4358 * @param {String} html The HTML fragmenet
4359 * @return {HTMLElement} The new node
4361 insertHtml : function(where, el, html){
4362 where = where.toLowerCase();
4363 if(el.insertAdjacentHTML){
4364 if(tableRe.test(el.tagName)){
4366 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4372 el.insertAdjacentHTML('BeforeBegin', html);
4373 return el.previousSibling;
4375 el.insertAdjacentHTML('AfterBegin', html);
4376 return el.firstChild;
4378 el.insertAdjacentHTML('BeforeEnd', html);
4379 return el.lastChild;
4381 el.insertAdjacentHTML('AfterEnd', html);
4382 return el.nextSibling;
4384 throw 'Illegal insertion point -> "' + where + '"';
4386 var range = el.ownerDocument.createRange();
4390 range.setStartBefore(el);
4391 frag = range.createContextualFragment(html);
4392 el.parentNode.insertBefore(frag, el);
4393 return el.previousSibling;
4396 range.setStartBefore(el.firstChild);
4397 frag = range.createContextualFragment(html);
4398 el.insertBefore(frag, el.firstChild);
4399 return el.firstChild;
4401 el.innerHTML = html;
4402 return el.firstChild;
4406 range.setStartAfter(el.lastChild);
4407 frag = range.createContextualFragment(html);
4408 el.appendChild(frag);
4409 return el.lastChild;
4411 el.innerHTML = html;
4412 return el.lastChild;
4415 range.setStartAfter(el);
4416 frag = range.createContextualFragment(html);
4417 el.parentNode.insertBefore(frag, el.nextSibling);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4424 * Creates new Dom element(s) and inserts them before el
4425 * @param {String/HTMLElement/Element} el The context element
4426 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4427 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4428 * @return {HTMLElement/Roo.Element} The new node
4430 insertBefore : function(el, o, returnElement){
4431 return this.doInsert(el, o, returnElement, "beforeBegin");
4435 * Creates new Dom element(s) and inserts them after el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object} o The Dom object spec (and children)
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertAfter : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4446 * Creates new Dom element(s) and inserts them as the first child of el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertFirst : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterBegin");
4457 doInsert : function(el, o, returnElement, pos, sibling){
4458 el = Roo.getDom(el);
4460 if(this.useDom || o.ns){
4461 newNode = createDom(o, null);
4462 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4464 var html = createHtml(o);
4465 newNode = this.insertHtml(pos, el, html);
4467 return returnElement ? Roo.get(newNode, true) : newNode;
4471 * Creates new Dom element(s) and appends them to el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 append : function(el, o, returnElement){
4478 el = Roo.getDom(el);
4480 if(this.useDom || o.ns){
4481 newNode = createDom(o, null);
4482 el.appendChild(newNode);
4484 var html = createHtml(o);
4485 newNode = this.insertHtml("beforeEnd", el, html);
4487 return returnElement ? Roo.get(newNode, true) : newNode;
4491 * Creates new Dom element(s) and overwrites the contents of el with them
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 overwrite : function(el, o, returnElement){
4498 el = Roo.getDom(el);
4501 while (el.childNodes.length) {
4502 el.removeChild(el.firstChild);
4506 el.innerHTML = createHtml(o);
4509 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4513 * Creates a new Roo.DomHelper.Template from the Dom object spec
4514 * @param {Object} o The Dom object spec (and children)
4515 * @return {Roo.DomHelper.Template} The new template
4517 createTemplate : function(o){
4518 var html = createHtml(o);
4519 return new Roo.Template(html);
4525 * Ext JS Library 1.1.1
4526 * Copyright(c) 2006-2007, Ext JS, LLC.
4528 * Originally Released Under LGPL - original licence link has changed is not relivant.
4531 * <script type="text/javascript">
4535 * @class Roo.Template
4536 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4537 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4540 var t = new Roo.Template({
4541 html : '<div name="{id}">' +
4542 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4544 myformat: function (value, allValues) {
4545 return 'XX' + value;
4548 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4550 * For more information see this blog post with examples:
4551 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4552 - Create Elements using DOM, HTML fragments and Templates</a>.
4554 * @param {Object} cfg - Configuration object.
4556 Roo.Template = function(cfg){
4558 if(cfg instanceof Array){
4560 }else if(arguments.length > 1){
4561 cfg = Array.prototype.join.call(arguments, "");
4565 if (typeof(cfg) == 'object') {
4576 Roo.Template.prototype = {
4579 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4580 * it should be fixed so that template is observable...
4584 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4588 * Returns an HTML fragment of this template with the specified values applied.
4589 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4590 * @return {String} The HTML fragment
4592 applyTemplate : function(values){
4596 return this.compiled(values);
4598 var useF = this.disableFormats !== true;
4599 var fm = Roo.util.Format, tpl = this;
4600 var fn = function(m, name, format, args){
4602 if(format.substr(0, 5) == "this."){
4603 return tpl.call(format.substr(5), values[name], values);
4606 // quoted values are required for strings in compiled templates,
4607 // but for non compiled we need to strip them
4608 // quoted reversed for jsmin
4609 var re = /^\s*['"](.*)["']\s*$/;
4610 args = args.split(',');
4611 for(var i = 0, len = args.length; i < len; i++){
4612 args[i] = args[i].replace(re, "$1");
4614 args = [values[name]].concat(args);
4616 args = [values[name]];
4618 return fm[format].apply(fm, args);
4621 return values[name] !== undefined ? values[name] : "";
4624 return this.html.replace(this.re, fn);
4642 this.loading = true;
4643 this.compiled = false;
4645 var cx = new Roo.data.Connection();
4649 success : function (response) {
4651 _t.html = response.responseText;
4655 failure : function(response) {
4656 Roo.log("Template failed to load from " + url);
4663 * Sets the HTML used as the template and optionally compiles it.
4664 * @param {String} html
4665 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4666 * @return {Roo.Template} this
4668 set : function(html, compile){
4670 this.compiled = null;
4678 * True to disable format functions (defaults to false)
4681 disableFormats : false,
4684 * The regular expression used to match template variables
4688 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4691 * Compiles the template into an internal function, eliminating the RegEx overhead.
4692 * @return {Roo.Template} this
4694 compile : function(){
4695 var fm = Roo.util.Format;
4696 var useF = this.disableFormats !== true;
4697 var sep = Roo.isGecko ? "+" : ",";
4698 var fn = function(m, name, format, args){
4700 args = args ? ',' + args : "";
4701 if(format.substr(0, 5) != "this."){
4702 format = "fm." + format + '(';
4704 format = 'this.call("'+ format.substr(5) + '", ';
4708 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4710 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4713 // branched to use + in gecko and [].join() in others
4715 body = "this.compiled = function(values){ return '" +
4716 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4719 body = ["this.compiled = function(values){ return ['"];
4720 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4721 body.push("'].join('');};");
4722 body = body.join('');
4732 // private function used to call members
4733 call : function(fnName, value, allValues){
4734 return this[fnName](value, allValues);
4738 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4739 * @param {String/HTMLElement/Roo.Element} el The context element
4740 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4741 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4742 * @return {HTMLElement/Roo.Element} The new node or Element
4744 insertFirst: function(el, values, returnElement){
4745 return this.doInsert('afterBegin', el, values, returnElement);
4749 * Applies the supplied values to the template and inserts the new node(s) before el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertBefore: function(el, values, returnElement){
4756 return this.doInsert('beforeBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) after el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertAfter : function(el, values, returnElement){
4767 return this.doInsert('afterEnd', el, values, returnElement);
4771 * Applies the supplied values to the template and appends the new node(s) to el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 append : function(el, values, returnElement){
4778 return this.doInsert('beforeEnd', el, values, returnElement);
4781 doInsert : function(where, el, values, returnEl){
4782 el = Roo.getDom(el);
4783 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4784 return returnEl ? Roo.get(newNode, true) : newNode;
4788 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4789 * @param {String/HTMLElement/Roo.Element} el The context element
4790 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4791 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4792 * @return {HTMLElement/Roo.Element} The new node or Element
4794 overwrite : function(el, values, returnElement){
4795 el = Roo.getDom(el);
4796 el.innerHTML = this.applyTemplate(values);
4797 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4801 * Alias for {@link #applyTemplate}
4804 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4807 Roo.DomHelper.Template = Roo.Template;
4810 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4811 * @param {String/HTMLElement} el A DOM element or its id
4812 * @returns {Roo.Template} The created template
4815 Roo.Template.from = function(el){
4816 el = Roo.getDom(el);
4817 return new Roo.Template(el.value || el.innerHTML);
4820 * Ext JS Library 1.1.1
4821 * Copyright(c) 2006-2007, Ext JS, LLC.
4823 * Originally Released Under LGPL - original licence link has changed is not relivant.
4826 * <script type="text/javascript">
4831 * This is code is also distributed under MIT license for use
4832 * with jQuery and prototype JavaScript libraries.
4835 * @class Roo.DomQuery
4836 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4838 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4841 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4843 <h4>Element Selectors:</h4>
4845 <li> <b>*</b> any element</li>
4846 <li> <b>E</b> an element with the tag E</li>
4847 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4848 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4849 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4850 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4852 <h4>Attribute Selectors:</h4>
4853 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4855 <li> <b>E[foo]</b> has an attribute "foo"</li>
4856 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4857 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4858 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4859 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4860 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4861 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4863 <h4>Pseudo Classes:</h4>
4865 <li> <b>E:first-child</b> E is the first child of its parent</li>
4866 <li> <b>E:last-child</b> E is the last child of its parent</li>
4867 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4868 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4869 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4870 <li> <b>E:only-child</b> E is the only child of its parent</li>
4871 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4872 <li> <b>E:first</b> the first E in the resultset</li>
4873 <li> <b>E:last</b> the last E in the resultset</li>
4874 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4875 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4876 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4877 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4878 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4879 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4880 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4881 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4882 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4884 <h4>CSS Value Selectors:</h4>
4886 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4887 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4888 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4889 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4890 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4891 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4895 Roo.DomQuery = function(){
4896 var cache = {}, simpleCache = {}, valueCache = {};
4897 var nonSpace = /\S/;
4898 var trimRe = /^\s+|\s+$/g;
4899 var tplRe = /\{(\d+)\}/g;
4900 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4901 var tagTokenRe = /^(#)?([\w-\*]+)/;
4902 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4904 function child(p, index){
4906 var n = p.firstChild;
4908 if(n.nodeType == 1){
4919 while((n = n.nextSibling) && n.nodeType != 1);
4924 while((n = n.previousSibling) && n.nodeType != 1);
4928 function children(d){
4929 var n = d.firstChild, ni = -1;
4931 var nx = n.nextSibling;
4932 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4942 function byClassName(c, a, v){
4946 var r = [], ri = -1, cn;
4947 for(var i = 0, ci; ci = c[i]; i++){
4948 if((' '+ci.className+' ').indexOf(v) != -1){
4955 function attrValue(n, attr){
4956 if(!n.tagName && typeof n.length != "undefined"){
4965 if(attr == "class" || attr == "className"){
4968 return n.getAttribute(attr) || n[attr];
4972 function getNodes(ns, mode, tagName){
4973 var result = [], ri = -1, cs;
4977 tagName = tagName || "*";
4978 if(typeof ns.getElementsByTagName != "undefined"){
4982 for(var i = 0, ni; ni = ns[i]; i++){
4983 cs = ni.getElementsByTagName(tagName);
4984 for(var j = 0, ci; ci = cs[j]; j++){
4988 }else if(mode == "/" || mode == ">"){
4989 var utag = tagName.toUpperCase();
4990 for(var i = 0, ni, cn; ni = ns[i]; i++){
4991 cn = ni.children || ni.childNodes;
4992 for(var j = 0, cj; cj = cn[j]; j++){
4993 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4998 }else if(mode == "+"){
4999 var utag = tagName.toUpperCase();
5000 for(var i = 0, n; n = ns[i]; i++){
5001 while((n = n.nextSibling) && n.nodeType != 1);
5002 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5006 }else if(mode == "~"){
5007 for(var i = 0, n; n = ns[i]; i++){
5008 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5017 function concat(a, b){
5021 for(var i = 0, l = b.length; i < l; i++){
5027 function byTag(cs, tagName){
5028 if(cs.tagName || cs == document){
5034 var r = [], ri = -1;
5035 tagName = tagName.toLowerCase();
5036 for(var i = 0, ci; ci = cs[i]; i++){
5037 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5044 function byId(cs, attr, id){
5045 if(cs.tagName || cs == document){
5051 var r = [], ri = -1;
5052 for(var i = 0,ci; ci = cs[i]; i++){
5053 if(ci && ci.id == id){
5061 function byAttribute(cs, attr, value, op, custom){
5062 var r = [], ri = -1, st = custom=="{";
5063 var f = Roo.DomQuery.operators[op];
5064 for(var i = 0, ci; ci = cs[i]; i++){
5067 a = Roo.DomQuery.getStyle(ci, attr);
5069 else if(attr == "class" || attr == "className"){
5071 }else if(attr == "for"){
5073 }else if(attr == "href"){
5074 a = ci.getAttribute("href", 2);
5076 a = ci.getAttribute(attr);
5078 if((f && f(a, value)) || (!f && a)){
5085 function byPseudo(cs, name, value){
5086 return Roo.DomQuery.pseudos[name](cs, value);
5089 // This is for IE MSXML which does not support expandos.
5090 // IE runs the same speed using setAttribute, however FF slows way down
5091 // and Safari completely fails so they need to continue to use expandos.
5092 var isIE = window.ActiveXObject ? true : false;
5094 // this eval is stop the compressor from
5095 // renaming the variable to something shorter
5097 /** eval:var:batch */
5102 function nodupIEXml(cs){
5104 cs[0].setAttribute("_nodup", d);
5106 for(var i = 1, len = cs.length; i < len; i++){
5108 if(!c.getAttribute("_nodup") != d){
5109 c.setAttribute("_nodup", d);
5113 for(var i = 0, len = cs.length; i < len; i++){
5114 cs[i].removeAttribute("_nodup");
5123 var len = cs.length, c, i, r = cs, cj, ri = -1;
5124 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5127 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5128 return nodupIEXml(cs);
5132 for(i = 1; c = cs[i]; i++){
5137 for(var j = 0; j < i; j++){
5140 for(j = i+1; cj = cs[j]; j++){
5152 function quickDiffIEXml(c1, c2){
5154 for(var i = 0, len = c1.length; i < len; i++){
5155 c1[i].setAttribute("_qdiff", d);
5158 for(var i = 0, len = c2.length; i < len; i++){
5159 if(c2[i].getAttribute("_qdiff") != d){
5160 r[r.length] = c2[i];
5163 for(var i = 0, len = c1.length; i < len; i++){
5164 c1[i].removeAttribute("_qdiff");
5169 function quickDiff(c1, c2){
5170 var len1 = c1.length;
5174 if(isIE && c1[0].selectSingleNode){
5175 return quickDiffIEXml(c1, c2);
5178 for(var i = 0; i < len1; i++){
5182 for(var i = 0, len = c2.length; i < len; i++){
5183 if(c2[i]._qdiff != d){
5184 r[r.length] = c2[i];
5190 function quickId(ns, mode, root, id){
5192 var d = root.ownerDocument || root;
5193 return d.getElementById(id);
5195 ns = getNodes(ns, mode, "*");
5196 return byId(ns, null, id);
5200 getStyle : function(el, name){
5201 return Roo.fly(el).getStyle(name);
5204 * Compiles a selector/xpath query into a reusable function. The returned function
5205 * takes one parameter "root" (optional), which is the context node from where the query should start.
5206 * @param {String} selector The selector/xpath query
5207 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5208 * @return {Function}
5210 compile : function(path, type){
5211 type = type || "select";
5213 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5214 var q = path, mode, lq;
5215 var tk = Roo.DomQuery.matchers;
5216 var tklen = tk.length;
5219 // accept leading mode switch
5220 var lmode = q.match(modeRe);
5221 if(lmode && lmode[1]){
5222 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5223 q = q.replace(lmode[1], "");
5225 // strip leading slashes
5226 while(path.substr(0, 1)=="/"){
5227 path = path.substr(1);
5230 while(q && lq != q){
5232 var tm = q.match(tagTokenRe);
5233 if(type == "select"){
5236 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5238 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5240 q = q.replace(tm[0], "");
5241 }else if(q.substr(0, 1) != '@'){
5242 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5247 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5254 while(!(mm = q.match(modeRe))){
5255 var matched = false;
5256 for(var j = 0; j < tklen; j++){
5258 var m = q.match(t.re);
5260 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5263 q = q.replace(m[0], "");
5268 // prevent infinite loop on bad selector
5270 throw 'Error parsing selector, parsing failed at "' + q + '"';
5274 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5275 q = q.replace(mm[1], "");
5278 fn[fn.length] = "return nodup(n);\n}";
5281 * list of variables that need from compression as they are used by eval.
5291 * eval:var:byClassName
5293 * eval:var:byAttribute
5294 * eval:var:attrValue
5302 * Selects a group of elements.
5303 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5304 * @param {Node} root (optional) The start of the query (defaults to document).
5307 select : function(path, root, type){
5308 if(!root || root == document){
5311 if(typeof root == "string"){
5312 root = document.getElementById(root);
5314 var paths = path.split(",");
5316 for(var i = 0, len = paths.length; i < len; i++){
5317 var p = paths[i].replace(trimRe, "");
5319 cache[p] = Roo.DomQuery.compile(p);
5321 throw p + " is not a valid selector";
5324 var result = cache[p](root);
5325 if(result && result != document){
5326 results = results.concat(result);
5329 if(paths.length > 1){
5330 return nodup(results);
5336 * Selects a single element.
5337 * @param {String} selector The selector/xpath query
5338 * @param {Node} root (optional) The start of the query (defaults to document).
5341 selectNode : function(path, root){
5342 return Roo.DomQuery.select(path, root)[0];
5346 * Selects the value of a node, optionally replacing null with the defaultValue.
5347 * @param {String} selector The selector/xpath query
5348 * @param {Node} root (optional) The start of the query (defaults to document).
5349 * @param {String} defaultValue
5351 selectValue : function(path, root, defaultValue){
5352 path = path.replace(trimRe, "");
5353 if(!valueCache[path]){
5354 valueCache[path] = Roo.DomQuery.compile(path, "select");
5356 var n = valueCache[path](root);
5357 n = n[0] ? n[0] : n;
5358 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5359 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5363 * Selects the value of a node, parsing integers and floats.
5364 * @param {String} selector The selector/xpath query
5365 * @param {Node} root (optional) The start of the query (defaults to document).
5366 * @param {Number} defaultValue
5369 selectNumber : function(path, root, defaultValue){
5370 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5371 return parseFloat(v);
5375 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5376 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5377 * @param {String} selector The simple selector to test
5380 is : function(el, ss){
5381 if(typeof el == "string"){
5382 el = document.getElementById(el);
5384 var isArray = (el instanceof Array);
5385 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5386 return isArray ? (result.length == el.length) : (result.length > 0);
5390 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5391 * @param {Array} el An array of elements to filter
5392 * @param {String} selector The simple selector to test
5393 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5394 * the selector instead of the ones that match
5397 filter : function(els, ss, nonMatches){
5398 ss = ss.replace(trimRe, "");
5399 if(!simpleCache[ss]){
5400 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5402 var result = simpleCache[ss](els);
5403 return nonMatches ? quickDiff(result, els) : result;
5407 * Collection of matching regular expressions and code snippets.
5411 select: 'n = byClassName(n, null, " {1} ");'
5413 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5414 select: 'n = byPseudo(n, "{1}", "{2}");'
5416 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5417 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5420 select: 'n = byId(n, null, "{1}");'
5423 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5428 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5429 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5432 "=" : function(a, v){
5435 "!=" : function(a, v){
5438 "^=" : function(a, v){
5439 return a && a.substr(0, v.length) == v;
5441 "$=" : function(a, v){
5442 return a && a.substr(a.length-v.length) == v;
5444 "*=" : function(a, v){
5445 return a && a.indexOf(v) !== -1;
5447 "%=" : function(a, v){
5448 return (a % v) == 0;
5450 "|=" : function(a, v){
5451 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5453 "~=" : function(a, v){
5454 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5459 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5460 * and the argument (if any) supplied in the selector.
5463 "first-child" : function(c){
5464 var r = [], ri = -1, n;
5465 for(var i = 0, ci; ci = n = c[i]; i++){
5466 while((n = n.previousSibling) && n.nodeType != 1);
5474 "last-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.nextSibling) && n.nodeType != 1);
5485 "nth-child" : function(c, a) {
5486 var r = [], ri = -1;
5487 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5488 var f = (m[1] || 1) - 0, l = m[2] - 0;
5489 for(var i = 0, n; n = c[i]; i++){
5490 var pn = n.parentNode;
5491 if (batch != pn._batch) {
5493 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5494 if(cn.nodeType == 1){
5501 if (l == 0 || n.nodeIndex == l){
5504 } else if ((n.nodeIndex + l) % f == 0){
5512 "only-child" : function(c){
5513 var r = [], ri = -1;;
5514 for(var i = 0, ci; ci = c[i]; i++){
5515 if(!prev(ci) && !next(ci)){
5522 "empty" : function(c){
5523 var r = [], ri = -1;
5524 for(var i = 0, ci; ci = c[i]; i++){
5525 var cns = ci.childNodes, j = 0, cn, empty = true;
5528 if(cn.nodeType == 1 || cn.nodeType == 3){
5540 "contains" : function(c, v){
5541 var r = [], ri = -1;
5542 for(var i = 0, ci; ci = c[i]; i++){
5543 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5550 "nodeValue" : function(c, v){
5551 var r = [], ri = -1;
5552 for(var i = 0, ci; ci = c[i]; i++){
5553 if(ci.firstChild && ci.firstChild.nodeValue == v){
5560 "checked" : function(c){
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5563 if(ci.checked == true){
5570 "not" : function(c, ss){
5571 return Roo.DomQuery.filter(c, ss, true);
5574 "odd" : function(c){
5575 return this["nth-child"](c, "odd");
5578 "even" : function(c){
5579 return this["nth-child"](c, "even");
5582 "nth" : function(c, a){
5583 return c[a-1] || [];
5586 "first" : function(c){
5590 "last" : function(c){
5591 return c[c.length-1] || [];
5594 "has" : function(c, ss){
5595 var s = Roo.DomQuery.select;
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(s(ss, ci).length > 0){
5605 "next" : function(c, ss){
5606 var is = Roo.DomQuery.is;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5617 "prev" : function(c, ss){
5618 var is = Roo.DomQuery.is;
5619 var r = [], ri = -1;
5620 for(var i = 0, ci; ci = c[i]; i++){
5633 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5634 * @param {String} path The selector/xpath query
5635 * @param {Node} root (optional) The start of the query (defaults to document).
5640 Roo.query = Roo.DomQuery.select;
5643 * Ext JS Library 1.1.1
5644 * Copyright(c) 2006-2007, Ext JS, LLC.
5646 * Originally Released Under LGPL - original licence link has changed is not relivant.
5649 * <script type="text/javascript">
5653 * @class Roo.util.Observable
5654 * Base class that provides a common interface for publishing events. Subclasses are expected to
5655 * to have a property "events" with all the events defined.<br>
5658 Employee = function(name){
5665 Roo.extend(Employee, Roo.util.Observable);
5667 * @param {Object} config properties to use (incuding events / listeners)
5670 Roo.util.Observable = function(cfg){
5673 this.addEvents(cfg.events || {});
5675 delete cfg.events; // make sure
5678 Roo.apply(this, cfg);
5681 this.on(this.listeners);
5682 delete this.listeners;
5685 Roo.util.Observable.prototype = {
5687 * @cfg {Object} listeners list of events and functions to call for this object,
5691 'click' : function(e) {
5701 * Fires the specified event with the passed parameters (minus the event name).
5702 * @param {String} eventName
5703 * @param {Object...} args Variable number of parameters are passed to handlers
5704 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5706 fireEvent : function(){
5707 var ce = this.events[arguments[0].toLowerCase()];
5708 if(typeof ce == "object"){
5709 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5716 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5719 * Appends an event handler to this component
5720 * @param {String} eventName The type of event to listen for
5721 * @param {Function} handler The method the event invokes
5722 * @param {Object} scope (optional) The scope in which to execute the handler
5723 * function. The handler function's "this" context.
5724 * @param {Object} options (optional) An object containing handler configuration
5725 * properties. This may contain any of the following properties:<ul>
5726 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5727 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5728 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5729 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5730 * by the specified number of milliseconds. If the event fires again within that time, the original
5731 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5734 * <b>Combining Options</b><br>
5735 * Using the options argument, it is possible to combine different types of listeners:<br>
5737 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5739 el.on('click', this.onClick, this, {
5746 * <b>Attaching multiple handlers in 1 call</b><br>
5747 * The method also allows for a single argument to be passed which is a config object containing properties
5748 * which specify multiple handlers.
5757 fn: this.onMouseOver,
5761 fn: this.onMouseOut,
5767 * Or a shorthand syntax which passes the same scope object to all handlers:
5770 'click': this.onClick,
5771 'mouseover': this.onMouseOver,
5772 'mouseout': this.onMouseOut,
5777 addListener : function(eventName, fn, scope, o){
5778 if(typeof eventName == "object"){
5781 if(this.filterOptRe.test(e)){
5784 if(typeof o[e] == "function"){
5786 this.addListener(e, o[e], o.scope, o);
5788 // individual options
5789 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5794 o = (!o || typeof o == "boolean") ? {} : o;
5795 eventName = eventName.toLowerCase();
5796 var ce = this.events[eventName] || true;
5797 if(typeof ce == "boolean"){
5798 ce = new Roo.util.Event(this, eventName);
5799 this.events[eventName] = ce;
5801 ce.addListener(fn, scope, o);
5805 * Removes a listener
5806 * @param {String} eventName The type of event to listen for
5807 * @param {Function} handler The handler to remove
5808 * @param {Object} scope (optional) The scope (this object) for the handler
5810 removeListener : function(eventName, fn, scope){
5811 var ce = this.events[eventName.toLowerCase()];
5812 if(typeof ce == "object"){
5813 ce.removeListener(fn, scope);
5818 * Removes all listeners for this object
5820 purgeListeners : function(){
5821 for(var evt in this.events){
5822 if(typeof this.events[evt] == "object"){
5823 this.events[evt].clearListeners();
5828 relayEvents : function(o, events){
5829 var createHandler = function(ename){
5831 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5834 for(var i = 0, len = events.length; i < len; i++){
5835 var ename = events[i];
5836 if(!this.events[ename]){ this.events[ename] = true; };
5837 o.on(ename, createHandler(ename), this);
5842 * Used to define events on this Observable
5843 * @param {Object} object The object with the events defined
5845 addEvents : function(o){
5849 Roo.applyIf(this.events, o);
5853 * Checks to see if this object has any listeners for a specified event
5854 * @param {String} eventName The name of the event to check for
5855 * @return {Boolean} True if the event is being listened for, else false
5857 hasListener : function(eventName){
5858 var e = this.events[eventName];
5859 return typeof e == "object" && e.listeners.length > 0;
5863 * Appends an event handler to this element (shorthand for addListener)
5864 * @param {String} eventName The type of event to listen for
5865 * @param {Function} handler The method the event invokes
5866 * @param {Object} scope (optional) The scope in which to execute the handler
5867 * function. The handler function's "this" context.
5868 * @param {Object} options (optional)
5871 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5873 * Removes a listener (shorthand for removeListener)
5874 * @param {String} eventName The type of event to listen for
5875 * @param {Function} handler The handler to remove
5876 * @param {Object} scope (optional) The scope (this object) for the handler
5879 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5882 * Starts capture on the specified Observable. All events will be passed
5883 * to the supplied function with the event name + standard signature of the event
5884 * <b>before</b> the event is fired. If the supplied function returns false,
5885 * the event will not fire.
5886 * @param {Observable} o The Observable to capture
5887 * @param {Function} fn The function to call
5888 * @param {Object} scope (optional) The scope (this object) for the fn
5891 Roo.util.Observable.capture = function(o, fn, scope){
5892 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5896 * Removes <b>all</b> added captures from the Observable.
5897 * @param {Observable} o The Observable to release
5900 Roo.util.Observable.releaseCapture = function(o){
5901 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5906 var createBuffered = function(h, o, scope){
5907 var task = new Roo.util.DelayedTask();
5909 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5913 var createSingle = function(h, e, fn, scope){
5915 e.removeListener(fn, scope);
5916 return h.apply(scope, arguments);
5920 var createDelayed = function(h, o, scope){
5922 var args = Array.prototype.slice.call(arguments, 0);
5923 setTimeout(function(){
5924 h.apply(scope, args);
5929 Roo.util.Event = function(obj, name){
5932 this.listeners = [];
5935 Roo.util.Event.prototype = {
5936 addListener : function(fn, scope, options){
5937 var o = options || {};
5938 scope = scope || this.obj;
5939 if(!this.isListening(fn, scope)){
5940 var l = {fn: fn, scope: scope, options: o};
5943 h = createDelayed(h, o, scope);
5946 h = createSingle(h, this, fn, scope);
5949 h = createBuffered(h, o, scope);
5952 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5953 this.listeners.push(l);
5955 this.listeners = this.listeners.slice(0);
5956 this.listeners.push(l);
5961 findListener : function(fn, scope){
5962 scope = scope || this.obj;
5963 var ls = this.listeners;
5964 for(var i = 0, len = ls.length; i < len; i++){
5966 if(l.fn == fn && l.scope == scope){
5973 isListening : function(fn, scope){
5974 return this.findListener(fn, scope) != -1;
5977 removeListener : function(fn, scope){
5979 if((index = this.findListener(fn, scope)) != -1){
5981 this.listeners.splice(index, 1);
5983 this.listeners = this.listeners.slice(0);
5984 this.listeners.splice(index, 1);
5991 clearListeners : function(){
5992 this.listeners = [];
5996 var ls = this.listeners, scope, len = ls.length;
5999 var args = Array.prototype.slice.call(arguments, 0);
6000 for(var i = 0; i < len; i++){
6002 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6003 this.firing = false;
6007 this.firing = false;
6014 * Ext JS Library 1.1.1
6015 * Copyright(c) 2006-2007, Ext JS, LLC.
6017 * Originally Released Under LGPL - original licence link has changed is not relivant.
6020 * <script type="text/javascript">
6024 * @class Roo.EventManager
6025 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6026 * several useful events directly.
6027 * See {@link Roo.EventObject} for more details on normalized event objects.
6030 Roo.EventManager = function(){
6031 var docReadyEvent, docReadyProcId, docReadyState = false;
6032 var resizeEvent, resizeTask, textEvent, textSize;
6033 var E = Roo.lib.Event;
6034 var D = Roo.lib.Dom;
6037 var fireDocReady = function(){
6039 docReadyState = true;
6042 clearInterval(docReadyProcId);
6044 if(Roo.isGecko || Roo.isOpera) {
6045 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6048 var defer = document.getElementById("ie-deferred-loader");
6050 defer.onreadystatechange = null;
6051 defer.parentNode.removeChild(defer);
6055 docReadyEvent.fire();
6056 docReadyEvent.clearListeners();
6061 var initDocReady = function(){
6062 docReadyEvent = new Roo.util.Event();
6063 if(Roo.isGecko || Roo.isOpera) {
6064 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6066 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6067 var defer = document.getElementById("ie-deferred-loader");
6068 defer.onreadystatechange = function(){
6069 if(this.readyState == "complete"){
6073 }else if(Roo.isSafari){
6074 docReadyProcId = setInterval(function(){
6075 var rs = document.readyState;
6076 if(rs == "complete") {
6081 // no matter what, make sure it fires on load
6082 E.on(window, "load", fireDocReady);
6085 var createBuffered = function(h, o){
6086 var task = new Roo.util.DelayedTask(h);
6088 // create new event object impl so new events don't wipe out properties
6089 e = new Roo.EventObjectImpl(e);
6090 task.delay(o.buffer, h, null, [e]);
6094 var createSingle = function(h, el, ename, fn){
6096 Roo.EventManager.removeListener(el, ename, fn);
6101 var createDelayed = function(h, o){
6103 // create new event object impl so new events don't wipe out properties
6104 e = new Roo.EventObjectImpl(e);
6105 setTimeout(function(){
6111 var listen = function(element, ename, opt, fn, scope){
6112 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6113 fn = fn || o.fn; scope = scope || o.scope;
6114 var el = Roo.getDom(element);
6116 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6118 var h = function(e){
6119 e = Roo.EventObject.setEvent(e);
6122 t = e.getTarget(o.delegate, el);
6129 if(o.stopEvent === true){
6132 if(o.preventDefault === true){
6135 if(o.stopPropagation === true){
6136 e.stopPropagation();
6139 if(o.normalized === false){
6143 fn.call(scope || el, e, t, o);
6146 h = createDelayed(h, o);
6149 h = createSingle(h, el, ename, fn);
6152 h = createBuffered(h, o);
6154 fn._handlers = fn._handlers || [];
6155 fn._handlers.push([Roo.id(el), ename, h]);
6158 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6159 el.addEventListener("DOMMouseScroll", h, false);
6160 E.on(window, 'unload', function(){
6161 el.removeEventListener("DOMMouseScroll", h, false);
6164 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6165 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6170 var stopListening = function(el, ename, fn){
6171 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6173 for(var i = 0, len = hds.length; i < len; i++){
6175 if(h[0] == id && h[1] == ename){
6182 E.un(el, ename, hd);
6183 el = Roo.getDom(el);
6184 if(ename == "mousewheel" && el.addEventListener){
6185 el.removeEventListener("DOMMouseScroll", hd, false);
6187 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6188 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6192 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6199 * @scope Roo.EventManager
6204 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6205 * object with a Roo.EventObject
6206 * @param {Function} fn The method the event invokes
6207 * @param {Object} scope An object that becomes the scope of the handler
6208 * @param {boolean} override If true, the obj passed in becomes
6209 * the execution scope of the listener
6210 * @return {Function} The wrapped function
6213 wrap : function(fn, scope, override){
6215 Roo.EventObject.setEvent(e);
6216 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6221 * Appends an event handler to an element (shorthand for addListener)
6222 * @param {String/HTMLElement} element The html element or id to assign the
6223 * @param {String} eventName The type of event to listen for
6224 * @param {Function} handler The method the event invokes
6225 * @param {Object} scope (optional) The scope in which to execute the handler
6226 * function. The handler function's "this" context.
6227 * @param {Object} options (optional) An object containing handler configuration
6228 * properties. This may contain any of the following properties:<ul>
6229 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6230 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6231 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6232 * <li>preventDefault {Boolean} True to prevent the default action</li>
6233 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6234 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6235 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6236 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6237 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6238 * by the specified number of milliseconds. If the event fires again within that time, the original
6239 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6242 * <b>Combining Options</b><br>
6243 * Using the options argument, it is possible to combine different types of listeners:<br>
6245 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6247 el.on('click', this.onClick, this, {
6254 * <b>Attaching multiple handlers in 1 call</b><br>
6255 * The method also allows for a single argument to be passed which is a config object containing properties
6256 * which specify multiple handlers.
6266 fn: this.onMouseOver
6275 * Or a shorthand syntax:<br>
6278 'click' : this.onClick,
6279 'mouseover' : this.onMouseOver,
6280 'mouseout' : this.onMouseOut
6284 addListener : function(element, eventName, fn, scope, options){
6285 if(typeof eventName == "object"){
6291 if(typeof o[e] == "function"){
6293 listen(element, e, o, o[e], o.scope);
6295 // individual options
6296 listen(element, e, o[e]);
6301 return listen(element, eventName, options, fn, scope);
6305 * Removes an event handler
6307 * @param {String/HTMLElement} element The id or html element to remove the
6309 * @param {String} eventName The type of event
6310 * @param {Function} fn
6311 * @return {Boolean} True if a listener was actually removed
6313 removeListener : function(element, eventName, fn){
6314 return stopListening(element, eventName, fn);
6318 * Fires when the document is ready (before onload and before images are loaded). Can be
6319 * accessed shorthanded Roo.onReady().
6320 * @param {Function} fn The method the event invokes
6321 * @param {Object} scope An object that becomes the scope of the handler
6322 * @param {boolean} options
6324 onDocumentReady : function(fn, scope, options){
6325 if(docReadyState){ // if it already fired
6326 docReadyEvent.addListener(fn, scope, options);
6327 docReadyEvent.fire();
6328 docReadyEvent.clearListeners();
6334 docReadyEvent.addListener(fn, scope, options);
6338 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6339 * @param {Function} fn The method the event invokes
6340 * @param {Object} scope An object that becomes the scope of the handler
6341 * @param {boolean} options
6343 onWindowResize : function(fn, scope, options){
6345 resizeEvent = new Roo.util.Event();
6346 resizeTask = new Roo.util.DelayedTask(function(){
6347 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6349 E.on(window, "resize", function(){
6351 resizeTask.delay(50);
6353 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6357 resizeEvent.addListener(fn, scope, options);
6361 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6362 * @param {Function} fn The method the event invokes
6363 * @param {Object} scope An object that becomes the scope of the handler
6364 * @param {boolean} options
6366 onTextResize : function(fn, scope, options){
6368 textEvent = new Roo.util.Event();
6369 var textEl = new Roo.Element(document.createElement('div'));
6370 textEl.dom.className = 'x-text-resize';
6371 textEl.dom.innerHTML = 'X';
6372 textEl.appendTo(document.body);
6373 textSize = textEl.dom.offsetHeight;
6374 setInterval(function(){
6375 if(textEl.dom.offsetHeight != textSize){
6376 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6378 }, this.textResizeInterval);
6380 textEvent.addListener(fn, scope, options);
6384 * Removes the passed window resize listener.
6385 * @param {Function} fn The method the event invokes
6386 * @param {Object} scope The scope of handler
6388 removeResizeListener : function(fn, scope){
6390 resizeEvent.removeListener(fn, scope);
6395 fireResize : function(){
6397 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6401 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6405 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6407 textResizeInterval : 50
6412 * @scopeAlias pub=Roo.EventManager
6416 * Appends an event handler to an element (shorthand for addListener)
6417 * @param {String/HTMLElement} element The html element or id to assign the
6418 * @param {String} eventName The type of event to listen for
6419 * @param {Function} handler The method the event invokes
6420 * @param {Object} scope (optional) The scope in which to execute the handler
6421 * function. The handler function's "this" context.
6422 * @param {Object} options (optional) An object containing handler configuration
6423 * properties. This may contain any of the following properties:<ul>
6424 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6425 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6426 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6427 * <li>preventDefault {Boolean} True to prevent the default action</li>
6428 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6429 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6430 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6431 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6432 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6433 * by the specified number of milliseconds. If the event fires again within that time, the original
6434 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6437 * <b>Combining Options</b><br>
6438 * Using the options argument, it is possible to combine different types of listeners:<br>
6440 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6442 el.on('click', this.onClick, this, {
6449 * <b>Attaching multiple handlers in 1 call</b><br>
6450 * The method also allows for a single argument to be passed which is a config object containing properties
6451 * which specify multiple handlers.
6461 fn: this.onMouseOver
6470 * Or a shorthand syntax:<br>
6473 'click' : this.onClick,
6474 'mouseover' : this.onMouseOver,
6475 'mouseout' : this.onMouseOut
6479 pub.on = pub.addListener;
6480 pub.un = pub.removeListener;
6482 pub.stoppedMouseDownEvent = new Roo.util.Event();
6486 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6487 * @param {Function} fn The method the event invokes
6488 * @param {Object} scope An object that becomes the scope of the handler
6489 * @param {boolean} override If true, the obj passed in becomes
6490 * the execution scope of the listener
6494 Roo.onReady = Roo.EventManager.onDocumentReady;
6496 Roo.onReady(function(){
6497 var bd = Roo.get(document.body);
6502 : Roo.isGecko ? "roo-gecko"
6503 : Roo.isOpera ? "roo-opera"
6504 : Roo.isSafari ? "roo-safari" : ""];
6507 cls.push("roo-mac");
6510 cls.push("roo-linux");
6512 if(Roo.isBorderBox){
6513 cls.push('roo-border-box');
6515 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6516 var p = bd.dom.parentNode;
6518 p.className += ' roo-strict';
6521 bd.addClass(cls.join(' '));
6525 * @class Roo.EventObject
6526 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6527 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6530 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6532 var target = e.getTarget();
6535 var myDiv = Roo.get("myDiv");
6536 myDiv.on("click", handleClick);
6538 Roo.EventManager.on("myDiv", 'click', handleClick);
6539 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6543 Roo.EventObject = function(){
6545 var E = Roo.lib.Event;
6547 // safari keypress events for special keys return bad keycodes
6550 63235 : 39, // right
6553 63276 : 33, // page up
6554 63277 : 34, // page down
6555 63272 : 46, // delete
6560 // normalize button clicks
6561 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6562 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6564 Roo.EventObjectImpl = function(e){
6566 this.setEvent(e.browserEvent || e);
6569 Roo.EventObjectImpl.prototype = {
6571 * Used to fix doc tools.
6572 * @scope Roo.EventObject.prototype
6578 /** The normal browser event */
6579 browserEvent : null,
6580 /** The button pressed in a mouse event */
6582 /** True if the shift key was down during the event */
6584 /** True if the control key was down during the event */
6586 /** True if the alt key was down during the event */
6645 setEvent : function(e){
6646 if(e == this || (e && e.browserEvent)){ // already wrapped
6649 this.browserEvent = e;
6651 // normalize buttons
6652 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6653 if(e.type == 'click' && this.button == -1){
6657 this.shiftKey = e.shiftKey;
6658 // mac metaKey behaves like ctrlKey
6659 this.ctrlKey = e.ctrlKey || e.metaKey;
6660 this.altKey = e.altKey;
6661 // in getKey these will be normalized for the mac
6662 this.keyCode = e.keyCode;
6663 // keyup warnings on firefox.
6664 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6665 // cache the target for the delayed and or buffered events
6666 this.target = E.getTarget(e);
6668 this.xy = E.getXY(e);
6671 this.shiftKey = false;
6672 this.ctrlKey = false;
6673 this.altKey = false;
6683 * Stop the event (preventDefault and stopPropagation)
6685 stopEvent : function(){
6686 if(this.browserEvent){
6687 if(this.browserEvent.type == 'mousedown'){
6688 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6690 E.stopEvent(this.browserEvent);
6695 * Prevents the browsers default handling of the event.
6697 preventDefault : function(){
6698 if(this.browserEvent){
6699 E.preventDefault(this.browserEvent);
6704 isNavKeyPress : function(){
6705 var k = this.keyCode;
6706 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6707 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6710 isSpecialKey : function(){
6711 var k = this.keyCode;
6712 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6713 (k == 16) || (k == 17) ||
6714 (k >= 18 && k <= 20) ||
6715 (k >= 33 && k <= 35) ||
6716 (k >= 36 && k <= 39) ||
6717 (k >= 44 && k <= 45);
6720 * Cancels bubbling of the event.
6722 stopPropagation : function(){
6723 if(this.browserEvent){
6724 if(this.type == 'mousedown'){
6725 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6727 E.stopPropagation(this.browserEvent);
6732 * Gets the key code for the event.
6735 getCharCode : function(){
6736 return this.charCode || this.keyCode;
6740 * Returns a normalized keyCode for the event.
6741 * @return {Number} The key code
6743 getKey : function(){
6744 var k = this.keyCode || this.charCode;
6745 return Roo.isSafari ? (safariKeys[k] || k) : k;
6749 * Gets the x coordinate of the event.
6752 getPageX : function(){
6757 * Gets the y coordinate of the event.
6760 getPageY : function(){
6765 * Gets the time of the event.
6768 getTime : function(){
6769 if(this.browserEvent){
6770 return E.getTime(this.browserEvent);
6776 * Gets the page coordinates of the event.
6777 * @return {Array} The xy values like [x, y]
6784 * Gets the target for the event.
6785 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6786 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6787 search as a number or element (defaults to 10 || document.body)
6788 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6789 * @return {HTMLelement}
6791 getTarget : function(selector, maxDepth, returnEl){
6792 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6795 * Gets the related target.
6796 * @return {HTMLElement}
6798 getRelatedTarget : function(){
6799 if(this.browserEvent){
6800 return E.getRelatedTarget(this.browserEvent);
6806 * Normalizes mouse wheel delta across browsers
6807 * @return {Number} The delta
6809 getWheelDelta : function(){
6810 var e = this.browserEvent;
6812 if(e.wheelDelta){ /* IE/Opera. */
6813 delta = e.wheelDelta/120;
6814 }else if(e.detail){ /* Mozilla case. */
6815 delta = -e.detail/3;
6821 * Returns true if the control, meta, shift or alt key was pressed during this event.
6824 hasModifier : function(){
6825 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6829 * Returns true if the target of this event equals el or is a child of el
6830 * @param {String/HTMLElement/Element} el
6831 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6834 within : function(el, related){
6835 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6836 return t && Roo.fly(el).contains(t);
6839 getPoint : function(){
6840 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6844 return new Roo.EventObjectImpl();
6849 * Ext JS Library 1.1.1
6850 * Copyright(c) 2006-2007, Ext JS, LLC.
6852 * Originally Released Under LGPL - original licence link has changed is not relivant.
6855 * <script type="text/javascript">
6859 // was in Composite Element!??!?!
6862 var D = Roo.lib.Dom;
6863 var E = Roo.lib.Event;
6864 var A = Roo.lib.Anim;
6866 // local style camelizing for speed
6868 var camelRe = /(-[a-z])/gi;
6869 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6870 var view = document.defaultView;
6873 * @class Roo.Element
6874 * Represents an Element in the DOM.<br><br>
6877 var el = Roo.get("my-div");
6880 var el = getEl("my-div");
6882 // or with a DOM element
6883 var el = Roo.get(myDivElement);
6885 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6886 * each call instead of constructing a new one.<br><br>
6887 * <b>Animations</b><br />
6888 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6889 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6891 Option Default Description
6892 --------- -------- ---------------------------------------------
6893 duration .35 The duration of the animation in seconds
6894 easing easeOut The YUI easing method
6895 callback none A function to execute when the anim completes
6896 scope this The scope (this) of the callback function
6898 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6899 * manipulate the animation. Here's an example:
6901 var el = Roo.get("my-div");
6906 // default animation
6907 el.setWidth(100, true);
6909 // animation with some options set
6916 // using the "anim" property to get the Anim object
6922 el.setWidth(100, opt);
6924 if(opt.anim.isAnimated()){
6928 * <b> Composite (Collections of) Elements</b><br />
6929 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6930 * @constructor Create a new Element directly.
6931 * @param {String/HTMLElement} element
6932 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6934 Roo.Element = function(element, forceNew){
6935 var dom = typeof element == "string" ?
6936 document.getElementById(element) : element;
6937 if(!dom){ // invalid id/element
6941 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6942 return Roo.Element.cache[id];
6952 * The DOM element ID
6955 this.id = id || Roo.id(dom);
6958 var El = Roo.Element;
6962 * The element's default display mode (defaults to "")
6965 originalDisplay : "",
6969 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6974 * Sets the element's visibility mode. When setVisible() is called it
6975 * will use this to determine whether to set the visibility or the display property.
6976 * @param visMode Element.VISIBILITY or Element.DISPLAY
6977 * @return {Roo.Element} this
6979 setVisibilityMode : function(visMode){
6980 this.visibilityMode = visMode;
6984 * Convenience method for setVisibilityMode(Element.DISPLAY)
6985 * @param {String} display (optional) What to set display to when visible
6986 * @return {Roo.Element} this
6988 enableDisplayMode : function(display){
6989 this.setVisibilityMode(El.DISPLAY);
6990 if(typeof display != "undefined") this.originalDisplay = display;
6995 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6996 * @param {String} selector The simple selector to test
6997 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6998 search as a number or element (defaults to 10 || document.body)
6999 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7000 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7002 findParent : function(simpleSelector, maxDepth, returnEl){
7003 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7004 maxDepth = maxDepth || 50;
7005 if(typeof maxDepth != "number"){
7006 stopEl = Roo.getDom(maxDepth);
7009 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7010 if(dq.is(p, simpleSelector)){
7011 return returnEl ? Roo.get(p) : p;
7021 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7022 * @param {String} selector The simple selector to test
7023 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7024 search as a number or element (defaults to 10 || document.body)
7025 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7026 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7028 findParentNode : function(simpleSelector, maxDepth, returnEl){
7029 var p = Roo.fly(this.dom.parentNode, '_internal');
7030 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7034 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7035 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7036 * @param {String} selector The simple selector to test
7037 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7038 search as a number or element (defaults to 10 || document.body)
7039 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7041 up : function(simpleSelector, maxDepth){
7042 return this.findParentNode(simpleSelector, maxDepth, true);
7048 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7049 * @param {String} selector The simple selector to test
7050 * @return {Boolean} True if this element matches the selector, else false
7052 is : function(simpleSelector){
7053 return Roo.DomQuery.is(this.dom, simpleSelector);
7057 * Perform animation on this element.
7058 * @param {Object} args The YUI animation control args
7059 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7060 * @param {Function} onComplete (optional) Function to call when animation completes
7061 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7062 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7063 * @return {Roo.Element} this
7065 animate : function(args, duration, onComplete, easing, animType){
7066 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7071 * @private Internal animation call
7073 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7074 animType = animType || 'run';
7076 var anim = Roo.lib.Anim[animType](
7078 (opt.duration || defaultDur) || .35,
7079 (opt.easing || defaultEase) || 'easeOut',
7081 Roo.callback(cb, this);
7082 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7090 // private legacy anim prep
7091 preanim : function(a, i){
7092 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7096 * Removes worthless text nodes
7097 * @param {Boolean} forceReclean (optional) By default the element
7098 * keeps track if it has been cleaned already so
7099 * you can call this over and over. However, if you update the element and
7100 * need to force a reclean, you can pass true.
7102 clean : function(forceReclean){
7103 if(this.isCleaned && forceReclean !== true){
7107 var d = this.dom, n = d.firstChild, ni = -1;
7109 var nx = n.nextSibling;
7110 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7117 this.isCleaned = true;
7122 calcOffsetsTo : function(el){
7125 var restorePos = false;
7126 if(el.getStyle('position') == 'static'){
7127 el.position('relative');
7132 while(op && op != d && op.tagName != 'HTML'){
7135 op = op.offsetParent;
7138 el.position('static');
7144 * Scrolls this element into view within the passed container.
7145 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7146 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7147 * @return {Roo.Element} this
7149 scrollIntoView : function(container, hscroll){
7150 var c = Roo.getDom(container) || document.body;
7153 var o = this.calcOffsetsTo(c),
7156 b = t+el.offsetHeight,
7157 r = l+el.offsetWidth;
7159 var ch = c.clientHeight;
7160 var ct = parseInt(c.scrollTop, 10);
7161 var cl = parseInt(c.scrollLeft, 10);
7163 var cr = cl + c.clientWidth;
7171 if(hscroll !== false){
7175 c.scrollLeft = r-c.clientWidth;
7182 scrollChildIntoView : function(child, hscroll){
7183 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7187 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7188 * the new height may not be available immediately.
7189 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7190 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7191 * @param {Function} onComplete (optional) Function to call when animation completes
7192 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7193 * @return {Roo.Element} this
7195 autoHeight : function(animate, duration, onComplete, easing){
7196 var oldHeight = this.getHeight();
7198 this.setHeight(1); // force clipping
7199 setTimeout(function(){
7200 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7202 this.setHeight(height);
7204 if(typeof onComplete == "function"){
7208 this.setHeight(oldHeight); // restore original height
7209 this.setHeight(height, animate, duration, function(){
7211 if(typeof onComplete == "function") onComplete();
7212 }.createDelegate(this), easing);
7214 }.createDelegate(this), 0);
7219 * Returns true if this element is an ancestor of the passed element
7220 * @param {HTMLElement/String} el The element to check
7221 * @return {Boolean} True if this element is an ancestor of el, else false
7223 contains : function(el){
7224 if(!el){return false;}
7225 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7229 * Checks whether the element is currently visible using both visibility and display properties.
7230 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7231 * @return {Boolean} True if the element is currently visible, else false
7233 isVisible : function(deep) {
7234 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7235 if(deep !== true || !vis){
7238 var p = this.dom.parentNode;
7239 while(p && p.tagName.toLowerCase() != "body"){
7240 if(!Roo.fly(p, '_isVisible').isVisible()){
7249 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7250 * @param {String} selector The CSS selector
7251 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7252 * @return {CompositeElement/CompositeElementLite} The composite element
7254 select : function(selector, unique){
7255 return El.select(selector, unique, this.dom);
7259 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7260 * @param {String} selector The CSS selector
7261 * @return {Array} An array of the matched nodes
7263 query : function(selector, unique){
7264 return Roo.DomQuery.select(selector, this.dom);
7268 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7269 * @param {String} selector The CSS selector
7270 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7271 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7273 child : function(selector, returnDom){
7274 var n = Roo.DomQuery.selectNode(selector, this.dom);
7275 return returnDom ? n : Roo.get(n);
7279 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 down : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7291 * @param {String} group The group the DD object is member of
7292 * @param {Object} config The DD config object
7293 * @param {Object} overrides An object containing methods to override/implement on the DD object
7294 * @return {Roo.dd.DD} The DD object
7296 initDD : function(group, config, overrides){
7297 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7298 return Roo.apply(dd, overrides);
7302 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7303 * @param {String} group The group the DDProxy object is member of
7304 * @param {Object} config The DDProxy config object
7305 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7306 * @return {Roo.dd.DDProxy} The DDProxy object
7308 initDDProxy : function(group, config, overrides){
7309 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7310 return Roo.apply(dd, overrides);
7314 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7315 * @param {String} group The group the DDTarget object is member of
7316 * @param {Object} config The DDTarget config object
7317 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7318 * @return {Roo.dd.DDTarget} The DDTarget object
7320 initDDTarget : function(group, config, overrides){
7321 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7322 return Roo.apply(dd, overrides);
7326 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7327 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7328 * @param {Boolean} visible Whether the element is visible
7329 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7330 * @return {Roo.Element} this
7332 setVisible : function(visible, animate){
7334 if(this.visibilityMode == El.DISPLAY){
7335 this.setDisplayed(visible);
7338 this.dom.style.visibility = visible ? "visible" : "hidden";
7341 // closure for composites
7343 var visMode = this.visibilityMode;
7345 this.setOpacity(.01);
7346 this.setVisible(true);
7348 this.anim({opacity: { to: (visible?1:0) }},
7349 this.preanim(arguments, 1),
7350 null, .35, 'easeIn', function(){
7352 if(visMode == El.DISPLAY){
7353 dom.style.display = "none";
7355 dom.style.visibility = "hidden";
7357 Roo.get(dom).setOpacity(1);
7365 * Returns true if display is not "none"
7368 isDisplayed : function() {
7369 return this.getStyle("display") != "none";
7373 * Toggles the element's visibility or display, depending on visibility mode.
7374 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7375 * @return {Roo.Element} this
7377 toggle : function(animate){
7378 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7383 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7384 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7385 * @return {Roo.Element} this
7387 setDisplayed : function(value) {
7388 if(typeof value == "boolean"){
7389 value = value ? this.originalDisplay : "none";
7391 this.setStyle("display", value);
7396 * Tries to focus the element. Any exceptions are caught and ignored.
7397 * @return {Roo.Element} this
7399 focus : function() {
7407 * Tries to blur the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7418 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7419 * @param {String/Array} className The CSS class to add, or an array of classes
7420 * @return {Roo.Element} this
7422 addClass : function(className){
7423 if(className instanceof Array){
7424 for(var i = 0, len = className.length; i < len; i++) {
7425 this.addClass(className[i]);
7428 if(className && !this.hasClass(className)){
7429 this.dom.className = this.dom.className + " " + className;
7436 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7437 * @param {String/Array} className The CSS class to add, or an array of classes
7438 * @return {Roo.Element} this
7440 radioClass : function(className){
7441 var siblings = this.dom.parentNode.childNodes;
7442 for(var i = 0; i < siblings.length; i++) {
7443 var s = siblings[i];
7444 if(s.nodeType == 1){
7445 Roo.get(s).removeClass(className);
7448 this.addClass(className);
7453 * Removes one or more CSS classes from the element.
7454 * @param {String/Array} className The CSS class to remove, or an array of classes
7455 * @return {Roo.Element} this
7457 removeClass : function(className){
7458 if(!className || !this.dom.className){
7461 if(className instanceof Array){
7462 for(var i = 0, len = className.length; i < len; i++) {
7463 this.removeClass(className[i]);
7466 if(this.hasClass(className)){
7467 var re = this.classReCache[className];
7469 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7470 this.classReCache[className] = re;
7472 this.dom.className =
7473 this.dom.className.replace(re, " ");
7483 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7484 * @param {String} className The CSS class to toggle
7485 * @return {Roo.Element} this
7487 toggleClass : function(className){
7488 if(this.hasClass(className)){
7489 this.removeClass(className);
7491 this.addClass(className);
7497 * Checks if the specified CSS class exists on this element's DOM node.
7498 * @param {String} className The CSS class to check for
7499 * @return {Boolean} True if the class exists, else false
7501 hasClass : function(className){
7502 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7506 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7507 * @param {String} oldClassName The CSS class to replace
7508 * @param {String} newClassName The replacement CSS class
7509 * @return {Roo.Element} this
7511 replaceClass : function(oldClassName, newClassName){
7512 this.removeClass(oldClassName);
7513 this.addClass(newClassName);
7518 * Returns an object with properties matching the styles requested.
7519 * For example, el.getStyles('color', 'font-size', 'width') might return
7520 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7521 * @param {String} style1 A style name
7522 * @param {String} style2 A style name
7523 * @param {String} etc.
7524 * @return {Object} The style object
7526 getStyles : function(){
7527 var a = arguments, len = a.length, r = {};
7528 for(var i = 0; i < len; i++){
7529 r[a[i]] = this.getStyle(a[i]);
7535 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7536 * @param {String} property The style property whose value is returned.
7537 * @return {String} The current value of the style property for this element.
7539 getStyle : function(){
7540 return view && view.getComputedStyle ?
7542 var el = this.dom, v, cs, camel;
7543 if(prop == 'float'){
7546 if(el.style && (v = el.style[prop])){
7549 if(cs = view.getComputedStyle(el, "")){
7550 if(!(camel = propCache[prop])){
7551 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7558 var el = this.dom, v, cs, camel;
7559 if(prop == 'opacity'){
7560 if(typeof el.style.filter == 'string'){
7561 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7563 var fv = parseFloat(m[1]);
7565 return fv ? fv / 100 : 0;
7570 }else if(prop == 'float'){
7571 prop = "styleFloat";
7573 if(!(camel = propCache[prop])){
7574 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7576 if(v = el.style[camel]){
7579 if(cs = el.currentStyle){
7587 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7588 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7589 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7590 * @return {Roo.Element} this
7592 setStyle : function(prop, value){
7593 if(typeof prop == "string"){
7595 if (prop == 'float') {
7596 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7601 if(!(camel = propCache[prop])){
7602 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7605 if(camel == 'opacity') {
7606 this.setOpacity(value);
7608 this.dom.style[camel] = value;
7611 for(var style in prop){
7612 if(typeof prop[style] != "function"){
7613 this.setStyle(style, prop[style]);
7621 * More flexible version of {@link #setStyle} for setting style properties.
7622 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7623 * a function which returns such a specification.
7624 * @return {Roo.Element} this
7626 applyStyles : function(style){
7627 Roo.DomHelper.applyStyles(this.dom, style);
7632 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7633 * @return {Number} The X position of the element
7636 return D.getX(this.dom);
7640 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7641 * @return {Number} The Y position of the element
7644 return D.getY(this.dom);
7648 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7649 * @return {Array} The XY position of the element
7652 return D.getXY(this.dom);
7656 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7657 * @param {Number} The X position of the element
7658 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7659 * @return {Roo.Element} this
7661 setX : function(x, animate){
7663 D.setX(this.dom, x);
7665 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7671 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7672 * @param {Number} The Y position of the element
7673 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7674 * @return {Roo.Element} this
7676 setY : function(y, animate){
7678 D.setY(this.dom, y);
7680 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7686 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7687 * @param {String} left The left CSS property value
7688 * @return {Roo.Element} this
7690 setLeft : function(left){
7691 this.setStyle("left", this.addUnits(left));
7696 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7697 * @param {String} top The top CSS property value
7698 * @return {Roo.Element} this
7700 setTop : function(top){
7701 this.setStyle("top", this.addUnits(top));
7706 * Sets the element's CSS right style.
7707 * @param {String} right The right CSS property value
7708 * @return {Roo.Element} this
7710 setRight : function(right){
7711 this.setStyle("right", this.addUnits(right));
7716 * Sets the element's CSS bottom style.
7717 * @param {String} bottom The bottom CSS property value
7718 * @return {Roo.Element} this
7720 setBottom : function(bottom){
7721 this.setStyle("bottom", this.addUnits(bottom));
7726 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7727 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7728 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7729 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730 * @return {Roo.Element} this
7732 setXY : function(pos, animate){
7734 D.setXY(this.dom, pos);
7736 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7742 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7743 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7744 * @param {Number} x X value for new position (coordinates are page-based)
7745 * @param {Number} y Y value for new position (coordinates are page-based)
7746 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747 * @return {Roo.Element} this
7749 setLocation : function(x, y, animate){
7750 this.setXY([x, y], this.preanim(arguments, 2));
7755 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7756 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7757 * @param {Number} x X value for new position (coordinates are page-based)
7758 * @param {Number} y Y value for new position (coordinates are page-based)
7759 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7760 * @return {Roo.Element} this
7762 moveTo : function(x, y, animate){
7763 this.setXY([x, y], this.preanim(arguments, 2));
7768 * Returns the region of the given element.
7769 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7770 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7772 getRegion : function(){
7773 return D.getRegion(this.dom);
7777 * Returns the offset height of the element
7778 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7779 * @return {Number} The element's height
7781 getHeight : function(contentHeight){
7782 var h = this.dom.offsetHeight || 0;
7783 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7787 * Returns the offset width of the element
7788 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7789 * @return {Number} The element's width
7791 getWidth : function(contentWidth){
7792 var w = this.dom.offsetWidth || 0;
7793 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7797 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7798 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7799 * if a height has not been set using CSS.
7802 getComputedHeight : function(){
7803 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7805 h = parseInt(this.getStyle('height'), 10) || 0;
7806 if(!this.isBorderBox()){
7807 h += this.getFrameWidth('tb');
7814 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7815 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7816 * if a width has not been set using CSS.
7819 getComputedWidth : function(){
7820 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7822 w = parseInt(this.getStyle('width'), 10) || 0;
7823 if(!this.isBorderBox()){
7824 w += this.getFrameWidth('lr');
7831 * Returns the size of the element.
7832 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7833 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7835 getSize : function(contentSize){
7836 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7840 * Returns the width and height of the viewport.
7841 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7843 getViewSize : function(){
7844 var d = this.dom, doc = document, aw = 0, ah = 0;
7845 if(d == doc || d == doc.body){
7846 return {width : D.getViewWidth(), height: D.getViewHeight()};
7849 width : d.clientWidth,
7850 height: d.clientHeight
7856 * Returns the value of the "value" attribute
7857 * @param {Boolean} asNumber true to parse the value as a number
7858 * @return {String/Number}
7860 getValue : function(asNumber){
7861 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7865 adjustWidth : function(width){
7866 if(typeof width == "number"){
7867 if(this.autoBoxAdjust && !this.isBorderBox()){
7868 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7878 adjustHeight : function(height){
7879 if(typeof height == "number"){
7880 if(this.autoBoxAdjust && !this.isBorderBox()){
7881 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7891 * Set the width of the element
7892 * @param {Number} width The new width
7893 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7894 * @return {Roo.Element} this
7896 setWidth : function(width, animate){
7897 width = this.adjustWidth(width);
7899 this.dom.style.width = this.addUnits(width);
7901 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7907 * Set the height of the element
7908 * @param {Number} height The new height
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setHeight : function(height, animate){
7913 height = this.adjustHeight(height);
7915 this.dom.style.height = this.addUnits(height);
7917 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7923 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7924 * @param {Number} width The new width
7925 * @param {Number} height The new height
7926 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7927 * @return {Roo.Element} this
7929 setSize : function(width, height, animate){
7930 if(typeof width == "object"){ // in case of object from getSize()
7931 height = width.height; width = width.width;
7933 width = this.adjustWidth(width); height = this.adjustHeight(height);
7935 this.dom.style.width = this.addUnits(width);
7936 this.dom.style.height = this.addUnits(height);
7938 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7944 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7945 * @param {Number} x X value for new position (coordinates are page-based)
7946 * @param {Number} y Y value for new position (coordinates are page-based)
7947 * @param {Number} width The new width
7948 * @param {Number} height The new height
7949 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7950 * @return {Roo.Element} this
7952 setBounds : function(x, y, width, height, animate){
7954 this.setSize(width, height);
7955 this.setLocation(x, y);
7957 width = this.adjustWidth(width); height = this.adjustHeight(height);
7958 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7959 this.preanim(arguments, 4), 'motion');
7965 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7966 * @param {Roo.lib.Region} region The region to fill
7967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7968 * @return {Roo.Element} this
7970 setRegion : function(region, animate){
7971 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7976 * Appends an event handler
7978 * @param {String} eventName The type of event to append
7979 * @param {Function} fn The method the event invokes
7980 * @param {Object} scope (optional) The scope (this object) of the fn
7981 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7983 addListener : function(eventName, fn, scope, options){
7985 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7990 * Removes an event handler from this element
7991 * @param {String} eventName the type of event to remove
7992 * @param {Function} fn the method the event invokes
7993 * @return {Roo.Element} this
7995 removeListener : function(eventName, fn){
7996 Roo.EventManager.removeListener(this.dom, eventName, fn);
8001 * Removes all previous added listeners from this element
8002 * @return {Roo.Element} this
8004 removeAllListeners : function(){
8005 E.purgeElement(this.dom);
8009 relayEvent : function(eventName, observable){
8010 this.on(eventName, function(e){
8011 observable.fireEvent(eventName, e);
8016 * Set the opacity of the element
8017 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8018 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8019 * @return {Roo.Element} this
8021 setOpacity : function(opacity, animate){
8023 var s = this.dom.style;
8026 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8027 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8029 s.opacity = opacity;
8032 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8038 * Gets the left X coordinate
8039 * @param {Boolean} local True to get the local css position instead of page coordinate
8042 getLeft : function(local){
8046 return parseInt(this.getStyle("left"), 10) || 0;
8051 * Gets the right X coordinate of the element (element X position + element width)
8052 * @param {Boolean} local True to get the local css position instead of page coordinate
8055 getRight : function(local){
8057 return this.getX() + this.getWidth();
8059 return (this.getLeft(true) + this.getWidth()) || 0;
8064 * Gets the top Y coordinate
8065 * @param {Boolean} local True to get the local css position instead of page coordinate
8068 getTop : function(local) {
8072 return parseInt(this.getStyle("top"), 10) || 0;
8077 * Gets the bottom Y coordinate of the element (element Y position + element height)
8078 * @param {Boolean} local True to get the local css position instead of page coordinate
8081 getBottom : function(local){
8083 return this.getY() + this.getHeight();
8085 return (this.getTop(true) + this.getHeight()) || 0;
8090 * Initializes positioning on this element. If a desired position is not passed, it will make the
8091 * the element positioned relative IF it is not already positioned.
8092 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8093 * @param {Number} zIndex (optional) The zIndex to apply
8094 * @param {Number} x (optional) Set the page X position
8095 * @param {Number} y (optional) Set the page Y position
8097 position : function(pos, zIndex, x, y){
8099 if(this.getStyle('position') == 'static'){
8100 this.setStyle('position', 'relative');
8103 this.setStyle("position", pos);
8106 this.setStyle("z-index", zIndex);
8108 if(x !== undefined && y !== undefined){
8110 }else if(x !== undefined){
8112 }else if(y !== undefined){
8118 * Clear positioning back to the default when the document was loaded
8119 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8120 * @return {Roo.Element} this
8122 clearPositioning : function(value){
8130 "position" : "static"
8136 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8137 * snapshot before performing an update and then restoring the element.
8140 getPositioning : function(){
8141 var l = this.getStyle("left");
8142 var t = this.getStyle("top");
8144 "position" : this.getStyle("position"),
8146 "right" : l ? "" : this.getStyle("right"),
8148 "bottom" : t ? "" : this.getStyle("bottom"),
8149 "z-index" : this.getStyle("z-index")
8154 * Gets the width of the border(s) for the specified side(s)
8155 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8156 * passing lr would get the border (l)eft width + the border (r)ight width.
8157 * @return {Number} The width of the sides passed added together
8159 getBorderWidth : function(side){
8160 return this.addStyles(side, El.borders);
8164 * Gets the width of the padding(s) for the specified side(s)
8165 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8166 * passing lr would get the padding (l)eft + the padding (r)ight.
8167 * @return {Number} The padding of the sides passed added together
8169 getPadding : function(side){
8170 return this.addStyles(side, El.paddings);
8174 * Set positioning with an object returned by getPositioning().
8175 * @param {Object} posCfg
8176 * @return {Roo.Element} this
8178 setPositioning : function(pc){
8179 this.applyStyles(pc);
8180 if(pc.right == "auto"){
8181 this.dom.style.right = "";
8183 if(pc.bottom == "auto"){
8184 this.dom.style.bottom = "";
8190 fixDisplay : function(){
8191 if(this.getStyle("display") == "none"){
8192 this.setStyle("visibility", "hidden");
8193 this.setStyle("display", this.originalDisplay); // first try reverting to default
8194 if(this.getStyle("display") == "none"){ // if that fails, default to block
8195 this.setStyle("display", "block");
8201 * Quick set left and top adding default units
8202 * @param {String} left The left CSS property value
8203 * @param {String} top The top CSS property value
8204 * @return {Roo.Element} this
8206 setLeftTop : function(left, top){
8207 this.dom.style.left = this.addUnits(left);
8208 this.dom.style.top = this.addUnits(top);
8213 * Move this element relative to its current position.
8214 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8215 * @param {Number} distance How far to move the element in pixels
8216 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8217 * @return {Roo.Element} this
8219 move : function(direction, distance, animate){
8220 var xy = this.getXY();
8221 direction = direction.toLowerCase();
8225 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8229 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8234 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8239 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8246 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8247 * @return {Roo.Element} this
8250 if(!this.isClipped){
8251 this.isClipped = true;
8252 this.originalClip = {
8253 "o": this.getStyle("overflow"),
8254 "x": this.getStyle("overflow-x"),
8255 "y": this.getStyle("overflow-y")
8257 this.setStyle("overflow", "hidden");
8258 this.setStyle("overflow-x", "hidden");
8259 this.setStyle("overflow-y", "hidden");
8265 * Return clipping (overflow) to original clipping before clip() was called
8266 * @return {Roo.Element} this
8268 unclip : function(){
8270 this.isClipped = false;
8271 var o = this.originalClip;
8272 if(o.o){this.setStyle("overflow", o.o);}
8273 if(o.x){this.setStyle("overflow-x", o.x);}
8274 if(o.y){this.setStyle("overflow-y", o.y);}
8281 * Gets the x,y coordinates specified by the anchor position on the element.
8282 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8283 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8284 * {width: (target width), height: (target height)} (defaults to the element's current size)
8285 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8286 * @return {Array} [x, y] An array containing the element's x and y coordinates
8288 getAnchorXY : function(anchor, local, s){
8289 //Passing a different size is useful for pre-calculating anchors,
8290 //especially for anchored animations that change the el size.
8292 var w, h, vp = false;
8295 if(d == document.body || d == document){
8297 w = D.getViewWidth(); h = D.getViewHeight();
8299 w = this.getWidth(); h = this.getHeight();
8302 w = s.width; h = s.height;
8304 var x = 0, y = 0, r = Math.round;
8305 switch((anchor || "tl").toLowerCase()){
8347 var sc = this.getScroll();
8348 return [x + sc.left, y + sc.top];
8350 //Add the element's offset xy
8351 var o = this.getXY();
8352 return [x+o[0], y+o[1]];
8356 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8357 * supported position values.
8358 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8359 * @param {String} position The position to align to.
8360 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8361 * @return {Array} [x, y]
8363 getAlignToXY : function(el, p, o){
8367 throw "Element.alignTo with an element that doesn't exist";
8369 var c = false; //constrain to viewport
8370 var p1 = "", p2 = "";
8377 }else if(p.indexOf("-") == -1){
8380 p = p.toLowerCase();
8381 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8383 throw "Element.alignTo with an invalid alignment " + p;
8385 p1 = m[1]; p2 = m[2]; c = !!m[3];
8387 //Subtract the aligned el's internal xy from the target's offset xy
8388 //plus custom offset to get the aligned el's new offset xy
8389 var a1 = this.getAnchorXY(p1, true);
8390 var a2 = el.getAnchorXY(p2, false);
8391 var x = a2[0] - a1[0] + o[0];
8392 var y = a2[1] - a1[1] + o[1];
8394 //constrain the aligned el to viewport if necessary
8395 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8396 // 5px of margin for ie
8397 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8399 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8400 //perpendicular to the vp border, allow the aligned el to slide on that border,
8401 //otherwise swap the aligned el to the opposite border of the target.
8402 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8403 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8404 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8405 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8408 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8409 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8411 if((x+w) > dw + scrollX){
8412 x = swapX ? r.left-w : dw+scrollX-w;
8415 x = swapX ? r.right : scrollX;
8417 if((y+h) > dh + scrollY){
8418 y = swapY ? r.top-h : dh+scrollY-h;
8421 y = swapY ? r.bottom : scrollY;
8428 getConstrainToXY : function(){
8429 var os = {top:0, left:0, bottom:0, right: 0};
8431 return function(el, local, offsets, proposedXY){
8433 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8435 var vw, vh, vx = 0, vy = 0;
8436 if(el.dom == document.body || el.dom == document){
8437 vw = Roo.lib.Dom.getViewWidth();
8438 vh = Roo.lib.Dom.getViewHeight();
8440 vw = el.dom.clientWidth;
8441 vh = el.dom.clientHeight;
8443 var vxy = el.getXY();
8449 var s = el.getScroll();
8451 vx += offsets.left + s.left;
8452 vy += offsets.top + s.top;
8454 vw -= offsets.right;
8455 vh -= offsets.bottom;
8460 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8461 var x = xy[0], y = xy[1];
8462 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8464 // only move it if it needs it
8467 // first validate right/bottom
8476 // then make sure top/left isn't negative
8485 return moved ? [x, y] : false;
8490 adjustForConstraints : function(xy, parent, offsets){
8491 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8495 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8496 * document it aligns it to the viewport.
8497 * The position parameter is optional, and can be specified in any one of the following formats:
8499 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8500 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8501 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8502 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8503 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8504 * element's anchor point, and the second value is used as the target's anchor point.</li>
8506 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8507 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8508 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8509 * that specified in order to enforce the viewport constraints.
8510 * Following are all of the supported anchor positions:
8513 ----- -----------------------------
8514 tl The top left corner (default)
8515 t The center of the top edge
8516 tr The top right corner
8517 l The center of the left edge
8518 c In the center of the element
8519 r The center of the right edge
8520 bl The bottom left corner
8521 b The center of the bottom edge
8522 br The bottom right corner
8526 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8527 el.alignTo("other-el");
8529 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8530 el.alignTo("other-el", "tr?");
8532 // align the bottom right corner of el with the center left edge of other-el
8533 el.alignTo("other-el", "br-l?");
8535 // align the center of el with the bottom left corner of other-el and
8536 // adjust the x position by -6 pixels (and the y position by 0)
8537 el.alignTo("other-el", "c-bl", [-6, 0]);
8539 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8540 * @param {String} position The position to align to.
8541 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8542 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8543 * @return {Roo.Element} this
8545 alignTo : function(element, position, offsets, animate){
8546 var xy = this.getAlignToXY(element, position, offsets);
8547 this.setXY(xy, this.preanim(arguments, 3));
8552 * Anchors an element to another element and realigns it when the window is resized.
8553 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8554 * @param {String} position The position to align to.
8555 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8556 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8557 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8558 * is a number, it is used as the buffer delay (defaults to 50ms).
8559 * @param {Function} callback The function to call after the animation finishes
8560 * @return {Roo.Element} this
8562 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8563 var action = function(){
8564 this.alignTo(el, alignment, offsets, animate);
8565 Roo.callback(callback, this);
8567 Roo.EventManager.onWindowResize(action, this);
8568 var tm = typeof monitorScroll;
8569 if(tm != 'undefined'){
8570 Roo.EventManager.on(window, 'scroll', action, this,
8571 {buffer: tm == 'number' ? monitorScroll : 50});
8573 action.call(this); // align immediately
8577 * Clears any opacity settings from this element. Required in some cases for IE.
8578 * @return {Roo.Element} this
8580 clearOpacity : function(){
8581 if (window.ActiveXObject) {
8582 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8583 this.dom.style.filter = "";
8586 this.dom.style.opacity = "";
8587 this.dom.style["-moz-opacity"] = "";
8588 this.dom.style["-khtml-opacity"] = "";
8594 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8595 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8596 * @return {Roo.Element} this
8598 hide : function(animate){
8599 this.setVisible(false, this.preanim(arguments, 0));
8604 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8605 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8606 * @return {Roo.Element} this
8608 show : function(animate){
8609 this.setVisible(true, this.preanim(arguments, 0));
8614 * @private Test if size has a unit, otherwise appends the default
8616 addUnits : function(size){
8617 return Roo.Element.addUnits(size, this.defaultUnit);
8621 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8622 * @return {Roo.Element} this
8624 beginMeasure : function(){
8626 if(el.offsetWidth || el.offsetHeight){
8627 return this; // offsets work already
8630 var p = this.dom, b = document.body; // start with this element
8631 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8632 var pe = Roo.get(p);
8633 if(pe.getStyle('display') == 'none'){
8634 changed.push({el: p, visibility: pe.getStyle("visibility")});
8635 p.style.visibility = "hidden";
8636 p.style.display = "block";
8640 this._measureChanged = changed;
8646 * Restores displays to before beginMeasure was called
8647 * @return {Roo.Element} this
8649 endMeasure : function(){
8650 var changed = this._measureChanged;
8652 for(var i = 0, len = changed.length; i < len; i++) {
8654 r.el.style.visibility = r.visibility;
8655 r.el.style.display = "none";
8657 this._measureChanged = null;
8663 * Update the innerHTML of this element, optionally searching for and processing scripts
8664 * @param {String} html The new HTML
8665 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8666 * @param {Function} callback For async script loading you can be noticed when the update completes
8667 * @return {Roo.Element} this
8669 update : function(html, loadScripts, callback){
8670 if(typeof html == "undefined"){
8673 if(loadScripts !== true){
8674 this.dom.innerHTML = html;
8675 if(typeof callback == "function"){
8683 html += '<span id="' + id + '"></span>';
8685 E.onAvailable(id, function(){
8686 var hd = document.getElementsByTagName("head")[0];
8687 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8688 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8689 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8692 while(match = re.exec(html)){
8693 var attrs = match[1];
8694 var srcMatch = attrs ? attrs.match(srcRe) : false;
8695 if(srcMatch && srcMatch[2]){
8696 var s = document.createElement("script");
8697 s.src = srcMatch[2];
8698 var typeMatch = attrs.match(typeRe);
8699 if(typeMatch && typeMatch[2]){
8700 s.type = typeMatch[2];
8703 }else if(match[2] && match[2].length > 0){
8704 if(window.execScript) {
8705 window.execScript(match[2]);
8713 window.eval(match[2]);
8717 var el = document.getElementById(id);
8718 if(el){el.parentNode.removeChild(el);}
8719 if(typeof callback == "function"){
8723 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8728 * Direct access to the UpdateManager update() method (takes the same parameters).
8729 * @param {String/Function} url The url for this request or a function to call to get the url
8730 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8731 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8732 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8733 * @return {Roo.Element} this
8736 var um = this.getUpdateManager();
8737 um.update.apply(um, arguments);
8742 * Gets this element's UpdateManager
8743 * @return {Roo.UpdateManager} The UpdateManager
8745 getUpdateManager : function(){
8746 if(!this.updateManager){
8747 this.updateManager = new Roo.UpdateManager(this);
8749 return this.updateManager;
8753 * Disables text selection for this element (normalized across browsers)
8754 * @return {Roo.Element} this
8756 unselectable : function(){
8757 this.dom.unselectable = "on";
8758 this.swallowEvent("selectstart", true);
8759 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8760 this.addClass("x-unselectable");
8765 * Calculates the x, y to center this element on the screen
8766 * @return {Array} The x, y values [x, y]
8768 getCenterXY : function(){
8769 return this.getAlignToXY(document, 'c-c');
8773 * Centers the Element in either the viewport, or another Element.
8774 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8776 center : function(centerIn){
8777 this.alignTo(centerIn || document, 'c-c');
8782 * Tests various css rules/browsers to determine if this element uses a border box
8785 isBorderBox : function(){
8786 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8790 * Return a box {x, y, width, height} that can be used to set another elements
8791 * size/location to match this element.
8792 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8793 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8794 * @return {Object} box An object in the format {x, y, width, height}
8796 getBox : function(contentBox, local){
8801 var left = parseInt(this.getStyle("left"), 10) || 0;
8802 var top = parseInt(this.getStyle("top"), 10) || 0;
8805 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8807 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8809 var l = this.getBorderWidth("l")+this.getPadding("l");
8810 var r = this.getBorderWidth("r")+this.getPadding("r");
8811 var t = this.getBorderWidth("t")+this.getPadding("t");
8812 var b = this.getBorderWidth("b")+this.getPadding("b");
8813 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8815 bx.right = bx.x + bx.width;
8816 bx.bottom = bx.y + bx.height;
8821 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8822 for more information about the sides.
8823 * @param {String} sides
8826 getFrameWidth : function(sides, onlyContentBox){
8827 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8831 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8832 * @param {Object} box The box to fill {x, y, width, height}
8833 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8834 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8835 * @return {Roo.Element} this
8837 setBox : function(box, adjust, animate){
8838 var w = box.width, h = box.height;
8839 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8840 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8841 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8843 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8848 * Forces the browser to repaint this element
8849 * @return {Roo.Element} this
8851 repaint : function(){
8853 this.addClass("x-repaint");
8854 setTimeout(function(){
8855 Roo.get(dom).removeClass("x-repaint");
8861 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8862 * then it returns the calculated width of the sides (see getPadding)
8863 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8864 * @return {Object/Number}
8866 getMargins : function(side){
8869 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8870 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8871 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8872 right: parseInt(this.getStyle("margin-right"), 10) || 0
8875 return this.addStyles(side, El.margins);
8880 addStyles : function(sides, styles){
8882 for(var i = 0, len = sides.length; i < len; i++){
8883 v = this.getStyle(styles[sides.charAt(i)]);
8885 w = parseInt(v, 10);
8893 * Creates a proxy element of this element
8894 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8895 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8896 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8897 * @return {Roo.Element} The new proxy element
8899 createProxy : function(config, renderTo, matchBox){
8901 renderTo = Roo.getDom(renderTo);
8903 renderTo = document.body;
8905 config = typeof config == "object" ?
8906 config : {tag : "div", cls: config};
8907 var proxy = Roo.DomHelper.append(renderTo, config, true);
8909 proxy.setBox(this.getBox());
8915 * Puts a mask over this element to disable user interaction. Requires core.css.
8916 * This method can only be applied to elements which accept child nodes.
8917 * @param {String} msg (optional) A message to display in the mask
8918 * @param {String} msgCls (optional) A css class to apply to the msg element
8919 * @return {Element} The mask element
8921 mask : function(msg, msgCls)
8923 if(this.getStyle("position") == "static"){
8924 this.setStyle("position", "relative");
8927 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8929 this.addClass("x-masked");
8930 this._mask.setDisplayed(true);
8935 while (dom && dom.style) {
8936 if (!isNaN(parseInt(dom.style.zIndex))) {
8937 z = Math.max(z, parseInt(dom.style.zIndex));
8939 dom = dom.parentNode;
8941 // if we are masking the body - then it hides everything..
8942 if (this.dom == document.body) {
8944 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8945 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8948 if(typeof msg == 'string'){
8950 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8952 var mm = this._maskMsg;
8953 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8954 mm.dom.firstChild.innerHTML = msg;
8955 mm.setDisplayed(true);
8957 mm.setStyle('z-index', z + 102);
8959 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8960 this._mask.setHeight(this.getHeight());
8962 this._mask.setStyle('z-index', z + 100);
8968 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8969 * it is cached for reuse.
8971 unmask : function(removeEl){
8973 if(removeEl === true){
8974 this._mask.remove();
8977 this._maskMsg.remove();
8978 delete this._maskMsg;
8981 this._mask.setDisplayed(false);
8983 this._maskMsg.setDisplayed(false);
8987 this.removeClass("x-masked");
8991 * Returns true if this element is masked
8994 isMasked : function(){
8995 return this._mask && this._mask.isVisible();
8999 * Creates an iframe shim for this element to keep selects and other windowed objects from
9001 * @return {Roo.Element} The new shim element
9003 createShim : function(){
9004 var el = document.createElement('iframe');
9005 el.frameBorder = 'no';
9006 el.className = 'roo-shim';
9007 if(Roo.isIE && Roo.isSecure){
9008 el.src = Roo.SSL_SECURE_URL;
9010 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9011 shim.autoBoxAdjust = false;
9016 * Removes this element from the DOM and deletes it from the cache
9018 remove : function(){
9019 if(this.dom.parentNode){
9020 this.dom.parentNode.removeChild(this.dom);
9022 delete El.cache[this.dom.id];
9026 * Sets up event handlers to add and remove a css class when the mouse is over this element
9027 * @param {String} className
9028 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9029 * mouseout events for children elements
9030 * @return {Roo.Element} this
9032 addClassOnOver : function(className, preventFlicker){
9033 this.on("mouseover", function(){
9034 Roo.fly(this, '_internal').addClass(className);
9036 var removeFn = function(e){
9037 if(preventFlicker !== true || !e.within(this, true)){
9038 Roo.fly(this, '_internal').removeClass(className);
9041 this.on("mouseout", removeFn, this.dom);
9046 * Sets up event handlers to add and remove a css class when this element has the focus
9047 * @param {String} className
9048 * @return {Roo.Element} this
9050 addClassOnFocus : function(className){
9051 this.on("focus", function(){
9052 Roo.fly(this, '_internal').addClass(className);
9054 this.on("blur", function(){
9055 Roo.fly(this, '_internal').removeClass(className);
9060 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9061 * @param {String} className
9062 * @return {Roo.Element} this
9064 addClassOnClick : function(className){
9066 this.on("mousedown", function(){
9067 Roo.fly(dom, '_internal').addClass(className);
9068 var d = Roo.get(document);
9069 var fn = function(){
9070 Roo.fly(dom, '_internal').removeClass(className);
9071 d.removeListener("mouseup", fn);
9073 d.on("mouseup", fn);
9079 * Stops the specified event from bubbling and optionally prevents the default action
9080 * @param {String} eventName
9081 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9082 * @return {Roo.Element} this
9084 swallowEvent : function(eventName, preventDefault){
9085 var fn = function(e){
9086 e.stopPropagation();
9091 if(eventName instanceof Array){
9092 for(var i = 0, len = eventName.length; i < len; i++){
9093 this.on(eventName[i], fn);
9097 this.on(eventName, fn);
9104 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9107 * Sizes this element to its parent element's dimensions performing
9108 * neccessary box adjustments.
9109 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9110 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9111 * @return {Roo.Element} this
9113 fitToParent : function(monitorResize, targetParent) {
9114 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9115 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9116 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9119 var p = Roo.get(targetParent || this.dom.parentNode);
9120 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9121 if (monitorResize === true) {
9122 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9123 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9129 * Gets the next sibling, skipping text nodes
9130 * @return {HTMLElement} The next sibling or null
9132 getNextSibling : function(){
9133 var n = this.dom.nextSibling;
9134 while(n && n.nodeType != 1){
9141 * Gets the previous sibling, skipping text nodes
9142 * @return {HTMLElement} The previous sibling or null
9144 getPrevSibling : function(){
9145 var n = this.dom.previousSibling;
9146 while(n && n.nodeType != 1){
9147 n = n.previousSibling;
9154 * Appends the passed element(s) to this element
9155 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9156 * @return {Roo.Element} this
9158 appendChild: function(el){
9165 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9166 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9167 * automatically generated with the specified attributes.
9168 * @param {HTMLElement} insertBefore (optional) a child element of this element
9169 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9170 * @return {Roo.Element} The new child element
9172 createChild: function(config, insertBefore, returnDom){
9173 config = config || {tag:'div'};
9175 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9177 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9181 * Appends this element to the passed element
9182 * @param {String/HTMLElement/Element} el The new parent element
9183 * @return {Roo.Element} this
9185 appendTo: function(el){
9186 el = Roo.getDom(el);
9187 el.appendChild(this.dom);
9192 * Inserts this element before the passed element in the DOM
9193 * @param {String/HTMLElement/Element} el The element to insert before
9194 * @return {Roo.Element} this
9196 insertBefore: function(el){
9197 el = Roo.getDom(el);
9198 el.parentNode.insertBefore(this.dom, el);
9203 * Inserts this element after the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert after
9205 * @return {Roo.Element} this
9207 insertAfter: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el.nextSibling);
9214 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9215 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9216 * @return {Roo.Element} The new child
9218 insertFirst: function(el, returnDom){
9220 if(typeof el == 'object' && !el.nodeType){ // dh config
9221 return this.createChild(el, this.dom.firstChild, returnDom);
9223 el = Roo.getDom(el);
9224 this.dom.insertBefore(el, this.dom.firstChild);
9225 return !returnDom ? Roo.get(el) : el;
9230 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9231 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9232 * @param {String} where (optional) 'before' or 'after' defaults to before
9233 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9234 * @return {Roo.Element} the inserted Element
9236 insertSibling: function(el, where, returnDom){
9237 where = where ? where.toLowerCase() : 'before';
9239 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9241 if(typeof el == 'object' && !el.nodeType){ // dh config
9242 if(where == 'after' && !this.dom.nextSibling){
9243 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9245 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9249 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9250 where == 'before' ? this.dom : this.dom.nextSibling);
9259 * Creates and wraps this element with another element
9260 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9261 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9262 * @return {HTMLElement/Element} The newly created wrapper element
9264 wrap: function(config, returnDom){
9266 config = {tag: "div"};
9268 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9269 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9274 * Replaces the passed element with this element
9275 * @param {String/HTMLElement/Element} el The element to replace
9276 * @return {Roo.Element} this
9278 replace: function(el){
9280 this.insertBefore(el);
9286 * Inserts an html fragment into this element
9287 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9288 * @param {String} html The HTML fragment
9289 * @param {Boolean} returnEl True to return an Roo.Element
9290 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9292 insertHtml : function(where, html, returnEl){
9293 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9294 return returnEl ? Roo.get(el) : el;
9298 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9299 * @param {Object} o The object with the attributes
9300 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9301 * @return {Roo.Element} this
9303 set : function(o, useSet){
9305 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9307 if(attr == "style" || typeof o[attr] == "function") continue;
9309 el.className = o["cls"];
9311 if(useSet) el.setAttribute(attr, o[attr]);
9312 else el[attr] = o[attr];
9316 Roo.DomHelper.applyStyles(el, o.style);
9322 * Convenience method for constructing a KeyMap
9323 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9324 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9325 * @param {Function} fn The function to call
9326 * @param {Object} scope (optional) The scope of the function
9327 * @return {Roo.KeyMap} The KeyMap created
9329 addKeyListener : function(key, fn, scope){
9331 if(typeof key != "object" || key instanceof Array){
9347 return new Roo.KeyMap(this, config);
9351 * Creates a KeyMap for this element
9352 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9353 * @return {Roo.KeyMap} The KeyMap created
9355 addKeyMap : function(config){
9356 return new Roo.KeyMap(this, config);
9360 * Returns true if this element is scrollable.
9363 isScrollable : function(){
9365 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9369 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9370 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9371 * @param {Number} value The new scroll value
9372 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9373 * @return {Element} this
9376 scrollTo : function(side, value, animate){
9377 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9379 this.dom[prop] = value;
9381 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9382 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9388 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9389 * within this element's scrollable range.
9390 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9391 * @param {Number} distance How far to scroll the element in pixels
9392 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9393 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9394 * was scrolled as far as it could go.
9396 scroll : function(direction, distance, animate){
9397 if(!this.isScrollable()){
9401 var l = el.scrollLeft, t = el.scrollTop;
9402 var w = el.scrollWidth, h = el.scrollHeight;
9403 var cw = el.clientWidth, ch = el.clientHeight;
9404 direction = direction.toLowerCase();
9405 var scrolled = false;
9406 var a = this.preanim(arguments, 2);
9411 var v = Math.min(l + distance, w-cw);
9412 this.scrollTo("left", v, a);
9419 var v = Math.max(l - distance, 0);
9420 this.scrollTo("left", v, a);
9428 var v = Math.max(t - distance, 0);
9429 this.scrollTo("top", v, a);
9437 var v = Math.min(t + distance, h-ch);
9438 this.scrollTo("top", v, a);
9447 * Translates the passed page coordinates into left/top css values for this element
9448 * @param {Number/Array} x The page x or an array containing [x, y]
9449 * @param {Number} y The page y
9450 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9452 translatePoints : function(x, y){
9453 if(typeof x == 'object' || x instanceof Array){
9456 var p = this.getStyle('position');
9457 var o = this.getXY();
9459 var l = parseInt(this.getStyle('left'), 10);
9460 var t = parseInt(this.getStyle('top'), 10);
9463 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9466 t = (p == "relative") ? 0 : this.dom.offsetTop;
9469 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9473 * Returns the current scroll position of the element.
9474 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9476 getScroll : function(){
9477 var d = this.dom, doc = document;
9478 if(d == doc || d == doc.body){
9479 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9480 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9481 return {left: l, top: t};
9483 return {left: d.scrollLeft, top: d.scrollTop};
9488 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9489 * are convert to standard 6 digit hex color.
9490 * @param {String} attr The css attribute
9491 * @param {String} defaultValue The default value to use when a valid color isn't found
9492 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9495 getColor : function(attr, defaultValue, prefix){
9496 var v = this.getStyle(attr);
9497 if(!v || v == "transparent" || v == "inherit") {
9498 return defaultValue;
9500 var color = typeof prefix == "undefined" ? "#" : prefix;
9501 if(v.substr(0, 4) == "rgb("){
9502 var rvs = v.slice(4, v.length -1).split(",");
9503 for(var i = 0; i < 3; i++){
9504 var h = parseInt(rvs[i]).toString(16);
9511 if(v.substr(0, 1) == "#"){
9513 for(var i = 1; i < 4; i++){
9514 var c = v.charAt(i);
9517 }else if(v.length == 7){
9518 color += v.substr(1);
9522 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9526 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9527 * gradient background, rounded corners and a 4-way shadow.
9528 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9529 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9530 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9531 * @return {Roo.Element} this
9533 boxWrap : function(cls){
9534 cls = cls || 'x-box';
9535 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9536 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9541 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9542 * @param {String} namespace The namespace in which to look for the attribute
9543 * @param {String} name The attribute name
9544 * @return {String} The attribute value
9546 getAttributeNS : Roo.isIE ? function(ns, name){
9548 var type = typeof d[ns+":"+name];
9549 if(type != 'undefined' && type != 'unknown'){
9550 return d[ns+":"+name];
9553 } : function(ns, name){
9555 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9559 var ep = El.prototype;
9562 * Appends an event handler (Shorthand for addListener)
9563 * @param {String} eventName The type of event to append
9564 * @param {Function} fn The method the event invokes
9565 * @param {Object} scope (optional) The scope (this object) of the fn
9566 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9569 ep.on = ep.addListener;
9571 ep.mon = ep.addListener;
9574 * Removes an event handler from this element (shorthand for removeListener)
9575 * @param {String} eventName the type of event to remove
9576 * @param {Function} fn the method the event invokes
9577 * @return {Roo.Element} this
9580 ep.un = ep.removeListener;
9583 * true to automatically adjust width and height settings for box-model issues (default to true)
9585 ep.autoBoxAdjust = true;
9588 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9591 El.addUnits = function(v, defaultUnit){
9592 if(v === "" || v == "auto"){
9595 if(v === undefined){
9598 if(typeof v == "number" || !El.unitPattern.test(v)){
9599 return v + (defaultUnit || 'px');
9604 // special markup used throughout Roo when box wrapping elements
9605 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9607 * Visibility mode constant - Use visibility to hide element
9613 * Visibility mode constant - Use display to hide element
9619 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9620 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9621 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9633 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9634 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9635 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9636 * @return {Element} The Element object
9639 El.get = function(el){
9641 if(!el){ return null; }
9642 if(typeof el == "string"){ // element id
9643 if(!(elm = document.getElementById(el))){
9646 if(ex = El.cache[el]){
9649 ex = El.cache[el] = new El(elm);
9652 }else if(el.tagName){ // dom element
9656 if(ex = El.cache[id]){
9659 ex = El.cache[id] = new El(el);
9662 }else if(el instanceof El){
9664 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9665 // catch case where it hasn't been appended
9666 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9669 }else if(el.isComposite){
9671 }else if(el instanceof Array){
9672 return El.select(el);
9673 }else if(el == document){
9674 // create a bogus element object representing the document object
9676 var f = function(){};
9677 f.prototype = El.prototype;
9679 docEl.dom = document;
9687 El.uncache = function(el){
9688 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9690 delete El.cache[a[i].id || a[i]];
9696 // Garbage collection - uncache elements/purge listeners on orphaned elements
9697 // so we don't hold a reference and cause the browser to retain them
9698 El.garbageCollect = function(){
9699 if(!Roo.enableGarbageCollector){
9700 clearInterval(El.collectorThread);
9703 for(var eid in El.cache){
9704 var el = El.cache[eid], d = el.dom;
9705 // -------------------------------------------------------
9706 // Determining what is garbage:
9707 // -------------------------------------------------------
9709 // dom node is null, definitely garbage
9710 // -------------------------------------------------------
9712 // no parentNode == direct orphan, definitely garbage
9713 // -------------------------------------------------------
9714 // !d.offsetParent && !document.getElementById(eid)
9715 // display none elements have no offsetParent so we will
9716 // also try to look it up by it's id. However, check
9717 // offsetParent first so we don't do unneeded lookups.
9718 // This enables collection of elements that are not orphans
9719 // directly, but somewhere up the line they have an orphan
9721 // -------------------------------------------------------
9722 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9723 delete El.cache[eid];
9724 if(d && Roo.enableListenerCollection){
9730 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9734 El.Flyweight = function(dom){
9737 El.Flyweight.prototype = El.prototype;
9739 El._flyweights = {};
9741 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9742 * the dom node can be overwritten by other code.
9743 * @param {String/HTMLElement} el The dom node or id
9744 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9745 * prevent conflicts (e.g. internally Roo uses "_internal")
9747 * @return {Element} The shared Element object
9749 El.fly = function(el, named){
9750 named = named || '_global';
9751 el = Roo.getDom(el);
9755 if(!El._flyweights[named]){
9756 El._flyweights[named] = new El.Flyweight();
9758 El._flyweights[named].dom = el;
9759 return El._flyweights[named];
9763 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9764 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9765 * Shorthand of {@link Roo.Element#get}
9766 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9767 * @return {Element} The Element object
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * Shorthand of {@link Roo.Element#fly}
9776 * @param {String/HTMLElement} el The dom node or id
9777 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9778 * prevent conflicts (e.g. internally Roo uses "_internal")
9780 * @return {Element} The shared Element object
9786 // speedy lookup for elements never to box adjust
9787 var noBoxAdjust = Roo.isStrict ? {
9790 input:1, select:1, textarea:1
9792 if(Roo.isIE || Roo.isGecko){
9793 noBoxAdjust['button'] = 1;
9797 Roo.EventManager.on(window, 'unload', function(){
9799 delete El._flyweights;
9807 Roo.Element.selectorFunction = Roo.DomQuery.select;
9810 Roo.Element.select = function(selector, unique, root){
9812 if(typeof selector == "string"){
9813 els = Roo.Element.selectorFunction(selector, root);
9814 }else if(selector.length !== undefined){
9817 throw "Invalid selector";
9819 if(unique === true){
9820 return new Roo.CompositeElement(els);
9822 return new Roo.CompositeElementLite(els);
9826 * Selects elements based on the passed CSS selector to enable working on them as 1.
9827 * @param {String/Array} selector The CSS selector or an array of elements
9828 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9829 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9830 * @return {CompositeElementLite/CompositeElement}
9834 Roo.select = Roo.Element.select;
9851 * Ext JS Library 1.1.1
9852 * Copyright(c) 2006-2007, Ext JS, LLC.
9854 * Originally Released Under LGPL - original licence link has changed is not relivant.
9857 * <script type="text/javascript">
9862 //Notifies Element that fx methods are available
9863 Roo.enableFx = true;
9867 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9868 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9869 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9870 * Element effects to work.</p><br/>
9872 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9873 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9874 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9875 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9876 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9877 * expected results and should be done with care.</p><br/>
9879 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9880 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9883 ----- -----------------------------
9884 tl The top left corner
9885 t The center of the top edge
9886 tr The top right corner
9887 l The center of the left edge
9888 r The center of the right edge
9889 bl The bottom left corner
9890 b The center of the bottom edge
9891 br The bottom right corner
9893 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9894 * below are common options that can be passed to any Fx method.</b>
9895 * @cfg {Function} callback A function called when the effect is finished
9896 * @cfg {Object} scope The scope of the effect function
9897 * @cfg {String} easing A valid Easing value for the effect
9898 * @cfg {String} afterCls A css class to apply after the effect
9899 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9900 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9901 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9902 * effects that end with the element being visually hidden, ignored otherwise)
9903 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9904 * a function which returns such a specification that will be applied to the Element after the effect finishes
9905 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9906 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9907 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9911 * Slides the element into view. An anchor point can be optionally passed to set the point of
9912 * origin for the slide effect. This function automatically handles wrapping the element with
9913 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9916 // default: slide the element in from the top
9919 // custom: slide the element in from the right with a 2-second duration
9920 el.slideIn('r', { duration: 2 });
9922 // common config options shown with default values
9928 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9929 * @param {Object} options (optional) Object literal with any of the Fx config options
9930 * @return {Roo.Element} The Element
9932 slideIn : function(anchor, o){
9933 var el = this.getFxEl();
9936 el.queueFx(o, function(){
9938 anchor = anchor || "t";
9940 // fix display to visibility
9943 // restore values after effect
9944 var r = this.getFxRestore();
9945 var b = this.getBox();
9946 // fixed size for slide
9950 var wrap = this.fxWrap(r.pos, o, "hidden");
9952 var st = this.dom.style;
9953 st.visibility = "visible";
9954 st.position = "absolute";
9956 // clear out temp styles after slide and unwrap
9957 var after = function(){
9958 el.fxUnwrap(wrap, r.pos, o);
9960 st.height = r.height;
9963 // time to calc the positions
9964 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9966 switch(anchor.toLowerCase()){
9968 wrap.setSize(b.width, 0);
9969 st.left = st.bottom = "0";
9973 wrap.setSize(0, b.height);
9974 st.right = st.top = "0";
9978 wrap.setSize(0, b.height);
9980 st.left = st.top = "0";
9981 a = {width: bw, points: pt};
9984 wrap.setSize(b.width, 0);
9985 wrap.setY(b.bottom);
9986 st.left = st.top = "0";
9987 a = {height: bh, points: pt};
9991 st.right = st.bottom = "0";
9992 a = {width: bw, height: bh};
9996 wrap.setY(b.y+b.height);
9997 st.right = st.top = "0";
9998 a = {width: bw, height: bh, points: pt};
10001 wrap.setSize(0, 0);
10002 wrap.setXY([b.right, b.bottom]);
10003 st.left = st.top = "0";
10004 a = {width: bw, height: bh, points: pt};
10007 wrap.setSize(0, 0);
10008 wrap.setX(b.x+b.width);
10009 st.left = st.bottom = "0";
10010 a = {width: bw, height: bh, points: pt};
10013 this.dom.style.visibility = "visible";
10016 arguments.callee.anim = wrap.fxanim(a,
10026 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10027 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10028 * 'hidden') but block elements will still take up space in the document. The element must be removed
10029 * from the DOM using the 'remove' config option if desired. This function automatically handles
10030 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10033 // default: slide the element out to the top
10036 // custom: slide the element out to the right with a 2-second duration
10037 el.slideOut('r', { duration: 2 });
10039 // common config options shown with default values
10047 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10048 * @param {Object} options (optional) Object literal with any of the Fx config options
10049 * @return {Roo.Element} The Element
10051 slideOut : function(anchor, o){
10052 var el = this.getFxEl();
10055 el.queueFx(o, function(){
10057 anchor = anchor || "t";
10059 // restore values after effect
10060 var r = this.getFxRestore();
10062 var b = this.getBox();
10063 // fixed size for slide
10067 var wrap = this.fxWrap(r.pos, o, "visible");
10069 var st = this.dom.style;
10070 st.visibility = "visible";
10071 st.position = "absolute";
10075 var after = function(){
10077 el.setDisplayed(false);
10082 el.fxUnwrap(wrap, r.pos, o);
10084 st.width = r.width;
10085 st.height = r.height;
10090 var a, zero = {to: 0};
10091 switch(anchor.toLowerCase()){
10093 st.left = st.bottom = "0";
10094 a = {height: zero};
10097 st.right = st.top = "0";
10101 st.left = st.top = "0";
10102 a = {width: zero, points: {to:[b.right, b.y]}};
10105 st.left = st.top = "0";
10106 a = {height: zero, points: {to:[b.x, b.bottom]}};
10109 st.right = st.bottom = "0";
10110 a = {width: zero, height: zero};
10113 st.right = st.top = "0";
10114 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10117 st.left = st.top = "0";
10118 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10121 st.left = st.bottom = "0";
10122 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10126 arguments.callee.anim = wrap.fxanim(a,
10136 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10137 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10138 * The element must be removed from the DOM using the 'remove' config option if desired.
10144 // common config options shown with default values
10152 * @param {Object} options (optional) Object literal with any of the Fx config options
10153 * @return {Roo.Element} The Element
10155 puff : function(o){
10156 var el = this.getFxEl();
10159 el.queueFx(o, function(){
10160 this.clearOpacity();
10163 // restore values after effect
10164 var r = this.getFxRestore();
10165 var st = this.dom.style;
10167 var after = function(){
10169 el.setDisplayed(false);
10176 el.setPositioning(r.pos);
10177 st.width = r.width;
10178 st.height = r.height;
10183 var width = this.getWidth();
10184 var height = this.getHeight();
10186 arguments.callee.anim = this.fxanim({
10187 width : {to: this.adjustWidth(width * 2)},
10188 height : {to: this.adjustHeight(height * 2)},
10189 points : {by: [-(width * .5), -(height * .5)]},
10191 fontSize: {to:200, unit: "%"}
10202 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10203 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10204 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10210 // all config options shown with default values
10218 * @param {Object} options (optional) Object literal with any of the Fx config options
10219 * @return {Roo.Element} The Element
10221 switchOff : function(o){
10222 var el = this.getFxEl();
10225 el.queueFx(o, function(){
10226 this.clearOpacity();
10229 // restore values after effect
10230 var r = this.getFxRestore();
10231 var st = this.dom.style;
10233 var after = function(){
10235 el.setDisplayed(false);
10241 el.setPositioning(r.pos);
10242 st.width = r.width;
10243 st.height = r.height;
10248 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10249 this.clearOpacity();
10253 points:{by:[0, this.getHeight() * .5]}
10254 }, o, 'motion', 0.3, 'easeIn', after);
10255 }).defer(100, this);
10262 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10263 * changed using the "attr" config option) and then fading back to the original color. If no original
10264 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10267 // default: highlight background to yellow
10270 // custom: highlight foreground text to blue for 2 seconds
10271 el.highlight("0000ff", { attr: 'color', duration: 2 });
10273 // common config options shown with default values
10274 el.highlight("ffff9c", {
10275 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10276 endColor: (current color) or "ffffff",
10281 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10282 * @param {Object} options (optional) Object literal with any of the Fx config options
10283 * @return {Roo.Element} The Element
10285 highlight : function(color, o){
10286 var el = this.getFxEl();
10289 el.queueFx(o, function(){
10290 color = color || "ffff9c";
10291 attr = o.attr || "backgroundColor";
10293 this.clearOpacity();
10296 var origColor = this.getColor(attr);
10297 var restoreColor = this.dom.style[attr];
10298 endColor = (o.endColor || origColor) || "ffffff";
10300 var after = function(){
10301 el.dom.style[attr] = restoreColor;
10306 a[attr] = {from: color, to: endColor};
10307 arguments.callee.anim = this.fxanim(a,
10317 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10320 // default: a single light blue ripple
10323 // custom: 3 red ripples lasting 3 seconds total
10324 el.frame("ff0000", 3, { duration: 3 });
10326 // common config options shown with default values
10327 el.frame("C3DAF9", 1, {
10328 duration: 1 //duration of entire animation (not each individual ripple)
10329 // Note: Easing is not configurable and will be ignored if included
10332 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10333 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10334 * @param {Object} options (optional) Object literal with any of the Fx config options
10335 * @return {Roo.Element} The Element
10337 frame : function(color, count, o){
10338 var el = this.getFxEl();
10341 el.queueFx(o, function(){
10342 color = color || "#C3DAF9";
10343 if(color.length == 6){
10344 color = "#" + color;
10346 count = count || 1;
10347 duration = o.duration || 1;
10350 var b = this.getBox();
10351 var animFn = function(){
10352 var proxy = this.createProxy({
10355 visbility:"hidden",
10356 position:"absolute",
10357 "z-index":"35000", // yee haw
10358 border:"0px solid " + color
10361 var scale = Roo.isBorderBox ? 2 : 1;
10363 top:{from:b.y, to:b.y - 20},
10364 left:{from:b.x, to:b.x - 20},
10365 borderWidth:{from:0, to:10},
10366 opacity:{from:1, to:0},
10367 height:{from:b.height, to:(b.height + (20*scale))},
10368 width:{from:b.width, to:(b.width + (20*scale))}
10369 }, duration, function(){
10373 animFn.defer((duration/2)*1000, this);
10384 * Creates a pause before any subsequent queued effects begin. If there are
10385 * no effects queued after the pause it will have no effect.
10390 * @param {Number} seconds The length of time to pause (in seconds)
10391 * @return {Roo.Element} The Element
10393 pause : function(seconds){
10394 var el = this.getFxEl();
10397 el.queueFx(o, function(){
10398 setTimeout(function(){
10400 }, seconds * 1000);
10406 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10407 * using the "endOpacity" config option.
10410 // default: fade in from opacity 0 to 100%
10413 // custom: fade in from opacity 0 to 75% over 2 seconds
10414 el.fadeIn({ endOpacity: .75, duration: 2});
10416 // common config options shown with default values
10418 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10423 * @param {Object} options (optional) Object literal with any of the Fx config options
10424 * @return {Roo.Element} The Element
10426 fadeIn : function(o){
10427 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 this.setOpacity(0);
10432 this.dom.style.visibility = 'visible';
10433 var to = o.endOpacity || 1;
10434 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10435 o, null, .5, "easeOut", function(){
10437 this.clearOpacity();
10446 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade out from the element's current opacity to 0
10453 // custom: fade out from the element's current opacity to 25% over 2 seconds
10454 el.fadeOut({ endOpacity: .25, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10465 * @param {Object} options (optional) Object literal with any of the Fx config options
10466 * @return {Roo.Element} The Element
10468 fadeOut : function(o){
10469 var el = this.getFxEl();
10471 el.queueFx(o, function(){
10472 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10473 o, null, .5, "easeOut", function(){
10474 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10475 this.dom.style.display = "none";
10477 this.dom.style.visibility = "hidden";
10479 this.clearOpacity();
10487 * Animates the transition of an element's dimensions from a starting height/width
10488 * to an ending height/width.
10491 // change height and width to 100x100 pixels
10492 el.scale(100, 100);
10494 // common config options shown with default values. The height and width will default to
10495 // the element's existing values if passed as null.
10498 [element's height], {
10503 * @param {Number} width The new width (pass undefined to keep the original width)
10504 * @param {Number} height The new height (pass undefined to keep the original height)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 scale : function(w, h, o){
10509 this.shift(Roo.apply({}, o, {
10517 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10518 * Any of these properties not specified in the config object will not be changed. This effect
10519 * requires that at least one new dimension, position or opacity setting must be passed in on
10520 * the config object in order for the function to have any effect.
10523 // slide the element horizontally to x position 200 while changing the height and opacity
10524 el.shift({ x: 200, height: 50, opacity: .8 });
10526 // common config options shown with default values.
10528 width: [element's width],
10529 height: [element's height],
10530 x: [element's x position],
10531 y: [element's y position],
10532 opacity: [element's opacity],
10537 * @param {Object} options Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 shift : function(o){
10541 var el = this.getFxEl();
10543 el.queueFx(o, function(){
10544 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10545 if(w !== undefined){
10546 a.width = {to: this.adjustWidth(w)};
10548 if(h !== undefined){
10549 a.height = {to: this.adjustHeight(h)};
10551 if(x !== undefined || y !== undefined){
10553 x !== undefined ? x : this.getX(),
10554 y !== undefined ? y : this.getY()
10557 if(op !== undefined){
10558 a.opacity = {to: op};
10560 if(o.xy !== undefined){
10561 a.points = {to: o.xy};
10563 arguments.callee.anim = this.fxanim(a,
10564 o, 'motion', .35, "easeOut", function(){
10572 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10573 * ending point of the effect.
10576 // default: slide the element downward while fading out
10579 // custom: slide the element out to the right with a 2-second duration
10580 el.ghost('r', { duration: 2 });
10582 // common config options shown with default values
10590 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10591 * @param {Object} options (optional) Object literal with any of the Fx config options
10592 * @return {Roo.Element} The Element
10594 ghost : function(anchor, o){
10595 var el = this.getFxEl();
10598 el.queueFx(o, function(){
10599 anchor = anchor || "b";
10601 // restore values after effect
10602 var r = this.getFxRestore();
10603 var w = this.getWidth(),
10604 h = this.getHeight();
10606 var st = this.dom.style;
10608 var after = function(){
10610 el.setDisplayed(false);
10616 el.setPositioning(r.pos);
10617 st.width = r.width;
10618 st.height = r.height;
10623 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10624 switch(anchor.toLowerCase()){
10651 arguments.callee.anim = this.fxanim(a,
10661 * Ensures that all effects queued after syncFx is called on the element are
10662 * run concurrently. This is the opposite of {@link #sequenceFx}.
10663 * @return {Roo.Element} The Element
10665 syncFx : function(){
10666 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10675 * Ensures that all effects queued after sequenceFx is called on the element are
10676 * run in sequence. This is the opposite of {@link #syncFx}.
10677 * @return {Roo.Element} The Element
10679 sequenceFx : function(){
10680 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10682 concurrent : false,
10689 nextFx : function(){
10690 var ef = this.fxQueue[0];
10697 * Returns true if the element has any effects actively running or queued, else returns false.
10698 * @return {Boolean} True if element has active effects, else false
10700 hasActiveFx : function(){
10701 return this.fxQueue && this.fxQueue[0];
10705 * Stops any running effects and clears the element's internal effects queue if it contains
10706 * any additional effects that haven't started yet.
10707 * @return {Roo.Element} The Element
10709 stopFx : function(){
10710 if(this.hasActiveFx()){
10711 var cur = this.fxQueue[0];
10712 if(cur && cur.anim && cur.anim.isAnimated()){
10713 this.fxQueue = [cur]; // clear out others
10714 cur.anim.stop(true);
10721 beforeFx : function(o){
10722 if(this.hasActiveFx() && !o.concurrent){
10733 * Returns true if the element is currently blocking so that no other effect can be queued
10734 * until this effect is finished, else returns false if blocking is not set. This is commonly
10735 * used to ensure that an effect initiated by a user action runs to completion prior to the
10736 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10737 * @return {Boolean} True if blocking, else false
10739 hasFxBlock : function(){
10740 var q = this.fxQueue;
10741 return q && q[0] && q[0].block;
10745 queueFx : function(o, fn){
10749 if(!this.hasFxBlock()){
10750 Roo.applyIf(o, this.fxDefaults);
10752 var run = this.beforeFx(o);
10753 fn.block = o.block;
10754 this.fxQueue.push(fn);
10766 fxWrap : function(pos, o, vis){
10768 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10771 wrapXY = this.getXY();
10773 var div = document.createElement("div");
10774 div.style.visibility = vis;
10775 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10776 wrap.setPositioning(pos);
10777 if(wrap.getStyle("position") == "static"){
10778 wrap.position("relative");
10780 this.clearPositioning('auto');
10782 wrap.dom.appendChild(this.dom);
10784 wrap.setXY(wrapXY);
10791 fxUnwrap : function(wrap, pos, o){
10792 this.clearPositioning();
10793 this.setPositioning(pos);
10795 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10801 getFxRestore : function(){
10802 var st = this.dom.style;
10803 return {pos: this.getPositioning(), width: st.width, height : st.height};
10807 afterFx : function(o){
10809 this.applyStyles(o.afterStyle);
10812 this.addClass(o.afterCls);
10814 if(o.remove === true){
10817 Roo.callback(o.callback, o.scope, [this]);
10819 this.fxQueue.shift();
10825 getFxEl : function(){ // support for composite element fx
10826 return Roo.get(this.dom);
10830 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10831 animType = animType || 'run';
10833 var anim = Roo.lib.Anim[animType](
10835 (opt.duration || defaultDur) || .35,
10836 (opt.easing || defaultEase) || 'easeOut',
10838 Roo.callback(cb, this);
10847 // backwords compat
10848 Roo.Fx.resize = Roo.Fx.scale;
10850 //When included, Roo.Fx is automatically applied to Element so that all basic
10851 //effects are available directly via the Element API
10852 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10854 * Ext JS Library 1.1.1
10855 * Copyright(c) 2006-2007, Ext JS, LLC.
10857 * Originally Released Under LGPL - original licence link has changed is not relivant.
10860 * <script type="text/javascript">
10865 * @class Roo.CompositeElement
10866 * Standard composite class. Creates a Roo.Element for every element in the collection.
10868 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10869 * actions will be performed on all the elements in this collection.</b>
10871 * All methods return <i>this</i> and can be chained.
10873 var els = Roo.select("#some-el div.some-class", true);
10874 // or select directly from an existing element
10875 var el = Roo.get('some-el');
10876 el.select('div.some-class', true);
10878 els.setWidth(100); // all elements become 100 width
10879 els.hide(true); // all elements fade out and hide
10881 els.setWidth(100).hide(true);
10884 Roo.CompositeElement = function(els){
10885 this.elements = [];
10886 this.addElements(els);
10888 Roo.CompositeElement.prototype = {
10890 addElements : function(els){
10891 if(!els) return this;
10892 if(typeof els == "string"){
10893 els = Roo.Element.selectorFunction(els);
10895 var yels = this.elements;
10896 var index = yels.length-1;
10897 for(var i = 0, len = els.length; i < len; i++) {
10898 yels[++index] = Roo.get(els[i]);
10904 * Clears this composite and adds the elements returned by the passed selector.
10905 * @param {String/Array} els A string CSS selector, an array of elements or an element
10906 * @return {CompositeElement} this
10908 fill : function(els){
10909 this.elements = [];
10915 * Filters this composite to only elements that match the passed selector.
10916 * @param {String} selector A string CSS selector
10917 * @return {CompositeElement} this
10919 filter : function(selector){
10921 this.each(function(el){
10922 if(el.is(selector)){
10923 els[els.length] = el.dom;
10930 invoke : function(fn, args){
10931 var els = this.elements;
10932 for(var i = 0, len = els.length; i < len; i++) {
10933 Roo.Element.prototype[fn].apply(els[i], args);
10938 * Adds elements to this composite.
10939 * @param {String/Array} els A string CSS selector, an array of elements or an element
10940 * @return {CompositeElement} this
10942 add : function(els){
10943 if(typeof els == "string"){
10944 this.addElements(Roo.Element.selectorFunction(els));
10945 }else if(els.length !== undefined){
10946 this.addElements(els);
10948 this.addElements([els]);
10953 * Calls the passed function passing (el, this, index) for each element in this composite.
10954 * @param {Function} fn The function to call
10955 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10956 * @return {CompositeElement} this
10958 each : function(fn, scope){
10959 var els = this.elements;
10960 for(var i = 0, len = els.length; i < len; i++){
10961 if(fn.call(scope || els[i], els[i], this, i) === false) {
10969 * Returns the Element object at the specified index
10970 * @param {Number} index
10971 * @return {Roo.Element}
10973 item : function(index){
10974 return this.elements[index] || null;
10978 * Returns the first Element
10979 * @return {Roo.Element}
10981 first : function(){
10982 return this.item(0);
10986 * Returns the last Element
10987 * @return {Roo.Element}
10990 return this.item(this.elements.length-1);
10994 * Returns the number of elements in this composite
10997 getCount : function(){
10998 return this.elements.length;
11002 * Returns true if this composite contains the passed element
11005 contains : function(el){
11006 return this.indexOf(el) !== -1;
11010 * Returns true if this composite contains the passed element
11013 indexOf : function(el){
11014 return this.elements.indexOf(Roo.get(el));
11019 * Removes the specified element(s).
11020 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11021 * or an array of any of those.
11022 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11023 * @return {CompositeElement} this
11025 removeElement : function(el, removeDom){
11026 if(el instanceof Array){
11027 for(var i = 0, len = el.length; i < len; i++){
11028 this.removeElement(el[i]);
11032 var index = typeof el == 'number' ? el : this.indexOf(el);
11035 var d = this.elements[index];
11039 d.parentNode.removeChild(d);
11042 this.elements.splice(index, 1);
11048 * Replaces the specified element with the passed element.
11049 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11051 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11052 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11053 * @return {CompositeElement} this
11055 replaceElement : function(el, replacement, domReplace){
11056 var index = typeof el == 'number' ? el : this.indexOf(el);
11059 this.elements[index].replaceWith(replacement);
11061 this.elements.splice(index, 1, Roo.get(replacement))
11068 * Removes all elements.
11070 clear : function(){
11071 this.elements = [];
11075 Roo.CompositeElement.createCall = function(proto, fnName){
11076 if(!proto[fnName]){
11077 proto[fnName] = function(){
11078 return this.invoke(fnName, arguments);
11082 for(var fnName in Roo.Element.prototype){
11083 if(typeof Roo.Element.prototype[fnName] == "function"){
11084 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11090 * Ext JS Library 1.1.1
11091 * Copyright(c) 2006-2007, Ext JS, LLC.
11093 * Originally Released Under LGPL - original licence link has changed is not relivant.
11096 * <script type="text/javascript">
11100 * @class Roo.CompositeElementLite
11101 * @extends Roo.CompositeElement
11102 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11104 var els = Roo.select("#some-el div.some-class");
11105 // or select directly from an existing element
11106 var el = Roo.get('some-el');
11107 el.select('div.some-class');
11109 els.setWidth(100); // all elements become 100 width
11110 els.hide(true); // all elements fade out and hide
11112 els.setWidth(100).hide(true);
11113 </code></pre><br><br>
11114 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11115 * actions will be performed on all the elements in this collection.</b>
11117 Roo.CompositeElementLite = function(els){
11118 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11119 this.el = new Roo.Element.Flyweight();
11121 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11122 addElements : function(els){
11124 if(els instanceof Array){
11125 this.elements = this.elements.concat(els);
11127 var yels = this.elements;
11128 var index = yels.length-1;
11129 for(var i = 0, len = els.length; i < len; i++) {
11130 yels[++index] = els[i];
11136 invoke : function(fn, args){
11137 var els = this.elements;
11139 for(var i = 0, len = els.length; i < len; i++) {
11141 Roo.Element.prototype[fn].apply(el, args);
11146 * Returns a flyweight Element of the dom element object at the specified index
11147 * @param {Number} index
11148 * @return {Roo.Element}
11150 item : function(index){
11151 if(!this.elements[index]){
11154 this.el.dom = this.elements[index];
11158 // fixes scope with flyweight
11159 addListener : function(eventName, handler, scope, opt){
11160 var els = this.elements;
11161 for(var i = 0, len = els.length; i < len; i++) {
11162 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11168 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11169 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11170 * a reference to the dom node, use el.dom.</b>
11171 * @param {Function} fn The function to call
11172 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11173 * @return {CompositeElement} this
11175 each : function(fn, scope){
11176 var els = this.elements;
11178 for(var i = 0, len = els.length; i < len; i++){
11180 if(fn.call(scope || el, el, this, i) === false){
11187 indexOf : function(el){
11188 return this.elements.indexOf(Roo.getDom(el));
11191 replaceElement : function(el, replacement, domReplace){
11192 var index = typeof el == 'number' ? el : this.indexOf(el);
11194 replacement = Roo.getDom(replacement);
11196 var d = this.elements[index];
11197 d.parentNode.insertBefore(replacement, d);
11198 d.parentNode.removeChild(d);
11200 this.elements.splice(index, 1, replacement);
11205 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11209 * Ext JS Library 1.1.1
11210 * Copyright(c) 2006-2007, Ext JS, LLC.
11212 * Originally Released Under LGPL - original licence link has changed is not relivant.
11215 * <script type="text/javascript">
11221 * @class Roo.data.Connection
11222 * @extends Roo.util.Observable
11223 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11224 * either to a configured URL, or to a URL specified at request time.<br><br>
11226 * Requests made by this class are asynchronous, and will return immediately. No data from
11227 * the server will be available to the statement immediately following the {@link #request} call.
11228 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11230 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11231 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11232 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11233 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11234 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11235 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11236 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11237 * standard DOM methods.
11239 * @param {Object} config a configuration object.
11241 Roo.data.Connection = function(config){
11242 Roo.apply(this, config);
11245 * @event beforerequest
11246 * Fires before a network request is made to retrieve a data object.
11247 * @param {Connection} conn This Connection object.
11248 * @param {Object} options The options config object passed to the {@link #request} method.
11250 "beforerequest" : true,
11252 * @event requestcomplete
11253 * Fires if the request was successfully completed.
11254 * @param {Connection} conn This Connection object.
11255 * @param {Object} response The XHR object containing the response data.
11256 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11257 * @param {Object} options The options config object passed to the {@link #request} method.
11259 "requestcomplete" : true,
11261 * @event requestexception
11262 * Fires if an error HTTP status was returned from the server.
11263 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11264 * @param {Connection} conn This Connection object.
11265 * @param {Object} response The XHR object containing the response data.
11266 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11267 * @param {Object} options The options config object passed to the {@link #request} method.
11269 "requestexception" : true
11271 Roo.data.Connection.superclass.constructor.call(this);
11274 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11276 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11279 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11280 * extra parameters to each request made by this object. (defaults to undefined)
11283 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11284 * to each request made by this object. (defaults to undefined)
11287 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11290 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11294 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11300 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11303 disableCaching: true,
11306 * Sends an HTTP request to a remote server.
11307 * @param {Object} options An object which may contain the following properties:<ul>
11308 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11309 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11310 * request, a url encoded string or a function to call to get either.</li>
11311 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11312 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11313 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11314 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11315 * <li>options {Object} The parameter to the request call.</li>
11316 * <li>success {Boolean} True if the request succeeded.</li>
11317 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11319 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11320 * The callback is passed the following parameters:<ul>
11321 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11322 * <li>options {Object} The parameter to the request call.</li>
11324 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11325 * The callback is passed the following parameters:<ul>
11326 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11327 * <li>options {Object} The parameter to the request call.</li>
11329 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11330 * for the callback function. Defaults to the browser window.</li>
11331 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11332 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11333 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11334 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11335 * params for the post data. Any params will be appended to the URL.</li>
11336 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11338 * @return {Number} transactionId
11340 request : function(o){
11341 if(this.fireEvent("beforerequest", this, o) !== false){
11344 if(typeof p == "function"){
11345 p = p.call(o.scope||window, o);
11347 if(typeof p == "object"){
11348 p = Roo.urlEncode(o.params);
11350 if(this.extraParams){
11351 var extras = Roo.urlEncode(this.extraParams);
11352 p = p ? (p + '&' + extras) : extras;
11355 var url = o.url || this.url;
11356 if(typeof url == 'function'){
11357 url = url.call(o.scope||window, o);
11361 var form = Roo.getDom(o.form);
11362 url = url || form.action;
11364 var enctype = form.getAttribute("enctype");
11365 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11366 return this.doFormUpload(o, p, url);
11368 var f = Roo.lib.Ajax.serializeForm(form);
11369 p = p ? (p + '&' + f) : f;
11372 var hs = o.headers;
11373 if(this.defaultHeaders){
11374 hs = Roo.apply(hs || {}, this.defaultHeaders);
11381 success: this.handleResponse,
11382 failure: this.handleFailure,
11384 argument: {options: o},
11385 timeout : this.timeout
11388 var method = o.method||this.method||(p ? "POST" : "GET");
11390 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11391 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11394 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11398 }else if(this.autoAbort !== false){
11402 if((method == 'GET' && p) || o.xmlData){
11403 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11406 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11407 return this.transId;
11409 Roo.callback(o.callback, o.scope, [o, null, null]);
11415 * Determine whether this object has a request outstanding.
11416 * @param {Number} transactionId (Optional) defaults to the last transaction
11417 * @return {Boolean} True if there is an outstanding request.
11419 isLoading : function(transId){
11421 return Roo.lib.Ajax.isCallInProgress(transId);
11423 return this.transId ? true : false;
11428 * Aborts any outstanding request.
11429 * @param {Number} transactionId (Optional) defaults to the last transaction
11431 abort : function(transId){
11432 if(transId || this.isLoading()){
11433 Roo.lib.Ajax.abort(transId || this.transId);
11438 handleResponse : function(response){
11439 this.transId = false;
11440 var options = response.argument.options;
11441 response.argument = options ? options.argument : null;
11442 this.fireEvent("requestcomplete", this, response, options);
11443 Roo.callback(options.success, options.scope, [response, options]);
11444 Roo.callback(options.callback, options.scope, [options, true, response]);
11448 handleFailure : function(response, e){
11449 this.transId = false;
11450 var options = response.argument.options;
11451 response.argument = options ? options.argument : null;
11452 this.fireEvent("requestexception", this, response, options, e);
11453 Roo.callback(options.failure, options.scope, [response, options]);
11454 Roo.callback(options.callback, options.scope, [options, false, response]);
11458 doFormUpload : function(o, ps, url){
11460 var frame = document.createElement('iframe');
11463 frame.className = 'x-hidden';
11465 frame.src = Roo.SSL_SECURE_URL;
11467 document.body.appendChild(frame);
11470 document.frames[id].name = id;
11473 var form = Roo.getDom(o.form);
11475 form.method = 'POST';
11476 form.enctype = form.encoding = 'multipart/form-data';
11482 if(ps){ // add dynamic params
11484 ps = Roo.urlDecode(ps, false);
11486 if(ps.hasOwnProperty(k)){
11487 hd = document.createElement('input');
11488 hd.type = 'hidden';
11491 form.appendChild(hd);
11498 var r = { // bogus response object
11503 r.argument = o ? o.argument : null;
11508 doc = frame.contentWindow.document;
11510 doc = (frame.contentDocument || window.frames[id].document);
11512 if(doc && doc.body){
11513 r.responseText = doc.body.innerHTML;
11515 if(doc && doc.XMLDocument){
11516 r.responseXML = doc.XMLDocument;
11518 r.responseXML = doc;
11525 Roo.EventManager.removeListener(frame, 'load', cb, this);
11527 this.fireEvent("requestcomplete", this, r, o);
11528 Roo.callback(o.success, o.scope, [r, o]);
11529 Roo.callback(o.callback, o.scope, [o, true, r]);
11531 setTimeout(function(){document.body.removeChild(frame);}, 100);
11534 Roo.EventManager.on(frame, 'load', cb, this);
11537 if(hiddens){ // remove dynamic params
11538 for(var i = 0, len = hiddens.length; i < len; i++){
11539 form.removeChild(hiddens[i]);
11547 * @extends Roo.data.Connection
11548 * Global Ajax request class.
11552 Roo.Ajax = new Roo.data.Connection({
11555 * @cfg {String} url @hide
11558 * @cfg {Object} extraParams @hide
11561 * @cfg {Object} defaultHeaders @hide
11564 * @cfg {String} method (Optional) @hide
11567 * @cfg {Number} timeout (Optional) @hide
11570 * @cfg {Boolean} autoAbort (Optional) @hide
11574 * @cfg {Boolean} disableCaching (Optional) @hide
11578 * @property disableCaching
11579 * True to add a unique cache-buster param to GET requests. (defaults to true)
11584 * The default URL to be used for requests to the server. (defaults to undefined)
11588 * @property extraParams
11589 * An object containing properties which are used as
11590 * extra parameters to each request made by this object. (defaults to undefined)
11594 * @property defaultHeaders
11595 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11600 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11604 * @property timeout
11605 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11610 * @property autoAbort
11611 * Whether a new request should abort any pending requests. (defaults to false)
11617 * Serialize the passed form into a url encoded string
11618 * @param {String/HTMLElement} form
11621 serializeForm : function(form){
11622 return Roo.lib.Ajax.serializeForm(form);
11626 * Ext JS Library 1.1.1
11627 * Copyright(c) 2006-2007, Ext JS, LLC.
11629 * Originally Released Under LGPL - original licence link has changed is not relivant.
11632 * <script type="text/javascript">
11636 * Global Ajax request class.
11639 * @extends Roo.data.Connection
11642 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11643 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11644 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11645 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11646 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11647 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11648 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11650 Roo.Ajax = new Roo.data.Connection({
11659 * Serialize the passed form into a url encoded string
11661 * @param {String/HTMLElement} form
11664 serializeForm : function(form){
11665 return Roo.lib.Ajax.serializeForm(form);
11669 * Ext JS Library 1.1.1
11670 * Copyright(c) 2006-2007, Ext JS, LLC.
11672 * Originally Released Under LGPL - original licence link has changed is not relivant.
11675 * <script type="text/javascript">
11680 * @class Roo.UpdateManager
11681 * @extends Roo.util.Observable
11682 * Provides AJAX-style update for Element object.<br><br>
11685 * // Get it from a Roo.Element object
11686 * var el = Roo.get("foo");
11687 * var mgr = el.getUpdateManager();
11688 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11690 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11692 * // or directly (returns the same UpdateManager instance)
11693 * var mgr = new Roo.UpdateManager("myElementId");
11694 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11695 * mgr.on("update", myFcnNeedsToKnow);
11697 // short handed call directly from the element object
11698 Roo.get("foo").load({
11702 text: "Loading Foo..."
11706 * Create new UpdateManager directly.
11707 * @param {String/HTMLElement/Roo.Element} el The element to update
11708 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11710 Roo.UpdateManager = function(el, forceNew){
11712 if(!forceNew && el.updateManager){
11713 return el.updateManager;
11716 * The Element object
11717 * @type Roo.Element
11721 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11724 this.defaultUrl = null;
11728 * @event beforeupdate
11729 * Fired before an update is made, return false from your handler and the update is cancelled.
11730 * @param {Roo.Element} el
11731 * @param {String/Object/Function} url
11732 * @param {String/Object} params
11734 "beforeupdate": true,
11737 * Fired after successful update is made.
11738 * @param {Roo.Element} el
11739 * @param {Object} oResponseObject The response Object
11744 * Fired on update failure.
11745 * @param {Roo.Element} el
11746 * @param {Object} oResponseObject The response Object
11750 var d = Roo.UpdateManager.defaults;
11752 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11755 this.sslBlankUrl = d.sslBlankUrl;
11757 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11760 this.disableCaching = d.disableCaching;
11762 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11765 this.indicatorText = d.indicatorText;
11767 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11770 this.showLoadIndicator = d.showLoadIndicator;
11772 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11775 this.timeout = d.timeout;
11778 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11781 this.loadScripts = d.loadScripts;
11784 * Transaction object of current executing transaction
11786 this.transaction = null;
11791 this.autoRefreshProcId = null;
11793 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11796 this.refreshDelegate = this.refresh.createDelegate(this);
11798 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11801 this.updateDelegate = this.update.createDelegate(this);
11803 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11806 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11810 this.successDelegate = this.processSuccess.createDelegate(this);
11814 this.failureDelegate = this.processFailure.createDelegate(this);
11816 if(!this.renderer){
11818 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11820 this.renderer = new Roo.UpdateManager.BasicRenderer();
11823 Roo.UpdateManager.superclass.constructor.call(this);
11826 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11828 * Get the Element this UpdateManager is bound to
11829 * @return {Roo.Element} The element
11831 getEl : function(){
11835 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11836 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11839 url: "your-url.php",<br/>
11840 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11841 callback: yourFunction,<br/>
11842 scope: yourObject, //(optional scope) <br/>
11843 discardUrl: false, <br/>
11844 nocache: false,<br/>
11845 text: "Loading...",<br/>
11847 scripts: false<br/>
11850 * The only required property is url. The optional properties nocache, text and scripts
11851 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11852 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11853 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11854 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11856 update : function(url, params, callback, discardUrl){
11857 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11858 var method = this.method, cfg;
11859 if(typeof url == "object"){ // must be config object
11862 params = params || cfg.params;
11863 callback = callback || cfg.callback;
11864 discardUrl = discardUrl || cfg.discardUrl;
11865 if(callback && cfg.scope){
11866 callback = callback.createDelegate(cfg.scope);
11868 if(typeof cfg.method != "undefined"){method = cfg.method;};
11869 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11870 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11871 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11872 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11874 this.showLoading();
11876 this.defaultUrl = url;
11878 if(typeof url == "function"){
11879 url = url.call(this);
11882 method = method || (params ? "POST" : "GET");
11883 if(method == "GET"){
11884 url = this.prepareUrl(url);
11887 var o = Roo.apply(cfg ||{}, {
11890 success: this.successDelegate,
11891 failure: this.failureDelegate,
11892 callback: undefined,
11893 timeout: (this.timeout*1000),
11894 argument: {"url": url, "form": null, "callback": callback, "params": params}
11897 this.transaction = Roo.Ajax.request(o);
11902 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11903 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11904 * @param {String/HTMLElement} form The form Id or form element
11905 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11906 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11907 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11909 formUpdate : function(form, url, reset, callback){
11910 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11911 if(typeof url == "function"){
11912 url = url.call(this);
11914 form = Roo.getDom(form);
11915 this.transaction = Roo.Ajax.request({
11918 success: this.successDelegate,
11919 failure: this.failureDelegate,
11920 timeout: (this.timeout*1000),
11921 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11923 this.showLoading.defer(1, this);
11928 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11929 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11931 refresh : function(callback){
11932 if(this.defaultUrl == null){
11935 this.update(this.defaultUrl, null, callback, true);
11939 * Set this element to auto refresh.
11940 * @param {Number} interval How often to update (in seconds).
11941 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11942 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11943 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11944 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11946 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11948 this.update(url || this.defaultUrl, params, callback, true);
11950 if(this.autoRefreshProcId){
11951 clearInterval(this.autoRefreshProcId);
11953 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11957 * Stop auto refresh on this element.
11959 stopAutoRefresh : function(){
11960 if(this.autoRefreshProcId){
11961 clearInterval(this.autoRefreshProcId);
11962 delete this.autoRefreshProcId;
11966 isAutoRefreshing : function(){
11967 return this.autoRefreshProcId ? true : false;
11970 * Called to update the element to "Loading" state. Override to perform custom action.
11972 showLoading : function(){
11973 if(this.showLoadIndicator){
11974 this.el.update(this.indicatorText);
11979 * Adds unique parameter to query string if disableCaching = true
11982 prepareUrl : function(url){
11983 if(this.disableCaching){
11984 var append = "_dc=" + (new Date().getTime());
11985 if(url.indexOf("?") !== -1){
11986 url += "&" + append;
11988 url += "?" + append;
11997 processSuccess : function(response){
11998 this.transaction = null;
11999 if(response.argument.form && response.argument.reset){
12000 try{ // put in try/catch since some older FF releases had problems with this
12001 response.argument.form.reset();
12004 if(this.loadScripts){
12005 this.renderer.render(this.el, response, this,
12006 this.updateComplete.createDelegate(this, [response]));
12008 this.renderer.render(this.el, response, this);
12009 this.updateComplete(response);
12013 updateComplete : function(response){
12014 this.fireEvent("update", this.el, response);
12015 if(typeof response.argument.callback == "function"){
12016 response.argument.callback(this.el, true, response);
12023 processFailure : function(response){
12024 this.transaction = null;
12025 this.fireEvent("failure", this.el, response);
12026 if(typeof response.argument.callback == "function"){
12027 response.argument.callback(this.el, false, response);
12032 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12033 * @param {Object} renderer The object implementing the render() method
12035 setRenderer : function(renderer){
12036 this.renderer = renderer;
12039 getRenderer : function(){
12040 return this.renderer;
12044 * Set the defaultUrl used for updates
12045 * @param {String/Function} defaultUrl The url or a function to call to get the url
12047 setDefaultUrl : function(defaultUrl){
12048 this.defaultUrl = defaultUrl;
12052 * Aborts the executing transaction
12054 abort : function(){
12055 if(this.transaction){
12056 Roo.Ajax.abort(this.transaction);
12061 * Returns true if an update is in progress
12062 * @return {Boolean}
12064 isUpdating : function(){
12065 if(this.transaction){
12066 return Roo.Ajax.isLoading(this.transaction);
12073 * @class Roo.UpdateManager.defaults
12074 * @static (not really - but it helps the doc tool)
12075 * The defaults collection enables customizing the default properties of UpdateManager
12077 Roo.UpdateManager.defaults = {
12079 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12085 * True to process scripts by default (Defaults to false).
12088 loadScripts : false,
12091 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12094 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12096 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12099 disableCaching : false,
12101 * Whether to show indicatorText when loading (Defaults to true).
12104 showLoadIndicator : true,
12106 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12109 indicatorText : '<div class="loading-indicator">Loading...</div>'
12113 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12115 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12116 * @param {String/HTMLElement/Roo.Element} el The element to update
12117 * @param {String} url The url
12118 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12119 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12122 * @member Roo.UpdateManager
12124 Roo.UpdateManager.updateElement = function(el, url, params, options){
12125 var um = Roo.get(el, true).getUpdateManager();
12126 Roo.apply(um, options);
12127 um.update(url, params, options ? options.callback : null);
12129 // alias for backwards compat
12130 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12132 * @class Roo.UpdateManager.BasicRenderer
12133 * Default Content renderer. Updates the elements innerHTML with the responseText.
12135 Roo.UpdateManager.BasicRenderer = function(){};
12137 Roo.UpdateManager.BasicRenderer.prototype = {
12139 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12140 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12141 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12142 * @param {Roo.Element} el The element being rendered
12143 * @param {Object} response The YUI Connect response object
12144 * @param {UpdateManager} updateManager The calling update manager
12145 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12147 render : function(el, response, updateManager, callback){
12148 el.update(response.responseText, updateManager.loadScripts, callback);
12154 * (c)) Alan Knowles
12160 * @class Roo.DomTemplate
12161 * @extends Roo.Template
12162 * An effort at a dom based template engine..
12164 * Similar to XTemplate, except it uses dom parsing to create the template..
12166 * Supported features:
12171 {a_variable} - output encoded.
12172 {a_variable.format:("Y-m-d")} - call a method on the variable
12173 {a_variable:raw} - unencoded output
12174 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12175 {a_variable:this.method_on_template(...)} - call a method on the template object.
12180 <div roo-for="a_variable or condition.."></div>
12181 <div roo-if="a_variable or condition"></div>
12182 <div roo-exec="some javascript"></div>
12183 <div roo-name="named_template"></div>
12188 Roo.DomTemplate = function()
12190 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12197 Roo.extend(Roo.DomTemplate, Roo.Template, {
12199 * id counter for sub templates.
12203 * flag to indicate if dom parser is inside a pre,
12204 * it will strip whitespace if not.
12209 * The various sub templates
12217 * basic tag replacing syntax
12220 * // you can fake an object call by doing this
12224 re : /(\{|%7B])([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\}|%7D)/g,
12225 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12227 iterChild : function (node, method) {
12229 var oldPre = this.inPre;
12230 if (node.tagName == 'PRE') {
12233 for( var i = 0; i < node.childNodes.length; i++) {
12234 method.call(this, node.childNodes[i]);
12236 this.inPre = oldPre;
12242 * compile the template
12244 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12247 compile: function()
12251 // covert the html into DOM...
12253 var div = document.createElement('div');
12254 div.innerHTML = this.html ;
12258 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12260 var tpls = this.tpls;
12262 // create a top level template from the snippet..
12264 Roo.log(div.innerHTML);
12271 body : div.innerHTML,
12284 Roo.each(tpls, function(tp){
12285 this.compileTpl(tp);
12286 this.tpls[tp.id] = tp;
12289 this.master = tpls[0];
12295 compileNode : function(node, istop) {
12300 // skip anything not a tag..
12301 if (node.nodeType != 1) {
12302 if (node.nodeType == 3 && !this.inPre) {
12303 // reduce white space..
12304 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12327 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12328 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12329 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12330 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12336 // just itterate children..
12337 this.iterChild(node,this.compileNode);
12340 tpl.uid = this.id++;
12341 tpl.value = node.getAttribute('roo-' + tpl.attr);
12342 node.removeAttribute('roo-'+ tpl.attr);
12343 if (tpl.attr != 'name') {
12344 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12345 node.parentNode.replaceChild(placeholder, node);
12348 var placeholder = document.createElement('span');
12349 placeholder.className = 'roo-tpl-' + tpl.value;
12350 node.parentNode.replaceChild(placeholder, node);
12353 // parent now sees '{domtplXXXX}
12354 this.iterChild(node,this.compileNode);
12356 // we should now have node body...
12357 var div = document.createElement('div');
12358 div.appendChild(node);
12360 // this has the unfortunate side effect of converting tagged attributes
12361 // eg. href="{...}" into %7C...%7D
12362 // this has been fixed by searching for those combo's although it's a bit hacky..
12365 tpl.body = div.innerHTML;
12372 switch (tpl.value) {
12373 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12374 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12375 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12380 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12384 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12388 tpl.id = tpl.value; // replace non characters???
12394 this.tpls.push(tpl);
12404 * Compile a segment of the template into a 'sub-template'
12410 compileTpl : function(tpl)
12412 var fm = Roo.util.Format;
12413 var useF = this.disableFormats !== true;
12415 var sep = Roo.isGecko ? "+\n" : ",\n";
12417 var undef = function(str) {
12418 Roo.log("Property not found :" + str);
12423 var fn = function(m, lbrace, name, format, args)
12426 //Roo.log(arguments);
12427 args = args ? args.replace(/\\'/g,"'") : args;
12428 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12429 if (typeof(format) == 'undefined') {
12430 format = 'htmlEncode';
12432 if (format == 'raw' ) {
12436 if(name.substr(0, 6) == 'domtpl'){
12437 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12440 // build an array of options to determine if value is undefined..
12442 // basically get 'xxxx.yyyy' then do
12443 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12444 // (function () { Roo.log("Property not found"); return ''; })() :
12449 Roo.each(name.split('.'), function(st) {
12450 lookfor += (lookfor.length ? '.': '') + st;
12451 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12454 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12457 if(format && useF){
12459 args = args ? ',' + args : "";
12461 if(format.substr(0, 5) != "this."){
12462 format = "fm." + format + '(';
12464 format = 'this.call("'+ format.substr(5) + '", ';
12468 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12472 // called with xxyx.yuu:(test,test)
12474 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12476 // raw.. - :raw modifier..
12477 return "'"+ sep + udef_st + name + ")"+sep+"'";
12481 // branched to use + in gecko and [].join() in others
12483 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12484 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12487 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12488 body.push(tpl.body.replace(/(\r\n|\n)/g,
12489 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12490 body.push("'].join('');};};");
12491 body = body.join('');
12494 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12496 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12503 * same as applyTemplate, except it's done to one of the subTemplates
12504 * when using named templates, you can do:
12506 * var str = pl.applySubTemplate('your-name', values);
12509 * @param {Number} id of the template
12510 * @param {Object} values to apply to template
12511 * @param {Object} parent (normaly the instance of this object)
12513 applySubTemplate : function(id, values, parent)
12517 var t = this.tpls[id];
12521 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12522 Roo.log('if call on ' + t.value + ' return false');
12526 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12533 if(t.execCall && t.execCall.call(this, values, parent)){
12537 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12543 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12544 parent = t.target ? values : parent;
12545 if(t.forCall && vs instanceof Array){
12547 for(var i = 0, len = vs.length; i < len; i++){
12549 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12551 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12553 //Roo.log(t.compiled);
12557 return buf.join('');
12560 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12565 return t.compiled.call(this, vs, parent);
12567 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12569 //Roo.log(t.compiled);
12577 applyTemplate : function(values){
12578 return this.master.compiled.call(this, values, {});
12579 //var s = this.subs;
12582 apply : function(){
12583 return this.applyTemplate.apply(this, arguments);
12588 Roo.DomTemplate.from = function(el){
12589 el = Roo.getDom(el);
12590 return new Roo.Domtemplate(el.value || el.innerHTML);
12593 * Ext JS Library 1.1.1
12594 * Copyright(c) 2006-2007, Ext JS, LLC.
12596 * Originally Released Under LGPL - original licence link has changed is not relivant.
12599 * <script type="text/javascript">
12603 * @class Roo.util.DelayedTask
12604 * Provides a convenient method of performing setTimeout where a new
12605 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12606 * You can use this class to buffer
12607 * the keypress events for a certain number of milliseconds, and perform only if they stop
12608 * for that amount of time.
12609 * @constructor The parameters to this constructor serve as defaults and are not required.
12610 * @param {Function} fn (optional) The default function to timeout
12611 * @param {Object} scope (optional) The default scope of that timeout
12612 * @param {Array} args (optional) The default Array of arguments
12614 Roo.util.DelayedTask = function(fn, scope, args){
12615 var id = null, d, t;
12617 var call = function(){
12618 var now = new Date().getTime();
12622 fn.apply(scope, args || []);
12626 * Cancels any pending timeout and queues a new one
12627 * @param {Number} delay The milliseconds to delay
12628 * @param {Function} newFn (optional) Overrides function passed to constructor
12629 * @param {Object} newScope (optional) Overrides scope passed to constructor
12630 * @param {Array} newArgs (optional) Overrides args passed to constructor
12632 this.delay = function(delay, newFn, newScope, newArgs){
12633 if(id && delay != d){
12637 t = new Date().getTime();
12639 scope = newScope || scope;
12640 args = newArgs || args;
12642 id = setInterval(call, d);
12647 * Cancel the last queued timeout
12649 this.cancel = function(){
12657 * Ext JS Library 1.1.1
12658 * Copyright(c) 2006-2007, Ext JS, LLC.
12660 * Originally Released Under LGPL - original licence link has changed is not relivant.
12663 * <script type="text/javascript">
12667 Roo.util.TaskRunner = function(interval){
12668 interval = interval || 10;
12669 var tasks = [], removeQueue = [];
12671 var running = false;
12673 var stopThread = function(){
12679 var startThread = function(){
12682 id = setInterval(runTasks, interval);
12686 var removeTask = function(task){
12687 removeQueue.push(task);
12693 var runTasks = function(){
12694 if(removeQueue.length > 0){
12695 for(var i = 0, len = removeQueue.length; i < len; i++){
12696 tasks.remove(removeQueue[i]);
12699 if(tasks.length < 1){
12704 var now = new Date().getTime();
12705 for(var i = 0, len = tasks.length; i < len; ++i){
12707 var itime = now - t.taskRunTime;
12708 if(t.interval <= itime){
12709 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12710 t.taskRunTime = now;
12711 if(rt === false || t.taskRunCount === t.repeat){
12716 if(t.duration && t.duration <= (now - t.taskStartTime)){
12723 * Queues a new task.
12724 * @param {Object} task
12726 this.start = function(task){
12728 task.taskStartTime = new Date().getTime();
12729 task.taskRunTime = 0;
12730 task.taskRunCount = 0;
12735 this.stop = function(task){
12740 this.stopAll = function(){
12742 for(var i = 0, len = tasks.length; i < len; i++){
12743 if(tasks[i].onStop){
12752 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12754 * Ext JS Library 1.1.1
12755 * Copyright(c) 2006-2007, Ext JS, LLC.
12757 * Originally Released Under LGPL - original licence link has changed is not relivant.
12760 * <script type="text/javascript">
12765 * @class Roo.util.MixedCollection
12766 * @extends Roo.util.Observable
12767 * A Collection class that maintains both numeric indexes and keys and exposes events.
12769 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12770 * collection (defaults to false)
12771 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12772 * and return the key value for that item. This is used when available to look up the key on items that
12773 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12774 * equivalent to providing an implementation for the {@link #getKey} method.
12776 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12784 * Fires when the collection is cleared.
12789 * Fires when an item is added to the collection.
12790 * @param {Number} index The index at which the item was added.
12791 * @param {Object} o The item added.
12792 * @param {String} key The key associated with the added item.
12797 * Fires when an item is replaced in the collection.
12798 * @param {String} key he key associated with the new added.
12799 * @param {Object} old The item being replaced.
12800 * @param {Object} new The new item.
12805 * Fires when an item is removed from the collection.
12806 * @param {Object} o The item being removed.
12807 * @param {String} key (optional) The key associated with the removed item.
12812 this.allowFunctions = allowFunctions === true;
12814 this.getKey = keyFn;
12816 Roo.util.MixedCollection.superclass.constructor.call(this);
12819 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12820 allowFunctions : false,
12823 * Adds an item to the collection.
12824 * @param {String} key The key to associate with the item
12825 * @param {Object} o The item to add.
12826 * @return {Object} The item added.
12828 add : function(key, o){
12829 if(arguments.length == 1){
12831 key = this.getKey(o);
12833 if(typeof key == "undefined" || key === null){
12835 this.items.push(o);
12836 this.keys.push(null);
12838 var old = this.map[key];
12840 return this.replace(key, o);
12843 this.items.push(o);
12845 this.keys.push(key);
12847 this.fireEvent("add", this.length-1, o, key);
12852 * MixedCollection has a generic way to fetch keys if you implement getKey.
12855 var mc = new Roo.util.MixedCollection();
12856 mc.add(someEl.dom.id, someEl);
12857 mc.add(otherEl.dom.id, otherEl);
12861 var mc = new Roo.util.MixedCollection();
12862 mc.getKey = function(el){
12868 // or via the constructor
12869 var mc = new Roo.util.MixedCollection(false, function(el){
12875 * @param o {Object} The item for which to find the key.
12876 * @return {Object} The key for the passed item.
12878 getKey : function(o){
12883 * Replaces an item in the collection.
12884 * @param {String} key The key associated with the item to replace, or the item to replace.
12885 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12886 * @return {Object} The new item.
12888 replace : function(key, o){
12889 if(arguments.length == 1){
12891 key = this.getKey(o);
12893 var old = this.item(key);
12894 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12895 return this.add(key, o);
12897 var index = this.indexOfKey(key);
12898 this.items[index] = o;
12900 this.fireEvent("replace", key, old, o);
12905 * Adds all elements of an Array or an Object to the collection.
12906 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12907 * an Array of values, each of which are added to the collection.
12909 addAll : function(objs){
12910 if(arguments.length > 1 || objs instanceof Array){
12911 var args = arguments.length > 1 ? arguments : objs;
12912 for(var i = 0, len = args.length; i < len; i++){
12916 for(var key in objs){
12917 if(this.allowFunctions || typeof objs[key] != "function"){
12918 this.add(key, objs[key]);
12925 * Executes the specified function once for every item in the collection, passing each
12926 * item as the first and only parameter. returning false from the function will stop the iteration.
12927 * @param {Function} fn The function to execute for each item.
12928 * @param {Object} scope (optional) The scope in which to execute the function.
12930 each : function(fn, scope){
12931 var items = [].concat(this.items); // each safe for removal
12932 for(var i = 0, len = items.length; i < len; i++){
12933 if(fn.call(scope || items[i], items[i], i, len) === false){
12940 * Executes the specified function once for every key in the collection, passing each
12941 * key, and its associated item as the first two parameters.
12942 * @param {Function} fn The function to execute for each item.
12943 * @param {Object} scope (optional) The scope in which to execute the function.
12945 eachKey : function(fn, scope){
12946 for(var i = 0, len = this.keys.length; i < len; i++){
12947 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12952 * Returns the first item in the collection which elicits a true return value from the
12953 * passed selection function.
12954 * @param {Function} fn The selection function to execute for each item.
12955 * @param {Object} scope (optional) The scope in which to execute the function.
12956 * @return {Object} The first item in the collection which returned true from the selection function.
12958 find : function(fn, scope){
12959 for(var i = 0, len = this.items.length; i < len; i++){
12960 if(fn.call(scope || window, this.items[i], this.keys[i])){
12961 return this.items[i];
12968 * Inserts an item at the specified index in the collection.
12969 * @param {Number} index The index to insert the item at.
12970 * @param {String} key The key to associate with the new item, or the item itself.
12971 * @param {Object} o (optional) If the second parameter was a key, the new item.
12972 * @return {Object} The item inserted.
12974 insert : function(index, key, o){
12975 if(arguments.length == 2){
12977 key = this.getKey(o);
12979 if(index >= this.length){
12980 return this.add(key, o);
12983 this.items.splice(index, 0, o);
12984 if(typeof key != "undefined" && key != null){
12987 this.keys.splice(index, 0, key);
12988 this.fireEvent("add", index, o, key);
12993 * Removed an item from the collection.
12994 * @param {Object} o The item to remove.
12995 * @return {Object} The item removed.
12997 remove : function(o){
12998 return this.removeAt(this.indexOf(o));
13002 * Remove an item from a specified index in the collection.
13003 * @param {Number} index The index within the collection of the item to remove.
13005 removeAt : function(index){
13006 if(index < this.length && index >= 0){
13008 var o = this.items[index];
13009 this.items.splice(index, 1);
13010 var key = this.keys[index];
13011 if(typeof key != "undefined"){
13012 delete this.map[key];
13014 this.keys.splice(index, 1);
13015 this.fireEvent("remove", o, key);
13020 * Removed an item associated with the passed key fom the collection.
13021 * @param {String} key The key of the item to remove.
13023 removeKey : function(key){
13024 return this.removeAt(this.indexOfKey(key));
13028 * Returns the number of items in the collection.
13029 * @return {Number} the number of items in the collection.
13031 getCount : function(){
13032 return this.length;
13036 * Returns index within the collection of the passed Object.
13037 * @param {Object} o The item to find the index of.
13038 * @return {Number} index of the item.
13040 indexOf : function(o){
13041 if(!this.items.indexOf){
13042 for(var i = 0, len = this.items.length; i < len; i++){
13043 if(this.items[i] == o) return i;
13047 return this.items.indexOf(o);
13052 * Returns index within the collection of the passed key.
13053 * @param {String} key The key to find the index of.
13054 * @return {Number} index of the key.
13056 indexOfKey : function(key){
13057 if(!this.keys.indexOf){
13058 for(var i = 0, len = this.keys.length; i < len; i++){
13059 if(this.keys[i] == key) return i;
13063 return this.keys.indexOf(key);
13068 * Returns the item associated with the passed key OR index. Key has priority over index.
13069 * @param {String/Number} key The key or index of the item.
13070 * @return {Object} The item associated with the passed key.
13072 item : function(key){
13073 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13074 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13078 * Returns the item at the specified index.
13079 * @param {Number} index The index of the item.
13082 itemAt : function(index){
13083 return this.items[index];
13087 * Returns the item associated with the passed key.
13088 * @param {String/Number} key The key of the item.
13089 * @return {Object} The item associated with the passed key.
13091 key : function(key){
13092 return this.map[key];
13096 * Returns true if the collection contains the passed Object as an item.
13097 * @param {Object} o The Object to look for in the collection.
13098 * @return {Boolean} True if the collection contains the Object as an item.
13100 contains : function(o){
13101 return this.indexOf(o) != -1;
13105 * Returns true if the collection contains the passed Object as a key.
13106 * @param {String} key The key to look for in the collection.
13107 * @return {Boolean} True if the collection contains the Object as a key.
13109 containsKey : function(key){
13110 return typeof this.map[key] != "undefined";
13114 * Removes all items from the collection.
13116 clear : function(){
13121 this.fireEvent("clear");
13125 * Returns the first item in the collection.
13126 * @return {Object} the first item in the collection..
13128 first : function(){
13129 return this.items[0];
13133 * Returns the last item in the collection.
13134 * @return {Object} the last item in the collection..
13137 return this.items[this.length-1];
13140 _sort : function(property, dir, fn){
13141 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13142 fn = fn || function(a, b){
13145 var c = [], k = this.keys, items = this.items;
13146 for(var i = 0, len = items.length; i < len; i++){
13147 c[c.length] = {key: k[i], value: items[i], index: i};
13149 c.sort(function(a, b){
13150 var v = fn(a[property], b[property]) * dsc;
13152 v = (a.index < b.index ? -1 : 1);
13156 for(var i = 0, len = c.length; i < len; i++){
13157 items[i] = c[i].value;
13160 this.fireEvent("sort", this);
13164 * Sorts this collection with the passed comparison function
13165 * @param {String} direction (optional) "ASC" or "DESC"
13166 * @param {Function} fn (optional) comparison function
13168 sort : function(dir, fn){
13169 this._sort("value", dir, fn);
13173 * Sorts this collection by keys
13174 * @param {String} direction (optional) "ASC" or "DESC"
13175 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13177 keySort : function(dir, fn){
13178 this._sort("key", dir, fn || function(a, b){
13179 return String(a).toUpperCase()-String(b).toUpperCase();
13184 * Returns a range of items in this collection
13185 * @param {Number} startIndex (optional) defaults to 0
13186 * @param {Number} endIndex (optional) default to the last item
13187 * @return {Array} An array of items
13189 getRange : function(start, end){
13190 var items = this.items;
13191 if(items.length < 1){
13194 start = start || 0;
13195 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13198 for(var i = start; i <= end; i++) {
13199 r[r.length] = items[i];
13202 for(var i = start; i >= end; i--) {
13203 r[r.length] = items[i];
13210 * Filter the <i>objects</i> in this collection by a specific property.
13211 * Returns a new collection that has been filtered.
13212 * @param {String} property A property on your objects
13213 * @param {String/RegExp} value Either string that the property values
13214 * should start with or a RegExp to test against the property
13215 * @return {MixedCollection} The new filtered collection
13217 filter : function(property, value){
13218 if(!value.exec){ // not a regex
13219 value = String(value);
13220 if(value.length == 0){
13221 return this.clone();
13223 value = new RegExp("^" + Roo.escapeRe(value), "i");
13225 return this.filterBy(function(o){
13226 return o && value.test(o[property]);
13231 * Filter by a function. * Returns a new collection that has been filtered.
13232 * The passed function will be called with each
13233 * object in the collection. If the function returns true, the value is included
13234 * otherwise it is filtered.
13235 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13236 * @param {Object} scope (optional) The scope of the function (defaults to this)
13237 * @return {MixedCollection} The new filtered collection
13239 filterBy : function(fn, scope){
13240 var r = new Roo.util.MixedCollection();
13241 r.getKey = this.getKey;
13242 var k = this.keys, it = this.items;
13243 for(var i = 0, len = it.length; i < len; i++){
13244 if(fn.call(scope||this, it[i], k[i])){
13245 r.add(k[i], it[i]);
13252 * Creates a duplicate of this collection
13253 * @return {MixedCollection}
13255 clone : function(){
13256 var r = new Roo.util.MixedCollection();
13257 var k = this.keys, it = this.items;
13258 for(var i = 0, len = it.length; i < len; i++){
13259 r.add(k[i], it[i]);
13261 r.getKey = this.getKey;
13266 * Returns the item associated with the passed key or index.
13268 * @param {String/Number} key The key or index of the item.
13269 * @return {Object} The item associated with the passed key.
13271 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13273 * Ext JS Library 1.1.1
13274 * Copyright(c) 2006-2007, Ext JS, LLC.
13276 * Originally Released Under LGPL - original licence link has changed is not relivant.
13279 * <script type="text/javascript">
13282 * @class Roo.util.JSON
13283 * Modified version of Douglas Crockford"s json.js that doesn"t
13284 * mess with the Object prototype
13285 * http://www.json.org/js.html
13288 Roo.util.JSON = new (function(){
13289 var useHasOwn = {}.hasOwnProperty ? true : false;
13291 // crashes Safari in some instances
13292 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13294 var pad = function(n) {
13295 return n < 10 ? "0" + n : n;
13308 var encodeString = function(s){
13309 if (/["\\\x00-\x1f]/.test(s)) {
13310 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13315 c = b.charCodeAt();
13317 Math.floor(c / 16).toString(16) +
13318 (c % 16).toString(16);
13321 return '"' + s + '"';
13324 var encodeArray = function(o){
13325 var a = ["["], b, i, l = o.length, v;
13326 for (i = 0; i < l; i += 1) {
13328 switch (typeof v) {
13337 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13345 var encodeDate = function(o){
13346 return '"' + o.getFullYear() + "-" +
13347 pad(o.getMonth() + 1) + "-" +
13348 pad(o.getDate()) + "T" +
13349 pad(o.getHours()) + ":" +
13350 pad(o.getMinutes()) + ":" +
13351 pad(o.getSeconds()) + '"';
13355 * Encodes an Object, Array or other value
13356 * @param {Mixed} o The variable to encode
13357 * @return {String} The JSON string
13359 this.encode = function(o)
13361 // should this be extended to fully wrap stringify..
13363 if(typeof o == "undefined" || o === null){
13365 }else if(o instanceof Array){
13366 return encodeArray(o);
13367 }else if(o instanceof Date){
13368 return encodeDate(o);
13369 }else if(typeof o == "string"){
13370 return encodeString(o);
13371 }else if(typeof o == "number"){
13372 return isFinite(o) ? String(o) : "null";
13373 }else if(typeof o == "boolean"){
13376 var a = ["{"], b, i, v;
13378 if(!useHasOwn || o.hasOwnProperty(i)) {
13380 switch (typeof v) {
13389 a.push(this.encode(i), ":",
13390 v === null ? "null" : this.encode(v));
13401 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13402 * @param {String} json The JSON string
13403 * @return {Object} The resulting object
13405 this.decode = function(json){
13407 return /** eval:var:json */ eval("(" + json + ')');
13411 * Shorthand for {@link Roo.util.JSON#encode}
13412 * @member Roo encode
13414 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13416 * Shorthand for {@link Roo.util.JSON#decode}
13417 * @member Roo decode
13419 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13422 * Ext JS Library 1.1.1
13423 * Copyright(c) 2006-2007, Ext JS, LLC.
13425 * Originally Released Under LGPL - original licence link has changed is not relivant.
13428 * <script type="text/javascript">
13432 * @class Roo.util.Format
13433 * Reusable data formatting functions
13436 Roo.util.Format = function(){
13437 var trimRe = /^\s+|\s+$/g;
13440 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13441 * @param {String} value The string to truncate
13442 * @param {Number} length The maximum length to allow before truncating
13443 * @return {String} The converted text
13445 ellipsis : function(value, len){
13446 if(value && value.length > len){
13447 return value.substr(0, len-3)+"...";
13453 * Checks a reference and converts it to empty string if it is undefined
13454 * @param {Mixed} value Reference to check
13455 * @return {Mixed} Empty string if converted, otherwise the original value
13457 undef : function(value){
13458 return typeof value != "undefined" ? value : "";
13462 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13463 * @param {String} value The string to encode
13464 * @return {String} The encoded text
13466 htmlEncode : function(value){
13467 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13471 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13472 * @param {String} value The string to decode
13473 * @return {String} The decoded text
13475 htmlDecode : function(value){
13476 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13480 * Trims any whitespace from either side of a string
13481 * @param {String} value The text to trim
13482 * @return {String} The trimmed text
13484 trim : function(value){
13485 return String(value).replace(trimRe, "");
13489 * Returns a substring from within an original string
13490 * @param {String} value The original text
13491 * @param {Number} start The start index of the substring
13492 * @param {Number} length The length of the substring
13493 * @return {String} The substring
13495 substr : function(value, start, length){
13496 return String(value).substr(start, length);
13500 * Converts a string to all lower case letters
13501 * @param {String} value The text to convert
13502 * @return {String} The converted text
13504 lowercase : function(value){
13505 return String(value).toLowerCase();
13509 * Converts a string to all upper case letters
13510 * @param {String} value The text to convert
13511 * @return {String} The converted text
13513 uppercase : function(value){
13514 return String(value).toUpperCase();
13518 * Converts the first character only of a string to upper case
13519 * @param {String} value The text to convert
13520 * @return {String} The converted text
13522 capitalize : function(value){
13523 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13527 call : function(value, fn){
13528 if(arguments.length > 2){
13529 var args = Array.prototype.slice.call(arguments, 2);
13530 args.unshift(value);
13532 return /** eval:var:value */ eval(fn).apply(window, args);
13534 /** eval:var:value */
13535 return /** eval:var:value */ eval(fn).call(window, value);
13541 * safer version of Math.toFixed..??/
13542 * @param {Number/String} value The numeric value to format
13543 * @param {Number/String} value Decimal places
13544 * @return {String} The formatted currency string
13546 toFixed : function(v, n)
13548 // why not use to fixed - precision is buggered???
13550 return Math.round(v-0);
13552 var fact = Math.pow(10,n+1);
13553 v = (Math.round((v-0)*fact))/fact;
13554 var z = (''+fact).substring(2);
13555 if (v == Math.floor(v)) {
13556 return Math.floor(v) + '.' + z;
13559 // now just padd decimals..
13560 var ps = String(v).split('.');
13561 var fd = (ps[1] + z);
13562 var r = fd.substring(0,n);
13563 var rm = fd.substring(n);
13565 return ps[0] + '.' + r;
13567 r*=1; // turn it into a number;
13569 if (String(r).length != n) {
13572 r = String(r).substring(1); // chop the end off.
13575 return ps[0] + '.' + r;
13580 * Format a number as US currency
13581 * @param {Number/String} value The numeric value to format
13582 * @return {String} The formatted currency string
13584 usMoney : function(v){
13585 return '$' + this.number(v);
13590 * eventually this should probably emulate php's number_format
13591 * @param {Number/String} value The numeric value to format
13592 * @param {Number} decimals number of decimal places
13593 * @return {String} The formatted currency string
13595 number : function(v,decimals)
13597 // multiply and round.
13598 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13599 var mul = Math.pow(10, decimals);
13600 var zero = String(mul).substring(1);
13601 v = (Math.round((v-0)*mul))/mul;
13603 // if it's '0' number.. then
13605 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13607 var ps = v.split('.');
13611 var r = /(\d+)(\d{3})/;
13613 while (r.test(whole)) {
13614 whole = whole.replace(r, '$1' + ',' + '$2');
13619 (decimals ? ('.'+ zero.substring(ps[1].length) + ps[1]) : '') :
13620 (decimals ? ('.' + zero) : '');
13623 return whole + sub ;
13627 * Parse a value into a formatted date using the specified format pattern.
13628 * @param {Mixed} value The value to format
13629 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13630 * @return {String} The formatted date string
13632 date : function(v, format){
13636 if(!(v instanceof Date)){
13637 v = new Date(Date.parse(v));
13639 return v.dateFormat(format || "m/d/Y");
13643 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13644 * @param {String} format Any valid date format string
13645 * @return {Function} The date formatting function
13647 dateRenderer : function(format){
13648 return function(v){
13649 return Roo.util.Format.date(v, format);
13654 stripTagsRE : /<\/?[^>]+>/gi,
13657 * Strips all HTML tags
13658 * @param {Mixed} value The text from which to strip tags
13659 * @return {String} The stripped text
13661 stripTags : function(v){
13662 return !v ? v : String(v).replace(this.stripTagsRE, "");
13667 * Ext JS Library 1.1.1
13668 * Copyright(c) 2006-2007, Ext JS, LLC.
13670 * Originally Released Under LGPL - original licence link has changed is not relivant.
13673 * <script type="text/javascript">
13680 * @class Roo.MasterTemplate
13681 * @extends Roo.Template
13682 * Provides a template that can have child templates. The syntax is:
13684 var t = new Roo.MasterTemplate(
13685 '<select name="{name}">',
13686 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13689 t.add('options', {value: 'foo', text: 'bar'});
13690 // or you can add multiple child elements in one shot
13691 t.addAll('options', [
13692 {value: 'foo', text: 'bar'},
13693 {value: 'foo2', text: 'bar2'},
13694 {value: 'foo3', text: 'bar3'}
13696 // then append, applying the master template values
13697 t.append('my-form', {name: 'my-select'});
13699 * A name attribute for the child template is not required if you have only one child
13700 * template or you want to refer to them by index.
13702 Roo.MasterTemplate = function(){
13703 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13704 this.originalHtml = this.html;
13706 var m, re = this.subTemplateRe;
13709 while(m = re.exec(this.html)){
13710 var name = m[1], content = m[2];
13715 tpl : new Roo.Template(content)
13718 st[name] = st[subIndex];
13720 st[subIndex].tpl.compile();
13721 st[subIndex].tpl.call = this.call.createDelegate(this);
13724 this.subCount = subIndex;
13727 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13729 * The regular expression used to match sub templates
13733 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13736 * Applies the passed values to a child template.
13737 * @param {String/Number} name (optional) The name or index of the child template
13738 * @param {Array/Object} values The values to be applied to the template
13739 * @return {MasterTemplate} this
13741 add : function(name, values){
13742 if(arguments.length == 1){
13743 values = arguments[0];
13746 var s = this.subs[name];
13747 s.buffer[s.buffer.length] = s.tpl.apply(values);
13752 * Applies all the passed values to a child template.
13753 * @param {String/Number} name (optional) The name or index of the child template
13754 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13755 * @param {Boolean} reset (optional) True to reset the template first
13756 * @return {MasterTemplate} this
13758 fill : function(name, values, reset){
13760 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13768 for(var i = 0, len = values.length; i < len; i++){
13769 this.add(name, values[i]);
13775 * Resets the template for reuse
13776 * @return {MasterTemplate} this
13778 reset : function(){
13780 for(var i = 0; i < this.subCount; i++){
13786 applyTemplate : function(values){
13788 var replaceIndex = -1;
13789 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13790 return s[++replaceIndex].buffer.join("");
13792 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13795 apply : function(){
13796 return this.applyTemplate.apply(this, arguments);
13799 compile : function(){return this;}
13803 * Alias for fill().
13806 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13808 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13809 * var tpl = Roo.MasterTemplate.from('element-id');
13810 * @param {String/HTMLElement} el
13811 * @param {Object} config
13814 Roo.MasterTemplate.from = function(el, config){
13815 el = Roo.getDom(el);
13816 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13819 * Ext JS Library 1.1.1
13820 * Copyright(c) 2006-2007, Ext JS, LLC.
13822 * Originally Released Under LGPL - original licence link has changed is not relivant.
13825 * <script type="text/javascript">
13830 * @class Roo.util.CSS
13831 * Utility class for manipulating CSS rules
13834 Roo.util.CSS = function(){
13836 var doc = document;
13838 var camelRe = /(-[a-z])/gi;
13839 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13843 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13844 * tag and appended to the HEAD of the document.
13845 * @param {String|Object} cssText The text containing the css rules
13846 * @param {String} id An id to add to the stylesheet for later removal
13847 * @return {StyleSheet}
13849 createStyleSheet : function(cssText, id){
13851 var head = doc.getElementsByTagName("head")[0];
13852 var nrules = doc.createElement("style");
13853 nrules.setAttribute("type", "text/css");
13855 nrules.setAttribute("id", id);
13857 if (typeof(cssText) != 'string') {
13858 // support object maps..
13859 // not sure if this a good idea..
13860 // perhaps it should be merged with the general css handling
13861 // and handle js style props.
13862 var cssTextNew = [];
13863 for(var n in cssText) {
13865 for(var k in cssText[n]) {
13866 citems.push( k + ' : ' +cssText[n][k] + ';' );
13868 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13871 cssText = cssTextNew.join("\n");
13877 head.appendChild(nrules);
13878 ss = nrules.styleSheet;
13879 ss.cssText = cssText;
13882 nrules.appendChild(doc.createTextNode(cssText));
13884 nrules.cssText = cssText;
13886 head.appendChild(nrules);
13887 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13889 this.cacheStyleSheet(ss);
13894 * Removes a style or link tag by id
13895 * @param {String} id The id of the tag
13897 removeStyleSheet : function(id){
13898 var existing = doc.getElementById(id);
13900 existing.parentNode.removeChild(existing);
13905 * Dynamically swaps an existing stylesheet reference for a new one
13906 * @param {String} id The id of an existing link tag to remove
13907 * @param {String} url The href of the new stylesheet to include
13909 swapStyleSheet : function(id, url){
13910 this.removeStyleSheet(id);
13911 var ss = doc.createElement("link");
13912 ss.setAttribute("rel", "stylesheet");
13913 ss.setAttribute("type", "text/css");
13914 ss.setAttribute("id", id);
13915 ss.setAttribute("href", url);
13916 doc.getElementsByTagName("head")[0].appendChild(ss);
13920 * Refresh the rule cache if you have dynamically added stylesheets
13921 * @return {Object} An object (hash) of rules indexed by selector
13923 refreshCache : function(){
13924 return this.getRules(true);
13928 cacheStyleSheet : function(stylesheet){
13932 try{// try catch for cross domain access issue
13933 var ssRules = stylesheet.cssRules || stylesheet.rules;
13934 for(var j = ssRules.length-1; j >= 0; --j){
13935 rules[ssRules[j].selectorText] = ssRules[j];
13941 * Gets all css rules for the document
13942 * @param {Boolean} refreshCache true to refresh the internal cache
13943 * @return {Object} An object (hash) of rules indexed by selector
13945 getRules : function(refreshCache){
13946 if(rules == null || refreshCache){
13948 var ds = doc.styleSheets;
13949 for(var i =0, len = ds.length; i < len; i++){
13951 this.cacheStyleSheet(ds[i]);
13959 * Gets an an individual CSS rule by selector(s)
13960 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13961 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13962 * @return {CSSRule} The CSS rule or null if one is not found
13964 getRule : function(selector, refreshCache){
13965 var rs = this.getRules(refreshCache);
13966 if(!(selector instanceof Array)){
13967 return rs[selector];
13969 for(var i = 0; i < selector.length; i++){
13970 if(rs[selector[i]]){
13971 return rs[selector[i]];
13979 * Updates a rule property
13980 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13981 * @param {String} property The css property
13982 * @param {String} value The new value for the property
13983 * @return {Boolean} true If a rule was found and updated
13985 updateRule : function(selector, property, value){
13986 if(!(selector instanceof Array)){
13987 var rule = this.getRule(selector);
13989 rule.style[property.replace(camelRe, camelFn)] = value;
13993 for(var i = 0; i < selector.length; i++){
13994 if(this.updateRule(selector[i], property, value)){
14004 * Ext JS Library 1.1.1
14005 * Copyright(c) 2006-2007, Ext JS, LLC.
14007 * Originally Released Under LGPL - original licence link has changed is not relivant.
14010 * <script type="text/javascript">
14016 * @class Roo.util.ClickRepeater
14017 * @extends Roo.util.Observable
14019 * A wrapper class which can be applied to any element. Fires a "click" event while the
14020 * mouse is pressed. The interval between firings may be specified in the config but
14021 * defaults to 10 milliseconds.
14023 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14025 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14026 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14027 * Similar to an autorepeat key delay.
14028 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14029 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14030 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14031 * "interval" and "delay" are ignored. "immediate" is honored.
14032 * @cfg {Boolean} preventDefault True to prevent the default click event
14033 * @cfg {Boolean} stopDefault True to stop the default click event
14036 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14037 * 2007-02-02 jvs Renamed to ClickRepeater
14038 * 2007-02-03 jvs Modifications for FF Mac and Safari
14041 * @param {String/HTMLElement/Element} el The element to listen on
14042 * @param {Object} config
14044 Roo.util.ClickRepeater = function(el, config)
14046 this.el = Roo.get(el);
14047 this.el.unselectable();
14049 Roo.apply(this, config);
14054 * Fires when the mouse button is depressed.
14055 * @param {Roo.util.ClickRepeater} this
14057 "mousedown" : true,
14060 * Fires on a specified interval during the time the element is pressed.
14061 * @param {Roo.util.ClickRepeater} this
14066 * Fires when the mouse key is released.
14067 * @param {Roo.util.ClickRepeater} this
14072 this.el.on("mousedown", this.handleMouseDown, this);
14073 if(this.preventDefault || this.stopDefault){
14074 this.el.on("click", function(e){
14075 if(this.preventDefault){
14076 e.preventDefault();
14078 if(this.stopDefault){
14084 // allow inline handler
14086 this.on("click", this.handler, this.scope || this);
14089 Roo.util.ClickRepeater.superclass.constructor.call(this);
14092 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14095 preventDefault : true,
14096 stopDefault : false,
14100 handleMouseDown : function(){
14101 clearTimeout(this.timer);
14103 if(this.pressClass){
14104 this.el.addClass(this.pressClass);
14106 this.mousedownTime = new Date();
14108 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14109 this.el.on("mouseout", this.handleMouseOut, this);
14111 this.fireEvent("mousedown", this);
14112 this.fireEvent("click", this);
14114 this.timer = this.click.defer(this.delay || this.interval, this);
14118 click : function(){
14119 this.fireEvent("click", this);
14120 this.timer = this.click.defer(this.getInterval(), this);
14124 getInterval: function(){
14125 if(!this.accelerate){
14126 return this.interval;
14128 var pressTime = this.mousedownTime.getElapsed();
14129 if(pressTime < 500){
14131 }else if(pressTime < 1700){
14133 }else if(pressTime < 2600){
14135 }else if(pressTime < 3500){
14137 }else if(pressTime < 4400){
14139 }else if(pressTime < 5300){
14141 }else if(pressTime < 6200){
14149 handleMouseOut : function(){
14150 clearTimeout(this.timer);
14151 if(this.pressClass){
14152 this.el.removeClass(this.pressClass);
14154 this.el.on("mouseover", this.handleMouseReturn, this);
14158 handleMouseReturn : function(){
14159 this.el.un("mouseover", this.handleMouseReturn);
14160 if(this.pressClass){
14161 this.el.addClass(this.pressClass);
14167 handleMouseUp : function(){
14168 clearTimeout(this.timer);
14169 this.el.un("mouseover", this.handleMouseReturn);
14170 this.el.un("mouseout", this.handleMouseOut);
14171 Roo.get(document).un("mouseup", this.handleMouseUp);
14172 this.el.removeClass(this.pressClass);
14173 this.fireEvent("mouseup", this);
14177 * Ext JS Library 1.1.1
14178 * Copyright(c) 2006-2007, Ext JS, LLC.
14180 * Originally Released Under LGPL - original licence link has changed is not relivant.
14183 * <script type="text/javascript">
14188 * @class Roo.KeyNav
14189 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14190 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14191 * way to implement custom navigation schemes for any UI component.</p>
14192 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14193 * pageUp, pageDown, del, home, end. Usage:</p>
14195 var nav = new Roo.KeyNav("my-element", {
14196 "left" : function(e){
14197 this.moveLeft(e.ctrlKey);
14199 "right" : function(e){
14200 this.moveRight(e.ctrlKey);
14202 "enter" : function(e){
14209 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14210 * @param {Object} config The config
14212 Roo.KeyNav = function(el, config){
14213 this.el = Roo.get(el);
14214 Roo.apply(this, config);
14215 if(!this.disabled){
14216 this.disabled = true;
14221 Roo.KeyNav.prototype = {
14223 * @cfg {Boolean} disabled
14224 * True to disable this KeyNav instance (defaults to false)
14228 * @cfg {String} defaultEventAction
14229 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14230 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14231 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14233 defaultEventAction: "stopEvent",
14235 * @cfg {Boolean} forceKeyDown
14236 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14237 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14238 * handle keydown instead of keypress.
14240 forceKeyDown : false,
14243 prepareEvent : function(e){
14244 var k = e.getKey();
14245 var h = this.keyToHandler[k];
14246 //if(h && this[h]){
14247 // e.stopPropagation();
14249 if(Roo.isSafari && h && k >= 37 && k <= 40){
14255 relay : function(e){
14256 var k = e.getKey();
14257 var h = this.keyToHandler[k];
14259 if(this.doRelay(e, this[h], h) !== true){
14260 e[this.defaultEventAction]();
14266 doRelay : function(e, h, hname){
14267 return h.call(this.scope || this, e);
14270 // possible handlers
14284 // quick lookup hash
14301 * Enable this KeyNav
14303 enable: function(){
14305 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14306 // the EventObject will normalize Safari automatically
14307 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14308 this.el.on("keydown", this.relay, this);
14310 this.el.on("keydown", this.prepareEvent, this);
14311 this.el.on("keypress", this.relay, this);
14313 this.disabled = false;
14318 * Disable this KeyNav
14320 disable: function(){
14321 if(!this.disabled){
14322 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14323 this.el.un("keydown", this.relay);
14325 this.el.un("keydown", this.prepareEvent);
14326 this.el.un("keypress", this.relay);
14328 this.disabled = true;
14333 * Ext JS Library 1.1.1
14334 * Copyright(c) 2006-2007, Ext JS, LLC.
14336 * Originally Released Under LGPL - original licence link has changed is not relivant.
14339 * <script type="text/javascript">
14344 * @class Roo.KeyMap
14345 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14346 * The constructor accepts the same config object as defined by {@link #addBinding}.
14347 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14348 * combination it will call the function with this signature (if the match is a multi-key
14349 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14350 * A KeyMap can also handle a string representation of keys.<br />
14353 // map one key by key code
14354 var map = new Roo.KeyMap("my-element", {
14355 key: 13, // or Roo.EventObject.ENTER
14360 // map multiple keys to one action by string
14361 var map = new Roo.KeyMap("my-element", {
14367 // map multiple keys to multiple actions by strings and array of codes
14368 var map = new Roo.KeyMap("my-element", [
14371 fn: function(){ alert("Return was pressed"); }
14374 fn: function(){ alert('a, b or c was pressed'); }
14379 fn: function(){ alert('Control + shift + tab was pressed.'); }
14383 * <b>Note: A KeyMap starts enabled</b>
14385 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14386 * @param {Object} config The config (see {@link #addBinding})
14387 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14389 Roo.KeyMap = function(el, config, eventName){
14390 this.el = Roo.get(el);
14391 this.eventName = eventName || "keydown";
14392 this.bindings = [];
14394 this.addBinding(config);
14399 Roo.KeyMap.prototype = {
14401 * True to stop the event from bubbling and prevent the default browser action if the
14402 * key was handled by the KeyMap (defaults to false)
14408 * Add a new binding to this KeyMap. The following config object properties are supported:
14410 Property Type Description
14411 ---------- --------------- ----------------------------------------------------------------------
14412 key String/Array A single keycode or an array of keycodes to handle
14413 shift Boolean True to handle key only when shift is pressed (defaults to false)
14414 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14415 alt Boolean True to handle key only when alt is pressed (defaults to false)
14416 fn Function The function to call when KeyMap finds the expected key combination
14417 scope Object The scope of the callback function
14423 var map = new Roo.KeyMap(document, {
14424 key: Roo.EventObject.ENTER,
14429 //Add a new binding to the existing KeyMap later
14437 * @param {Object/Array} config A single KeyMap config or an array of configs
14439 addBinding : function(config){
14440 if(config instanceof Array){
14441 for(var i = 0, len = config.length; i < len; i++){
14442 this.addBinding(config[i]);
14446 var keyCode = config.key,
14447 shift = config.shift,
14448 ctrl = config.ctrl,
14451 scope = config.scope;
14452 if(typeof keyCode == "string"){
14454 var keyString = keyCode.toUpperCase();
14455 for(var j = 0, len = keyString.length; j < len; j++){
14456 ks.push(keyString.charCodeAt(j));
14460 var keyArray = keyCode instanceof Array;
14461 var handler = function(e){
14462 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14463 var k = e.getKey();
14465 for(var i = 0, len = keyCode.length; i < len; i++){
14466 if(keyCode[i] == k){
14467 if(this.stopEvent){
14470 fn.call(scope || window, k, e);
14476 if(this.stopEvent){
14479 fn.call(scope || window, k, e);
14484 this.bindings.push(handler);
14488 * Shorthand for adding a single key listener
14489 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14490 * following options:
14491 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14492 * @param {Function} fn The function to call
14493 * @param {Object} scope (optional) The scope of the function
14495 on : function(key, fn, scope){
14496 var keyCode, shift, ctrl, alt;
14497 if(typeof key == "object" && !(key instanceof Array)){
14516 handleKeyDown : function(e){
14517 if(this.enabled){ //just in case
14518 var b = this.bindings;
14519 for(var i = 0, len = b.length; i < len; i++){
14520 b[i].call(this, e);
14526 * Returns true if this KeyMap is enabled
14527 * @return {Boolean}
14529 isEnabled : function(){
14530 return this.enabled;
14534 * Enables this KeyMap
14536 enable: function(){
14538 this.el.on(this.eventName, this.handleKeyDown, this);
14539 this.enabled = true;
14544 * Disable this KeyMap
14546 disable: function(){
14548 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14549 this.enabled = false;
14554 * Ext JS Library 1.1.1
14555 * Copyright(c) 2006-2007, Ext JS, LLC.
14557 * Originally Released Under LGPL - original licence link has changed is not relivant.
14560 * <script type="text/javascript">
14565 * @class Roo.util.TextMetrics
14566 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14567 * wide, in pixels, a given block of text will be.
14570 Roo.util.TextMetrics = function(){
14574 * Measures the size of the specified text
14575 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14576 * that can affect the size of the rendered text
14577 * @param {String} text The text to measure
14578 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14579 * in order to accurately measure the text height
14580 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14582 measure : function(el, text, fixedWidth){
14584 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14587 shared.setFixedWidth(fixedWidth || 'auto');
14588 return shared.getSize(text);
14592 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14593 * the overhead of multiple calls to initialize the style properties on each measurement.
14594 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14595 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14596 * in order to accurately measure the text height
14597 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14599 createInstance : function(el, fixedWidth){
14600 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14607 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14608 var ml = new Roo.Element(document.createElement('div'));
14609 document.body.appendChild(ml.dom);
14610 ml.position('absolute');
14611 ml.setLeftTop(-1000, -1000);
14615 ml.setWidth(fixedWidth);
14620 * Returns the size of the specified text based on the internal element's style and width properties
14621 * @memberOf Roo.util.TextMetrics.Instance#
14622 * @param {String} text The text to measure
14623 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14625 getSize : function(text){
14627 var s = ml.getSize();
14633 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14634 * that can affect the size of the rendered text
14635 * @memberOf Roo.util.TextMetrics.Instance#
14636 * @param {String/HTMLElement} el The element, dom node or id
14638 bind : function(el){
14640 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14645 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14646 * to set a fixed width in order to accurately measure the text height.
14647 * @memberOf Roo.util.TextMetrics.Instance#
14648 * @param {Number} width The width to set on the element
14650 setFixedWidth : function(width){
14651 ml.setWidth(width);
14655 * Returns the measured width of the specified text
14656 * @memberOf Roo.util.TextMetrics.Instance#
14657 * @param {String} text The text to measure
14658 * @return {Number} width The width in pixels
14660 getWidth : function(text){
14661 ml.dom.style.width = 'auto';
14662 return this.getSize(text).width;
14666 * Returns the measured height of the specified text. For multiline text, be sure to call
14667 * {@link #setFixedWidth} if necessary.
14668 * @memberOf Roo.util.TextMetrics.Instance#
14669 * @param {String} text The text to measure
14670 * @return {Number} height The height in pixels
14672 getHeight : function(text){
14673 return this.getSize(text).height;
14677 instance.bind(bindTo);
14682 // backwards compat
14683 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14685 * Ext JS Library 1.1.1
14686 * Copyright(c) 2006-2007, Ext JS, LLC.
14688 * Originally Released Under LGPL - original licence link has changed is not relivant.
14691 * <script type="text/javascript">
14695 * @class Roo.state.Provider
14696 * Abstract base class for state provider implementations. This class provides methods
14697 * for encoding and decoding <b>typed</b> variables including dates and defines the
14698 * Provider interface.
14700 Roo.state.Provider = function(){
14702 * @event statechange
14703 * Fires when a state change occurs.
14704 * @param {Provider} this This state provider
14705 * @param {String} key The state key which was changed
14706 * @param {String} value The encoded value for the state
14709 "statechange": true
14712 Roo.state.Provider.superclass.constructor.call(this);
14714 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14716 * Returns the current value for a key
14717 * @param {String} name The key name
14718 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14719 * @return {Mixed} The state data
14721 get : function(name, defaultValue){
14722 return typeof this.state[name] == "undefined" ?
14723 defaultValue : this.state[name];
14727 * Clears a value from the state
14728 * @param {String} name The key name
14730 clear : function(name){
14731 delete this.state[name];
14732 this.fireEvent("statechange", this, name, null);
14736 * Sets the value for a key
14737 * @param {String} name The key name
14738 * @param {Mixed} value The value to set
14740 set : function(name, value){
14741 this.state[name] = value;
14742 this.fireEvent("statechange", this, name, value);
14746 * Decodes a string previously encoded with {@link #encodeValue}.
14747 * @param {String} value The value to decode
14748 * @return {Mixed} The decoded value
14750 decodeValue : function(cookie){
14751 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14752 var matches = re.exec(unescape(cookie));
14753 if(!matches || !matches[1]) return; // non state cookie
14754 var type = matches[1];
14755 var v = matches[2];
14758 return parseFloat(v);
14760 return new Date(Date.parse(v));
14765 var values = v.split("^");
14766 for(var i = 0, len = values.length; i < len; i++){
14767 all.push(this.decodeValue(values[i]));
14772 var values = v.split("^");
14773 for(var i = 0, len = values.length; i < len; i++){
14774 var kv = values[i].split("=");
14775 all[kv[0]] = this.decodeValue(kv[1]);
14784 * Encodes a value including type information. Decode with {@link #decodeValue}.
14785 * @param {Mixed} value The value to encode
14786 * @return {String} The encoded value
14788 encodeValue : function(v){
14790 if(typeof v == "number"){
14792 }else if(typeof v == "boolean"){
14793 enc = "b:" + (v ? "1" : "0");
14794 }else if(v instanceof Date){
14795 enc = "d:" + v.toGMTString();
14796 }else if(v instanceof Array){
14798 for(var i = 0, len = v.length; i < len; i++){
14799 flat += this.encodeValue(v[i]);
14800 if(i != len-1) flat += "^";
14803 }else if(typeof v == "object"){
14806 if(typeof v[key] != "function"){
14807 flat += key + "=" + this.encodeValue(v[key]) + "^";
14810 enc = "o:" + flat.substring(0, flat.length-1);
14814 return escape(enc);
14820 * Ext JS Library 1.1.1
14821 * Copyright(c) 2006-2007, Ext JS, LLC.
14823 * Originally Released Under LGPL - original licence link has changed is not relivant.
14826 * <script type="text/javascript">
14829 * @class Roo.state.Manager
14830 * This is the global state manager. By default all components that are "state aware" check this class
14831 * for state information if you don't pass them a custom state provider. In order for this class
14832 * to be useful, it must be initialized with a provider when your application initializes.
14834 // in your initialization function
14836 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14838 // supposed you have a {@link Roo.BorderLayout}
14839 var layout = new Roo.BorderLayout(...);
14840 layout.restoreState();
14841 // or a {Roo.BasicDialog}
14842 var dialog = new Roo.BasicDialog(...);
14843 dialog.restoreState();
14847 Roo.state.Manager = function(){
14848 var provider = new Roo.state.Provider();
14852 * Configures the default state provider for your application
14853 * @param {Provider} stateProvider The state provider to set
14855 setProvider : function(stateProvider){
14856 provider = stateProvider;
14860 * Returns the current value for a key
14861 * @param {String} name The key name
14862 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14863 * @return {Mixed} The state data
14865 get : function(key, defaultValue){
14866 return provider.get(key, defaultValue);
14870 * Sets the value for a key
14871 * @param {String} name The key name
14872 * @param {Mixed} value The state data
14874 set : function(key, value){
14875 provider.set(key, value);
14879 * Clears a value from the state
14880 * @param {String} name The key name
14882 clear : function(key){
14883 provider.clear(key);
14887 * Gets the currently configured state provider
14888 * @return {Provider} The state provider
14890 getProvider : function(){
14897 * Ext JS Library 1.1.1
14898 * Copyright(c) 2006-2007, Ext JS, LLC.
14900 * Originally Released Under LGPL - original licence link has changed is not relivant.
14903 * <script type="text/javascript">
14906 * @class Roo.state.CookieProvider
14907 * @extends Roo.state.Provider
14908 * The default Provider implementation which saves state via cookies.
14911 var cp = new Roo.state.CookieProvider({
14913 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14914 domain: "roojs.com"
14916 Roo.state.Manager.setProvider(cp);
14918 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14919 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14920 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14921 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14922 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14923 * domain the page is running on including the 'www' like 'www.roojs.com')
14924 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14926 * Create a new CookieProvider
14927 * @param {Object} config The configuration object
14929 Roo.state.CookieProvider = function(config){
14930 Roo.state.CookieProvider.superclass.constructor.call(this);
14932 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14933 this.domain = null;
14934 this.secure = false;
14935 Roo.apply(this, config);
14936 this.state = this.readCookies();
14939 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14941 set : function(name, value){
14942 if(typeof value == "undefined" || value === null){
14946 this.setCookie(name, value);
14947 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14951 clear : function(name){
14952 this.clearCookie(name);
14953 Roo.state.CookieProvider.superclass.clear.call(this, name);
14957 readCookies : function(){
14959 var c = document.cookie + ";";
14960 var re = /\s?(.*?)=(.*?);/g;
14962 while((matches = re.exec(c)) != null){
14963 var name = matches[1];
14964 var value = matches[2];
14965 if(name && name.substring(0,3) == "ys-"){
14966 cookies[name.substr(3)] = this.decodeValue(value);
14973 setCookie : function(name, value){
14974 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14975 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14976 ((this.path == null) ? "" : ("; path=" + this.path)) +
14977 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14978 ((this.secure == true) ? "; secure" : "");
14982 clearCookie : function(name){
14983 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14984 ((this.path == null) ? "" : ("; path=" + this.path)) +
14985 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14986 ((this.secure == true) ? "; secure" : "");
14990 * Ext JS Library 1.1.1
14991 * Copyright(c) 2006-2007, Ext JS, LLC.
14993 * Originally Released Under LGPL - original licence link has changed is not relivant.
14996 * <script type="text/javascript">
15002 * These classes are derivatives of the similarly named classes in the YUI Library.
15003 * The original license:
15004 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
15005 * Code licensed under the BSD License:
15006 * http://developer.yahoo.net/yui/license.txt
15011 var Event=Roo.EventManager;
15012 var Dom=Roo.lib.Dom;
15015 * @class Roo.dd.DragDrop
15016 * @extends Roo.util.Observable
15017 * Defines the interface and base operation of items that that can be
15018 * dragged or can be drop targets. It was designed to be extended, overriding
15019 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
15020 * Up to three html elements can be associated with a DragDrop instance:
15022 * <li>linked element: the element that is passed into the constructor.
15023 * This is the element which defines the boundaries for interaction with
15024 * other DragDrop objects.</li>
15025 * <li>handle element(s): The drag operation only occurs if the element that
15026 * was clicked matches a handle element. By default this is the linked
15027 * element, but there are times that you will want only a portion of the
15028 * linked element to initiate the drag operation, and the setHandleElId()
15029 * method provides a way to define this.</li>
15030 * <li>drag element: this represents the element that would be moved along
15031 * with the cursor during a drag operation. By default, this is the linked
15032 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
15033 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
15036 * This class should not be instantiated until the onload event to ensure that
15037 * the associated elements are available.
15038 * The following would define a DragDrop obj that would interact with any
15039 * other DragDrop obj in the "group1" group:
15041 * dd = new Roo.dd.DragDrop("div1", "group1");
15043 * Since none of the event handlers have been implemented, nothing would
15044 * actually happen if you were to run the code above. Normally you would
15045 * override this class or one of the default implementations, but you can
15046 * also override the methods you want on an instance of the class...
15048 * dd.onDragDrop = function(e, id) {
15049 * alert("dd was dropped on " + id);
15053 * @param {String} id of the element that is linked to this instance
15054 * @param {String} sGroup the group of related DragDrop objects
15055 * @param {object} config an object containing configurable attributes
15056 * Valid properties for DragDrop:
15057 * padding, isTarget, maintainOffset, primaryButtonOnly
15059 Roo.dd.DragDrop = function(id, sGroup, config) {
15061 this.init(id, sGroup, config);
15066 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15069 * The id of the element associated with this object. This is what we
15070 * refer to as the "linked element" because the size and position of
15071 * this element is used to determine when the drag and drop objects have
15079 * Configuration attributes passed into the constructor
15086 * The id of the element that will be dragged. By default this is same
15087 * as the linked element , but could be changed to another element. Ex:
15089 * @property dragElId
15096 * the id of the element that initiates the drag operation. By default
15097 * this is the linked element, but could be changed to be a child of this
15098 * element. This lets us do things like only starting the drag when the
15099 * header element within the linked html element is clicked.
15100 * @property handleElId
15107 * An associative array of HTML tags that will be ignored if clicked.
15108 * @property invalidHandleTypes
15109 * @type {string: string}
15111 invalidHandleTypes: null,
15114 * An associative array of ids for elements that will be ignored if clicked
15115 * @property invalidHandleIds
15116 * @type {string: string}
15118 invalidHandleIds: null,
15121 * An indexted array of css class names for elements that will be ignored
15123 * @property invalidHandleClasses
15126 invalidHandleClasses: null,
15129 * The linked element's absolute X position at the time the drag was
15131 * @property startPageX
15138 * The linked element's absolute X position at the time the drag was
15140 * @property startPageY
15147 * The group defines a logical collection of DragDrop objects that are
15148 * related. Instances only get events when interacting with other
15149 * DragDrop object in the same group. This lets us define multiple
15150 * groups using a single DragDrop subclass if we want.
15152 * @type {string: string}
15157 * Individual drag/drop instances can be locked. This will prevent
15158 * onmousedown start drag.
15166 * Lock this instance
15169 lock: function() { this.locked = true; },
15172 * Unlock this instace
15175 unlock: function() { this.locked = false; },
15178 * By default, all insances can be a drop target. This can be disabled by
15179 * setting isTarget to false.
15186 * The padding configured for this drag and drop object for calculating
15187 * the drop zone intersection with this object.
15194 * Cached reference to the linked element
15195 * @property _domRef
15201 * Internal typeof flag
15202 * @property __ygDragDrop
15205 __ygDragDrop: true,
15208 * Set to true when horizontal contraints are applied
15209 * @property constrainX
15216 * Set to true when vertical contraints are applied
15217 * @property constrainY
15224 * The left constraint
15232 * The right constraint
15240 * The up constraint
15249 * The down constraint
15257 * Maintain offsets when we resetconstraints. Set to true when you want
15258 * the position of the element relative to its parent to stay the same
15259 * when the page changes
15261 * @property maintainOffset
15264 maintainOffset: false,
15267 * Array of pixel locations the element will snap to if we specified a
15268 * horizontal graduation/interval. This array is generated automatically
15269 * when you define a tick interval.
15276 * Array of pixel locations the element will snap to if we specified a
15277 * vertical graduation/interval. This array is generated automatically
15278 * when you define a tick interval.
15285 * By default the drag and drop instance will only respond to the primary
15286 * button click (left button for a right-handed mouse). Set to true to
15287 * allow drag and drop to start with any mouse click that is propogated
15289 * @property primaryButtonOnly
15292 primaryButtonOnly: true,
15295 * The availabe property is false until the linked dom element is accessible.
15296 * @property available
15302 * By default, drags can only be initiated if the mousedown occurs in the
15303 * region the linked element is. This is done in part to work around a
15304 * bug in some browsers that mis-report the mousedown if the previous
15305 * mouseup happened outside of the window. This property is set to true
15306 * if outer handles are defined.
15308 * @property hasOuterHandles
15312 hasOuterHandles: false,
15315 * Code that executes immediately before the startDrag event
15316 * @method b4StartDrag
15319 b4StartDrag: function(x, y) { },
15322 * Abstract method called after a drag/drop object is clicked
15323 * and the drag or mousedown time thresholds have beeen met.
15324 * @method startDrag
15325 * @param {int} X click location
15326 * @param {int} Y click location
15328 startDrag: function(x, y) { /* override this */ },
15331 * Code that executes immediately before the onDrag event
15335 b4Drag: function(e) { },
15338 * Abstract method called during the onMouseMove event while dragging an
15341 * @param {Event} e the mousemove event
15343 onDrag: function(e) { /* override this */ },
15346 * Abstract method called when this element fist begins hovering over
15347 * another DragDrop obj
15348 * @method onDragEnter
15349 * @param {Event} e the mousemove event
15350 * @param {String|DragDrop[]} id In POINT mode, the element
15351 * id this is hovering over. In INTERSECT mode, an array of one or more
15352 * dragdrop items being hovered over.
15354 onDragEnter: function(e, id) { /* override this */ },
15357 * Code that executes immediately before the onDragOver event
15358 * @method b4DragOver
15361 b4DragOver: function(e) { },
15364 * Abstract method called when this element is hovering over another
15366 * @method onDragOver
15367 * @param {Event} e the mousemove event
15368 * @param {String|DragDrop[]} id In POINT mode, the element
15369 * id this is hovering over. In INTERSECT mode, an array of dd items
15370 * being hovered over.
15372 onDragOver: function(e, id) { /* override this */ },
15375 * Code that executes immediately before the onDragOut event
15376 * @method b4DragOut
15379 b4DragOut: function(e) { },
15382 * Abstract method called when we are no longer hovering over an element
15383 * @method onDragOut
15384 * @param {Event} e the mousemove event
15385 * @param {String|DragDrop[]} id In POINT mode, the element
15386 * id this was hovering over. In INTERSECT mode, an array of dd items
15387 * that the mouse is no longer over.
15389 onDragOut: function(e, id) { /* override this */ },
15392 * Code that executes immediately before the onDragDrop event
15393 * @method b4DragDrop
15396 b4DragDrop: function(e) { },
15399 * Abstract method called when this item is dropped on another DragDrop
15401 * @method onDragDrop
15402 * @param {Event} e the mouseup event
15403 * @param {String|DragDrop[]} id In POINT mode, the element
15404 * id this was dropped on. In INTERSECT mode, an array of dd items this
15407 onDragDrop: function(e, id) { /* override this */ },
15410 * Abstract method called when this item is dropped on an area with no
15412 * @method onInvalidDrop
15413 * @param {Event} e the mouseup event
15415 onInvalidDrop: function(e) { /* override this */ },
15418 * Code that executes immediately before the endDrag event
15419 * @method b4EndDrag
15422 b4EndDrag: function(e) { },
15425 * Fired when we are done dragging the object
15427 * @param {Event} e the mouseup event
15429 endDrag: function(e) { /* override this */ },
15432 * Code executed immediately before the onMouseDown event
15433 * @method b4MouseDown
15434 * @param {Event} e the mousedown event
15437 b4MouseDown: function(e) { },
15440 * Event handler that fires when a drag/drop obj gets a mousedown
15441 * @method onMouseDown
15442 * @param {Event} e the mousedown event
15444 onMouseDown: function(e) { /* override this */ },
15447 * Event handler that fires when a drag/drop obj gets a mouseup
15448 * @method onMouseUp
15449 * @param {Event} e the mouseup event
15451 onMouseUp: function(e) { /* override this */ },
15454 * Override the onAvailable method to do what is needed after the initial
15455 * position was determined.
15456 * @method onAvailable
15458 onAvailable: function () {
15462 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15465 defaultPadding : {left:0, right:0, top:0, bottom:0},
15468 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15472 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15473 { dragElId: "existingProxyDiv" });
15474 dd.startDrag = function(){
15475 this.constrainTo("parent-id");
15478 * Or you can initalize it using the {@link Roo.Element} object:
15480 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15481 startDrag : function(){
15482 this.constrainTo("parent-id");
15486 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15487 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15488 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15489 * an object containing the sides to pad. For example: {right:10, bottom:10}
15490 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15492 constrainTo : function(constrainTo, pad, inContent){
15493 if(typeof pad == "number"){
15494 pad = {left: pad, right:pad, top:pad, bottom:pad};
15496 pad = pad || this.defaultPadding;
15497 var b = Roo.get(this.getEl()).getBox();
15498 var ce = Roo.get(constrainTo);
15499 var s = ce.getScroll();
15500 var c, cd = ce.dom;
15501 if(cd == document.body){
15502 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15505 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15509 var topSpace = b.y - c.y;
15510 var leftSpace = b.x - c.x;
15512 this.resetConstraints();
15513 this.setXConstraint(leftSpace - (pad.left||0), // left
15514 c.width - leftSpace - b.width - (pad.right||0) //right
15516 this.setYConstraint(topSpace - (pad.top||0), //top
15517 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15522 * Returns a reference to the linked element
15524 * @return {HTMLElement} the html element
15526 getEl: function() {
15527 if (!this._domRef) {
15528 this._domRef = Roo.getDom(this.id);
15531 return this._domRef;
15535 * Returns a reference to the actual element to drag. By default this is
15536 * the same as the html element, but it can be assigned to another
15537 * element. An example of this can be found in Roo.dd.DDProxy
15538 * @method getDragEl
15539 * @return {HTMLElement} the html element
15541 getDragEl: function() {
15542 return Roo.getDom(this.dragElId);
15546 * Sets up the DragDrop object. Must be called in the constructor of any
15547 * Roo.dd.DragDrop subclass
15549 * @param id the id of the linked element
15550 * @param {String} sGroup the group of related items
15551 * @param {object} config configuration attributes
15553 init: function(id, sGroup, config) {
15554 this.initTarget(id, sGroup, config);
15555 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15556 // Event.on(this.id, "selectstart", Event.preventDefault);
15560 * Initializes Targeting functionality only... the object does not
15561 * get a mousedown handler.
15562 * @method initTarget
15563 * @param id the id of the linked element
15564 * @param {String} sGroup the group of related items
15565 * @param {object} config configuration attributes
15567 initTarget: function(id, sGroup, config) {
15569 // configuration attributes
15570 this.config = config || {};
15572 // create a local reference to the drag and drop manager
15573 this.DDM = Roo.dd.DDM;
15574 // initialize the groups array
15577 // assume that we have an element reference instead of an id if the
15578 // parameter is not a string
15579 if (typeof id !== "string") {
15586 // add to an interaction group
15587 this.addToGroup((sGroup) ? sGroup : "default");
15589 // We don't want to register this as the handle with the manager
15590 // so we just set the id rather than calling the setter.
15591 this.handleElId = id;
15593 // the linked element is the element that gets dragged by default
15594 this.setDragElId(id);
15596 // by default, clicked anchors will not start drag operations.
15597 this.invalidHandleTypes = { A: "A" };
15598 this.invalidHandleIds = {};
15599 this.invalidHandleClasses = [];
15601 this.applyConfig();
15603 this.handleOnAvailable();
15607 * Applies the configuration parameters that were passed into the constructor.
15608 * This is supposed to happen at each level through the inheritance chain. So
15609 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15610 * DragDrop in order to get all of the parameters that are available in
15612 * @method applyConfig
15614 applyConfig: function() {
15616 // configurable properties:
15617 // padding, isTarget, maintainOffset, primaryButtonOnly
15618 this.padding = this.config.padding || [0, 0, 0, 0];
15619 this.isTarget = (this.config.isTarget !== false);
15620 this.maintainOffset = (this.config.maintainOffset);
15621 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15626 * Executed when the linked element is available
15627 * @method handleOnAvailable
15630 handleOnAvailable: function() {
15631 this.available = true;
15632 this.resetConstraints();
15633 this.onAvailable();
15637 * Configures the padding for the target zone in px. Effectively expands
15638 * (or reduces) the virtual object size for targeting calculations.
15639 * Supports css-style shorthand; if only one parameter is passed, all sides
15640 * will have that padding, and if only two are passed, the top and bottom
15641 * will have the first param, the left and right the second.
15642 * @method setPadding
15643 * @param {int} iTop Top pad
15644 * @param {int} iRight Right pad
15645 * @param {int} iBot Bot pad
15646 * @param {int} iLeft Left pad
15648 setPadding: function(iTop, iRight, iBot, iLeft) {
15649 // this.padding = [iLeft, iRight, iTop, iBot];
15650 if (!iRight && 0 !== iRight) {
15651 this.padding = [iTop, iTop, iTop, iTop];
15652 } else if (!iBot && 0 !== iBot) {
15653 this.padding = [iTop, iRight, iTop, iRight];
15655 this.padding = [iTop, iRight, iBot, iLeft];
15660 * Stores the initial placement of the linked element.
15661 * @method setInitialPosition
15662 * @param {int} diffX the X offset, default 0
15663 * @param {int} diffY the Y offset, default 0
15665 setInitPosition: function(diffX, diffY) {
15666 var el = this.getEl();
15668 if (!this.DDM.verifyEl(el)) {
15672 var dx = diffX || 0;
15673 var dy = diffY || 0;
15675 var p = Dom.getXY( el );
15677 this.initPageX = p[0] - dx;
15678 this.initPageY = p[1] - dy;
15680 this.lastPageX = p[0];
15681 this.lastPageY = p[1];
15684 this.setStartPosition(p);
15688 * Sets the start position of the element. This is set when the obj
15689 * is initialized, the reset when a drag is started.
15690 * @method setStartPosition
15691 * @param pos current position (from previous lookup)
15694 setStartPosition: function(pos) {
15695 var p = pos || Dom.getXY( this.getEl() );
15696 this.deltaSetXY = null;
15698 this.startPageX = p[0];
15699 this.startPageY = p[1];
15703 * Add this instance to a group of related drag/drop objects. All
15704 * instances belong to at least one group, and can belong to as many
15705 * groups as needed.
15706 * @method addToGroup
15707 * @param sGroup {string} the name of the group
15709 addToGroup: function(sGroup) {
15710 this.groups[sGroup] = true;
15711 this.DDM.regDragDrop(this, sGroup);
15715 * Remove's this instance from the supplied interaction group
15716 * @method removeFromGroup
15717 * @param {string} sGroup The group to drop
15719 removeFromGroup: function(sGroup) {
15720 if (this.groups[sGroup]) {
15721 delete this.groups[sGroup];
15724 this.DDM.removeDDFromGroup(this, sGroup);
15728 * Allows you to specify that an element other than the linked element
15729 * will be moved with the cursor during a drag
15730 * @method setDragElId
15731 * @param id {string} the id of the element that will be used to initiate the drag
15733 setDragElId: function(id) {
15734 this.dragElId = id;
15738 * Allows you to specify a child of the linked element that should be
15739 * used to initiate the drag operation. An example of this would be if
15740 * you have a content div with text and links. Clicking anywhere in the
15741 * content area would normally start the drag operation. Use this method
15742 * to specify that an element inside of the content div is the element
15743 * that starts the drag operation.
15744 * @method setHandleElId
15745 * @param id {string} the id of the element that will be used to
15746 * initiate the drag.
15748 setHandleElId: function(id) {
15749 if (typeof id !== "string") {
15752 this.handleElId = id;
15753 this.DDM.regHandle(this.id, id);
15757 * Allows you to set an element outside of the linked element as a drag
15759 * @method setOuterHandleElId
15760 * @param id the id of the element that will be used to initiate the drag
15762 setOuterHandleElId: function(id) {
15763 if (typeof id !== "string") {
15766 Event.on(id, "mousedown",
15767 this.handleMouseDown, this);
15768 this.setHandleElId(id);
15770 this.hasOuterHandles = true;
15774 * Remove all drag and drop hooks for this element
15777 unreg: function() {
15778 Event.un(this.id, "mousedown",
15779 this.handleMouseDown);
15780 this._domRef = null;
15781 this.DDM._remove(this);
15784 destroy : function(){
15789 * Returns true if this instance is locked, or the drag drop mgr is locked
15790 * (meaning that all drag/drop is disabled on the page.)
15792 * @return {boolean} true if this obj or all drag/drop is locked, else
15795 isLocked: function() {
15796 return (this.DDM.isLocked() || this.locked);
15800 * Fired when this object is clicked
15801 * @method handleMouseDown
15803 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15806 handleMouseDown: function(e, oDD){
15807 if (this.primaryButtonOnly && e.button != 0) {
15811 if (this.isLocked()) {
15815 this.DDM.refreshCache(this.groups);
15817 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15818 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15820 if (this.clickValidator(e)) {
15822 // set the initial element position
15823 this.setStartPosition();
15826 this.b4MouseDown(e);
15827 this.onMouseDown(e);
15829 this.DDM.handleMouseDown(e, this);
15831 this.DDM.stopEvent(e);
15839 clickValidator: function(e) {
15840 var target = e.getTarget();
15841 return ( this.isValidHandleChild(target) &&
15842 (this.id == this.handleElId ||
15843 this.DDM.handleWasClicked(target, this.id)) );
15847 * Allows you to specify a tag name that should not start a drag operation
15848 * when clicked. This is designed to facilitate embedding links within a
15849 * drag handle that do something other than start the drag.
15850 * @method addInvalidHandleType
15851 * @param {string} tagName the type of element to exclude
15853 addInvalidHandleType: function(tagName) {
15854 var type = tagName.toUpperCase();
15855 this.invalidHandleTypes[type] = type;
15859 * Lets you to specify an element id for a child of a drag handle
15860 * that should not initiate a drag
15861 * @method addInvalidHandleId
15862 * @param {string} id the element id of the element you wish to ignore
15864 addInvalidHandleId: function(id) {
15865 if (typeof id !== "string") {
15868 this.invalidHandleIds[id] = id;
15872 * Lets you specify a css class of elements that will not initiate a drag
15873 * @method addInvalidHandleClass
15874 * @param {string} cssClass the class of the elements you wish to ignore
15876 addInvalidHandleClass: function(cssClass) {
15877 this.invalidHandleClasses.push(cssClass);
15881 * Unsets an excluded tag name set by addInvalidHandleType
15882 * @method removeInvalidHandleType
15883 * @param {string} tagName the type of element to unexclude
15885 removeInvalidHandleType: function(tagName) {
15886 var type = tagName.toUpperCase();
15887 // this.invalidHandleTypes[type] = null;
15888 delete this.invalidHandleTypes[type];
15892 * Unsets an invalid handle id
15893 * @method removeInvalidHandleId
15894 * @param {string} id the id of the element to re-enable
15896 removeInvalidHandleId: function(id) {
15897 if (typeof id !== "string") {
15900 delete this.invalidHandleIds[id];
15904 * Unsets an invalid css class
15905 * @method removeInvalidHandleClass
15906 * @param {string} cssClass the class of the element(s) you wish to
15909 removeInvalidHandleClass: function(cssClass) {
15910 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15911 if (this.invalidHandleClasses[i] == cssClass) {
15912 delete this.invalidHandleClasses[i];
15918 * Checks the tag exclusion list to see if this click should be ignored
15919 * @method isValidHandleChild
15920 * @param {HTMLElement} node the HTMLElement to evaluate
15921 * @return {boolean} true if this is a valid tag type, false if not
15923 isValidHandleChild: function(node) {
15926 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15929 nodeName = node.nodeName.toUpperCase();
15931 nodeName = node.nodeName;
15933 valid = valid && !this.invalidHandleTypes[nodeName];
15934 valid = valid && !this.invalidHandleIds[node.id];
15936 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15937 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15946 * Create the array of horizontal tick marks if an interval was specified
15947 * in setXConstraint().
15948 * @method setXTicks
15951 setXTicks: function(iStartX, iTickSize) {
15953 this.xTickSize = iTickSize;
15957 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15959 this.xTicks[this.xTicks.length] = i;
15964 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15966 this.xTicks[this.xTicks.length] = i;
15971 this.xTicks.sort(this.DDM.numericSort) ;
15975 * Create the array of vertical tick marks if an interval was specified in
15976 * setYConstraint().
15977 * @method setYTicks
15980 setYTicks: function(iStartY, iTickSize) {
15982 this.yTickSize = iTickSize;
15986 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15988 this.yTicks[this.yTicks.length] = i;
15993 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15995 this.yTicks[this.yTicks.length] = i;
16000 this.yTicks.sort(this.DDM.numericSort) ;
16004 * By default, the element can be dragged any place on the screen. Use
16005 * this method to limit the horizontal travel of the element. Pass in
16006 * 0,0 for the parameters if you want to lock the drag to the y axis.
16007 * @method setXConstraint
16008 * @param {int} iLeft the number of pixels the element can move to the left
16009 * @param {int} iRight the number of pixels the element can move to the
16011 * @param {int} iTickSize optional parameter for specifying that the
16013 * should move iTickSize pixels at a time.
16015 setXConstraint: function(iLeft, iRight, iTickSize) {
16016 this.leftConstraint = iLeft;
16017 this.rightConstraint = iRight;
16019 this.minX = this.initPageX - iLeft;
16020 this.maxX = this.initPageX + iRight;
16021 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
16023 this.constrainX = true;
16027 * Clears any constraints applied to this instance. Also clears ticks
16028 * since they can't exist independent of a constraint at this time.
16029 * @method clearConstraints
16031 clearConstraints: function() {
16032 this.constrainX = false;
16033 this.constrainY = false;
16038 * Clears any tick interval defined for this instance
16039 * @method clearTicks
16041 clearTicks: function() {
16042 this.xTicks = null;
16043 this.yTicks = null;
16044 this.xTickSize = 0;
16045 this.yTickSize = 0;
16049 * By default, the element can be dragged any place on the screen. Set
16050 * this to limit the vertical travel of the element. Pass in 0,0 for the
16051 * parameters if you want to lock the drag to the x axis.
16052 * @method setYConstraint
16053 * @param {int} iUp the number of pixels the element can move up
16054 * @param {int} iDown the number of pixels the element can move down
16055 * @param {int} iTickSize optional parameter for specifying that the
16056 * element should move iTickSize pixels at a time.
16058 setYConstraint: function(iUp, iDown, iTickSize) {
16059 this.topConstraint = iUp;
16060 this.bottomConstraint = iDown;
16062 this.minY = this.initPageY - iUp;
16063 this.maxY = this.initPageY + iDown;
16064 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16066 this.constrainY = true;
16071 * resetConstraints must be called if you manually reposition a dd element.
16072 * @method resetConstraints
16073 * @param {boolean} maintainOffset
16075 resetConstraints: function() {
16078 // Maintain offsets if necessary
16079 if (this.initPageX || this.initPageX === 0) {
16080 // figure out how much this thing has moved
16081 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16082 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16084 this.setInitPosition(dx, dy);
16086 // This is the first time we have detected the element's position
16088 this.setInitPosition();
16091 if (this.constrainX) {
16092 this.setXConstraint( this.leftConstraint,
16093 this.rightConstraint,
16097 if (this.constrainY) {
16098 this.setYConstraint( this.topConstraint,
16099 this.bottomConstraint,
16105 * Normally the drag element is moved pixel by pixel, but we can specify
16106 * that it move a number of pixels at a time. This method resolves the
16107 * location when we have it set up like this.
16109 * @param {int} val where we want to place the object
16110 * @param {int[]} tickArray sorted array of valid points
16111 * @return {int} the closest tick
16114 getTick: function(val, tickArray) {
16117 // If tick interval is not defined, it is effectively 1 pixel,
16118 // so we return the value passed to us.
16120 } else if (tickArray[0] >= val) {
16121 // The value is lower than the first tick, so we return the first
16123 return tickArray[0];
16125 for (var i=0, len=tickArray.length; i<len; ++i) {
16127 if (tickArray[next] && tickArray[next] >= val) {
16128 var diff1 = val - tickArray[i];
16129 var diff2 = tickArray[next] - val;
16130 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16134 // The value is larger than the last tick, so we return the last
16136 return tickArray[tickArray.length - 1];
16143 * @return {string} string representation of the dd obj
16145 toString: function() {
16146 return ("DragDrop " + this.id);
16154 * Ext JS Library 1.1.1
16155 * Copyright(c) 2006-2007, Ext JS, LLC.
16157 * Originally Released Under LGPL - original licence link has changed is not relivant.
16160 * <script type="text/javascript">
16165 * The drag and drop utility provides a framework for building drag and drop
16166 * applications. In addition to enabling drag and drop for specific elements,
16167 * the drag and drop elements are tracked by the manager class, and the
16168 * interactions between the various elements are tracked during the drag and
16169 * the implementing code is notified about these important moments.
16172 // Only load the library once. Rewriting the manager class would orphan
16173 // existing drag and drop instances.
16174 if (!Roo.dd.DragDropMgr) {
16177 * @class Roo.dd.DragDropMgr
16178 * DragDropMgr is a singleton that tracks the element interaction for
16179 * all DragDrop items in the window. Generally, you will not call
16180 * this class directly, but it does have helper methods that could
16181 * be useful in your DragDrop implementations.
16184 Roo.dd.DragDropMgr = function() {
16186 var Event = Roo.EventManager;
16191 * Two dimensional Array of registered DragDrop objects. The first
16192 * dimension is the DragDrop item group, the second the DragDrop
16195 * @type {string: string}
16202 * Array of element ids defined as drag handles. Used to determine
16203 * if the element that generated the mousedown event is actually the
16204 * handle and not the html element itself.
16205 * @property handleIds
16206 * @type {string: string}
16213 * the DragDrop object that is currently being dragged
16214 * @property dragCurrent
16222 * the DragDrop object(s) that are being hovered over
16223 * @property dragOvers
16231 * the X distance between the cursor and the object being dragged
16240 * the Y distance between the cursor and the object being dragged
16249 * Flag to determine if we should prevent the default behavior of the
16250 * events we define. By default this is true, but this can be set to
16251 * false if you need the default behavior (not recommended)
16252 * @property preventDefault
16256 preventDefault: true,
16259 * Flag to determine if we should stop the propagation of the events
16260 * we generate. This is true by default but you may want to set it to
16261 * false if the html element contains other features that require the
16263 * @property stopPropagation
16267 stopPropagation: true,
16270 * Internal flag that is set to true when drag and drop has been
16272 * @property initialized
16279 * All drag and drop can be disabled.
16287 * Called the first time an element is registered.
16293 this.initialized = true;
16297 * In point mode, drag and drop interaction is defined by the
16298 * location of the cursor during the drag/drop
16306 * In intersect mode, drag and drop interactio nis defined by the
16307 * overlap of two or more drag and drop objects.
16308 * @property INTERSECT
16315 * The current drag and drop mode. Default: POINT
16323 * Runs method on all drag and drop objects
16324 * @method _execOnAll
16328 _execOnAll: function(sMethod, args) {
16329 for (var i in this.ids) {
16330 for (var j in this.ids[i]) {
16331 var oDD = this.ids[i][j];
16332 if (! this.isTypeOfDD(oDD)) {
16335 oDD[sMethod].apply(oDD, args);
16341 * Drag and drop initialization. Sets up the global event handlers
16346 _onLoad: function() {
16351 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16352 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16353 Event.on(window, "unload", this._onUnload, this, true);
16354 Event.on(window, "resize", this._onResize, this, true);
16355 // Event.on(window, "mouseout", this._test);
16360 * Reset constraints on all drag and drop objs
16361 * @method _onResize
16365 _onResize: function(e) {
16366 this._execOnAll("resetConstraints", []);
16370 * Lock all drag and drop functionality
16374 lock: function() { this.locked = true; },
16377 * Unlock all drag and drop functionality
16381 unlock: function() { this.locked = false; },
16384 * Is drag and drop locked?
16386 * @return {boolean} True if drag and drop is locked, false otherwise.
16389 isLocked: function() { return this.locked; },
16392 * Location cache that is set for all drag drop objects when a drag is
16393 * initiated, cleared when the drag is finished.
16394 * @property locationCache
16401 * Set useCache to false if you want to force object the lookup of each
16402 * drag and drop linked element constantly during a drag.
16403 * @property useCache
16410 * The number of pixels that the mouse needs to move after the
16411 * mousedown before the drag is initiated. Default=3;
16412 * @property clickPixelThresh
16416 clickPixelThresh: 3,
16419 * The number of milliseconds after the mousedown event to initiate the
16420 * drag if we don't get a mouseup event. Default=1000
16421 * @property clickTimeThresh
16425 clickTimeThresh: 350,
16428 * Flag that indicates that either the drag pixel threshold or the
16429 * mousdown time threshold has been met
16430 * @property dragThreshMet
16435 dragThreshMet: false,
16438 * Timeout used for the click time threshold
16439 * @property clickTimeout
16444 clickTimeout: null,
16447 * The X position of the mousedown event stored for later use when a
16448 * drag threshold is met.
16457 * The Y position of the mousedown event stored for later use when a
16458 * drag threshold is met.
16467 * Each DragDrop instance must be registered with the DragDropMgr.
16468 * This is executed in DragDrop.init()
16469 * @method regDragDrop
16470 * @param {DragDrop} oDD the DragDrop object to register
16471 * @param {String} sGroup the name of the group this element belongs to
16474 regDragDrop: function(oDD, sGroup) {
16475 if (!this.initialized) { this.init(); }
16477 if (!this.ids[sGroup]) {
16478 this.ids[sGroup] = {};
16480 this.ids[sGroup][oDD.id] = oDD;
16484 * Removes the supplied dd instance from the supplied group. Executed
16485 * by DragDrop.removeFromGroup, so don't call this function directly.
16486 * @method removeDDFromGroup
16490 removeDDFromGroup: function(oDD, sGroup) {
16491 if (!this.ids[sGroup]) {
16492 this.ids[sGroup] = {};
16495 var obj = this.ids[sGroup];
16496 if (obj && obj[oDD.id]) {
16497 delete obj[oDD.id];
16502 * Unregisters a drag and drop item. This is executed in
16503 * DragDrop.unreg, use that method instead of calling this directly.
16508 _remove: function(oDD) {
16509 for (var g in oDD.groups) {
16510 if (g && this.ids[g][oDD.id]) {
16511 delete this.ids[g][oDD.id];
16514 delete this.handleIds[oDD.id];
16518 * Each DragDrop handle element must be registered. This is done
16519 * automatically when executing DragDrop.setHandleElId()
16520 * @method regHandle
16521 * @param {String} sDDId the DragDrop id this element is a handle for
16522 * @param {String} sHandleId the id of the element that is the drag
16526 regHandle: function(sDDId, sHandleId) {
16527 if (!this.handleIds[sDDId]) {
16528 this.handleIds[sDDId] = {};
16530 this.handleIds[sDDId][sHandleId] = sHandleId;
16534 * Utility function to determine if a given element has been
16535 * registered as a drag drop item.
16536 * @method isDragDrop
16537 * @param {String} id the element id to check
16538 * @return {boolean} true if this element is a DragDrop item,
16542 isDragDrop: function(id) {
16543 return ( this.getDDById(id) ) ? true : false;
16547 * Returns the drag and drop instances that are in all groups the
16548 * passed in instance belongs to.
16549 * @method getRelated
16550 * @param {DragDrop} p_oDD the obj to get related data for
16551 * @param {boolean} bTargetsOnly if true, only return targetable objs
16552 * @return {DragDrop[]} the related instances
16555 getRelated: function(p_oDD, bTargetsOnly) {
16557 for (var i in p_oDD.groups) {
16558 for (j in this.ids[i]) {
16559 var dd = this.ids[i][j];
16560 if (! this.isTypeOfDD(dd)) {
16563 if (!bTargetsOnly || dd.isTarget) {
16564 oDDs[oDDs.length] = dd;
16573 * Returns true if the specified dd target is a legal target for
16574 * the specifice drag obj
16575 * @method isLegalTarget
16576 * @param {DragDrop} the drag obj
16577 * @param {DragDrop} the target
16578 * @return {boolean} true if the target is a legal target for the
16582 isLegalTarget: function (oDD, oTargetDD) {
16583 var targets = this.getRelated(oDD, true);
16584 for (var i=0, len=targets.length;i<len;++i) {
16585 if (targets[i].id == oTargetDD.id) {
16594 * My goal is to be able to transparently determine if an object is
16595 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16596 * returns "object", oDD.constructor.toString() always returns
16597 * "DragDrop" and not the name of the subclass. So for now it just
16598 * evaluates a well-known variable in DragDrop.
16599 * @method isTypeOfDD
16600 * @param {Object} the object to evaluate
16601 * @return {boolean} true if typeof oDD = DragDrop
16604 isTypeOfDD: function (oDD) {
16605 return (oDD && oDD.__ygDragDrop);
16609 * Utility function to determine if a given element has been
16610 * registered as a drag drop handle for the given Drag Drop object.
16612 * @param {String} id the element id to check
16613 * @return {boolean} true if this element is a DragDrop handle, false
16617 isHandle: function(sDDId, sHandleId) {
16618 return ( this.handleIds[sDDId] &&
16619 this.handleIds[sDDId][sHandleId] );
16623 * Returns the DragDrop instance for a given id
16624 * @method getDDById
16625 * @param {String} id the id of the DragDrop object
16626 * @return {DragDrop} the drag drop object, null if it is not found
16629 getDDById: function(id) {
16630 for (var i in this.ids) {
16631 if (this.ids[i][id]) {
16632 return this.ids[i][id];
16639 * Fired after a registered DragDrop object gets the mousedown event.
16640 * Sets up the events required to track the object being dragged
16641 * @method handleMouseDown
16642 * @param {Event} e the event
16643 * @param oDD the DragDrop object being dragged
16647 handleMouseDown: function(e, oDD) {
16649 Roo.QuickTips.disable();
16651 this.currentTarget = e.getTarget();
16653 this.dragCurrent = oDD;
16655 var el = oDD.getEl();
16657 // track start position
16658 this.startX = e.getPageX();
16659 this.startY = e.getPageY();
16661 this.deltaX = this.startX - el.offsetLeft;
16662 this.deltaY = this.startY - el.offsetTop;
16664 this.dragThreshMet = false;
16666 this.clickTimeout = setTimeout(
16668 var DDM = Roo.dd.DDM;
16669 DDM.startDrag(DDM.startX, DDM.startY);
16671 this.clickTimeThresh );
16675 * Fired when either the drag pixel threshol or the mousedown hold
16676 * time threshold has been met.
16677 * @method startDrag
16678 * @param x {int} the X position of the original mousedown
16679 * @param y {int} the Y position of the original mousedown
16682 startDrag: function(x, y) {
16683 clearTimeout(this.clickTimeout);
16684 if (this.dragCurrent) {
16685 this.dragCurrent.b4StartDrag(x, y);
16686 this.dragCurrent.startDrag(x, y);
16688 this.dragThreshMet = true;
16692 * Internal function to handle the mouseup event. Will be invoked
16693 * from the context of the document.
16694 * @method handleMouseUp
16695 * @param {Event} e the event
16699 handleMouseUp: function(e) {
16702 Roo.QuickTips.enable();
16704 if (! this.dragCurrent) {
16708 clearTimeout(this.clickTimeout);
16710 if (this.dragThreshMet) {
16711 this.fireEvents(e, true);
16721 * Utility to stop event propagation and event default, if these
16722 * features are turned on.
16723 * @method stopEvent
16724 * @param {Event} e the event as returned by this.getEvent()
16727 stopEvent: function(e){
16728 if(this.stopPropagation) {
16729 e.stopPropagation();
16732 if (this.preventDefault) {
16733 e.preventDefault();
16738 * Internal function to clean up event handlers after the drag
16739 * operation is complete
16741 * @param {Event} e the event
16745 stopDrag: function(e) {
16746 // Fire the drag end event for the item that was dragged
16747 if (this.dragCurrent) {
16748 if (this.dragThreshMet) {
16749 this.dragCurrent.b4EndDrag(e);
16750 this.dragCurrent.endDrag(e);
16753 this.dragCurrent.onMouseUp(e);
16756 this.dragCurrent = null;
16757 this.dragOvers = {};
16761 * Internal function to handle the mousemove event. Will be invoked
16762 * from the context of the html element.
16764 * @TODO figure out what we can do about mouse events lost when the
16765 * user drags objects beyond the window boundary. Currently we can
16766 * detect this in internet explorer by verifying that the mouse is
16767 * down during the mousemove event. Firefox doesn't give us the
16768 * button state on the mousemove event.
16769 * @method handleMouseMove
16770 * @param {Event} e the event
16774 handleMouseMove: function(e) {
16775 if (! this.dragCurrent) {
16779 // var button = e.which || e.button;
16781 // check for IE mouseup outside of page boundary
16782 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16784 return this.handleMouseUp(e);
16787 if (!this.dragThreshMet) {
16788 var diffX = Math.abs(this.startX - e.getPageX());
16789 var diffY = Math.abs(this.startY - e.getPageY());
16790 if (diffX > this.clickPixelThresh ||
16791 diffY > this.clickPixelThresh) {
16792 this.startDrag(this.startX, this.startY);
16796 if (this.dragThreshMet) {
16797 this.dragCurrent.b4Drag(e);
16798 this.dragCurrent.onDrag(e);
16799 if(!this.dragCurrent.moveOnly){
16800 this.fireEvents(e, false);
16810 * Iterates over all of the DragDrop elements to find ones we are
16811 * hovering over or dropping on
16812 * @method fireEvents
16813 * @param {Event} e the event
16814 * @param {boolean} isDrop is this a drop op or a mouseover op?
16818 fireEvents: function(e, isDrop) {
16819 var dc = this.dragCurrent;
16821 // If the user did the mouse up outside of the window, we could
16822 // get here even though we have ended the drag.
16823 if (!dc || dc.isLocked()) {
16827 var pt = e.getPoint();
16829 // cache the previous dragOver array
16835 var enterEvts = [];
16837 // Check to see if the object(s) we were hovering over is no longer
16838 // being hovered over so we can fire the onDragOut event
16839 for (var i in this.dragOvers) {
16841 var ddo = this.dragOvers[i];
16843 if (! this.isTypeOfDD(ddo)) {
16847 if (! this.isOverTarget(pt, ddo, this.mode)) {
16848 outEvts.push( ddo );
16851 oldOvers[i] = true;
16852 delete this.dragOvers[i];
16855 for (var sGroup in dc.groups) {
16857 if ("string" != typeof sGroup) {
16861 for (i in this.ids[sGroup]) {
16862 var oDD = this.ids[sGroup][i];
16863 if (! this.isTypeOfDD(oDD)) {
16867 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16868 if (this.isOverTarget(pt, oDD, this.mode)) {
16869 // look for drop interactions
16871 dropEvts.push( oDD );
16872 // look for drag enter and drag over interactions
16875 // initial drag over: dragEnter fires
16876 if (!oldOvers[oDD.id]) {
16877 enterEvts.push( oDD );
16878 // subsequent drag overs: dragOver fires
16880 overEvts.push( oDD );
16883 this.dragOvers[oDD.id] = oDD;
16891 if (outEvts.length) {
16892 dc.b4DragOut(e, outEvts);
16893 dc.onDragOut(e, outEvts);
16896 if (enterEvts.length) {
16897 dc.onDragEnter(e, enterEvts);
16900 if (overEvts.length) {
16901 dc.b4DragOver(e, overEvts);
16902 dc.onDragOver(e, overEvts);
16905 if (dropEvts.length) {
16906 dc.b4DragDrop(e, dropEvts);
16907 dc.onDragDrop(e, dropEvts);
16911 // fire dragout events
16913 for (i=0, len=outEvts.length; i<len; ++i) {
16914 dc.b4DragOut(e, outEvts[i].id);
16915 dc.onDragOut(e, outEvts[i].id);
16918 // fire enter events
16919 for (i=0,len=enterEvts.length; i<len; ++i) {
16920 // dc.b4DragEnter(e, oDD.id);
16921 dc.onDragEnter(e, enterEvts[i].id);
16924 // fire over events
16925 for (i=0,len=overEvts.length; i<len; ++i) {
16926 dc.b4DragOver(e, overEvts[i].id);
16927 dc.onDragOver(e, overEvts[i].id);
16930 // fire drop events
16931 for (i=0, len=dropEvts.length; i<len; ++i) {
16932 dc.b4DragDrop(e, dropEvts[i].id);
16933 dc.onDragDrop(e, dropEvts[i].id);
16938 // notify about a drop that did not find a target
16939 if (isDrop && !dropEvts.length) {
16940 dc.onInvalidDrop(e);
16946 * Helper function for getting the best match from the list of drag
16947 * and drop objects returned by the drag and drop events when we are
16948 * in INTERSECT mode. It returns either the first object that the
16949 * cursor is over, or the object that has the greatest overlap with
16950 * the dragged element.
16951 * @method getBestMatch
16952 * @param {DragDrop[]} dds The array of drag and drop objects
16954 * @return {DragDrop} The best single match
16957 getBestMatch: function(dds) {
16959 // Return null if the input is not what we expect
16960 //if (!dds || !dds.length || dds.length == 0) {
16962 // If there is only one item, it wins
16963 //} else if (dds.length == 1) {
16965 var len = dds.length;
16970 // Loop through the targeted items
16971 for (var i=0; i<len; ++i) {
16973 // If the cursor is over the object, it wins. If the
16974 // cursor is over multiple matches, the first one we come
16976 if (dd.cursorIsOver) {
16979 // Otherwise the object with the most overlap wins
16982 winner.overlap.getArea() < dd.overlap.getArea()) {
16993 * Refreshes the cache of the top-left and bottom-right points of the
16994 * drag and drop objects in the specified group(s). This is in the
16995 * format that is stored in the drag and drop instance, so typical
16998 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
17002 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
17004 * @TODO this really should be an indexed array. Alternatively this
17005 * method could accept both.
17006 * @method refreshCache
17007 * @param {Object} groups an associative array of groups to refresh
17010 refreshCache: function(groups) {
17011 for (var sGroup in groups) {
17012 if ("string" != typeof sGroup) {
17015 for (var i in this.ids[sGroup]) {
17016 var oDD = this.ids[sGroup][i];
17018 if (this.isTypeOfDD(oDD)) {
17019 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
17020 var loc = this.getLocation(oDD);
17022 this.locationCache[oDD.id] = loc;
17024 delete this.locationCache[oDD.id];
17025 // this will unregister the drag and drop object if
17026 // the element is not in a usable state
17035 * This checks to make sure an element exists and is in the DOM. The
17036 * main purpose is to handle cases where innerHTML is used to remove
17037 * drag and drop objects from the DOM. IE provides an 'unspecified
17038 * error' when trying to access the offsetParent of such an element
17040 * @param {HTMLElement} el the element to check
17041 * @return {boolean} true if the element looks usable
17044 verifyEl: function(el) {
17049 parent = el.offsetParent;
17052 parent = el.offsetParent;
17063 * Returns a Region object containing the drag and drop element's position
17064 * and size, including the padding configured for it
17065 * @method getLocation
17066 * @param {DragDrop} oDD the drag and drop object to get the
17068 * @return {Roo.lib.Region} a Region object representing the total area
17069 * the element occupies, including any padding
17070 * the instance is configured for.
17073 getLocation: function(oDD) {
17074 if (! this.isTypeOfDD(oDD)) {
17078 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17081 pos= Roo.lib.Dom.getXY(el);
17089 x2 = x1 + el.offsetWidth;
17091 y2 = y1 + el.offsetHeight;
17093 t = y1 - oDD.padding[0];
17094 r = x2 + oDD.padding[1];
17095 b = y2 + oDD.padding[2];
17096 l = x1 - oDD.padding[3];
17098 return new Roo.lib.Region( t, r, b, l );
17102 * Checks the cursor location to see if it over the target
17103 * @method isOverTarget
17104 * @param {Roo.lib.Point} pt The point to evaluate
17105 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17106 * @return {boolean} true if the mouse is over the target
17110 isOverTarget: function(pt, oTarget, intersect) {
17111 // use cache if available
17112 var loc = this.locationCache[oTarget.id];
17113 if (!loc || !this.useCache) {
17114 loc = this.getLocation(oTarget);
17115 this.locationCache[oTarget.id] = loc;
17123 oTarget.cursorIsOver = loc.contains( pt );
17125 // DragDrop is using this as a sanity check for the initial mousedown
17126 // in this case we are done. In POINT mode, if the drag obj has no
17127 // contraints, we are also done. Otherwise we need to evaluate the
17128 // location of the target as related to the actual location of the
17129 // dragged element.
17130 var dc = this.dragCurrent;
17131 if (!dc || !dc.getTargetCoord ||
17132 (!intersect && !dc.constrainX && !dc.constrainY)) {
17133 return oTarget.cursorIsOver;
17136 oTarget.overlap = null;
17138 // Get the current location of the drag element, this is the
17139 // location of the mouse event less the delta that represents
17140 // where the original mousedown happened on the element. We
17141 // need to consider constraints and ticks as well.
17142 var pos = dc.getTargetCoord(pt.x, pt.y);
17144 var el = dc.getDragEl();
17145 var curRegion = new Roo.lib.Region( pos.y,
17146 pos.x + el.offsetWidth,
17147 pos.y + el.offsetHeight,
17150 var overlap = curRegion.intersect(loc);
17153 oTarget.overlap = overlap;
17154 return (intersect) ? true : oTarget.cursorIsOver;
17161 * unload event handler
17162 * @method _onUnload
17166 _onUnload: function(e, me) {
17167 Roo.dd.DragDropMgr.unregAll();
17171 * Cleans up the drag and drop events and objects.
17176 unregAll: function() {
17178 if (this.dragCurrent) {
17180 this.dragCurrent = null;
17183 this._execOnAll("unreg", []);
17185 for (i in this.elementCache) {
17186 delete this.elementCache[i];
17189 this.elementCache = {};
17194 * A cache of DOM elements
17195 * @property elementCache
17202 * Get the wrapper for the DOM element specified
17203 * @method getElWrapper
17204 * @param {String} id the id of the element to get
17205 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17207 * @deprecated This wrapper isn't that useful
17210 getElWrapper: function(id) {
17211 var oWrapper = this.elementCache[id];
17212 if (!oWrapper || !oWrapper.el) {
17213 oWrapper = this.elementCache[id] =
17214 new this.ElementWrapper(Roo.getDom(id));
17220 * Returns the actual DOM element
17221 * @method getElement
17222 * @param {String} id the id of the elment to get
17223 * @return {Object} The element
17224 * @deprecated use Roo.getDom instead
17227 getElement: function(id) {
17228 return Roo.getDom(id);
17232 * Returns the style property for the DOM element (i.e.,
17233 * document.getElById(id).style)
17235 * @param {String} id the id of the elment to get
17236 * @return {Object} The style property of the element
17237 * @deprecated use Roo.getDom instead
17240 getCss: function(id) {
17241 var el = Roo.getDom(id);
17242 return (el) ? el.style : null;
17246 * Inner class for cached elements
17247 * @class DragDropMgr.ElementWrapper
17252 ElementWrapper: function(el) {
17257 this.el = el || null;
17262 this.id = this.el && el.id;
17264 * A reference to the style property
17267 this.css = this.el && el.style;
17271 * Returns the X position of an html element
17273 * @param el the element for which to get the position
17274 * @return {int} the X coordinate
17276 * @deprecated use Roo.lib.Dom.getX instead
17279 getPosX: function(el) {
17280 return Roo.lib.Dom.getX(el);
17284 * Returns the Y position of an html element
17286 * @param el the element for which to get the position
17287 * @return {int} the Y coordinate
17288 * @deprecated use Roo.lib.Dom.getY instead
17291 getPosY: function(el) {
17292 return Roo.lib.Dom.getY(el);
17296 * Swap two nodes. In IE, we use the native method, for others we
17297 * emulate the IE behavior
17299 * @param n1 the first node to swap
17300 * @param n2 the other node to swap
17303 swapNode: function(n1, n2) {
17307 var p = n2.parentNode;
17308 var s = n2.nextSibling;
17311 p.insertBefore(n1, n2);
17312 } else if (n2 == n1.nextSibling) {
17313 p.insertBefore(n2, n1);
17315 n1.parentNode.replaceChild(n2, n1);
17316 p.insertBefore(n1, s);
17322 * Returns the current scroll position
17323 * @method getScroll
17327 getScroll: function () {
17328 var t, l, dde=document.documentElement, db=document.body;
17329 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17331 l = dde.scrollLeft;
17338 return { top: t, left: l };
17342 * Returns the specified element style property
17344 * @param {HTMLElement} el the element
17345 * @param {string} styleProp the style property
17346 * @return {string} The value of the style property
17347 * @deprecated use Roo.lib.Dom.getStyle
17350 getStyle: function(el, styleProp) {
17351 return Roo.fly(el).getStyle(styleProp);
17355 * Gets the scrollTop
17356 * @method getScrollTop
17357 * @return {int} the document's scrollTop
17360 getScrollTop: function () { return this.getScroll().top; },
17363 * Gets the scrollLeft
17364 * @method getScrollLeft
17365 * @return {int} the document's scrollTop
17368 getScrollLeft: function () { return this.getScroll().left; },
17371 * Sets the x/y position of an element to the location of the
17374 * @param {HTMLElement} moveEl The element to move
17375 * @param {HTMLElement} targetEl The position reference element
17378 moveToEl: function (moveEl, targetEl) {
17379 var aCoord = Roo.lib.Dom.getXY(targetEl);
17380 Roo.lib.Dom.setXY(moveEl, aCoord);
17384 * Numeric array sort function
17385 * @method numericSort
17388 numericSort: function(a, b) { return (a - b); },
17392 * @property _timeoutCount
17399 * Trying to make the load order less important. Without this we get
17400 * an error if this file is loaded before the Event Utility.
17401 * @method _addListeners
17405 _addListeners: function() {
17406 var DDM = Roo.dd.DDM;
17407 if ( Roo.lib.Event && document ) {
17410 if (DDM._timeoutCount > 2000) {
17412 setTimeout(DDM._addListeners, 10);
17413 if (document && document.body) {
17414 DDM._timeoutCount += 1;
17421 * Recursively searches the immediate parent and all child nodes for
17422 * the handle element in order to determine wheter or not it was
17424 * @method handleWasClicked
17425 * @param node the html element to inspect
17428 handleWasClicked: function(node, id) {
17429 if (this.isHandle(id, node.id)) {
17432 // check to see if this is a text node child of the one we want
17433 var p = node.parentNode;
17436 if (this.isHandle(id, p.id)) {
17451 // shorter alias, save a few bytes
17452 Roo.dd.DDM = Roo.dd.DragDropMgr;
17453 Roo.dd.DDM._addListeners();
17457 * Ext JS Library 1.1.1
17458 * Copyright(c) 2006-2007, Ext JS, LLC.
17460 * Originally Released Under LGPL - original licence link has changed is not relivant.
17463 * <script type="text/javascript">
17468 * A DragDrop implementation where the linked element follows the
17469 * mouse cursor during a drag.
17470 * @extends Roo.dd.DragDrop
17472 * @param {String} id the id of the linked element
17473 * @param {String} sGroup the group of related DragDrop items
17474 * @param {object} config an object containing configurable attributes
17475 * Valid properties for DD:
17478 Roo.dd.DD = function(id, sGroup, config) {
17480 this.init(id, sGroup, config);
17484 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17487 * When set to true, the utility automatically tries to scroll the browser
17488 * window wehn a drag and drop element is dragged near the viewport boundary.
17489 * Defaults to true.
17496 * Sets the pointer offset to the distance between the linked element's top
17497 * left corner and the location the element was clicked
17498 * @method autoOffset
17499 * @param {int} iPageX the X coordinate of the click
17500 * @param {int} iPageY the Y coordinate of the click
17502 autoOffset: function(iPageX, iPageY) {
17503 var x = iPageX - this.startPageX;
17504 var y = iPageY - this.startPageY;
17505 this.setDelta(x, y);
17509 * Sets the pointer offset. You can call this directly to force the
17510 * offset to be in a particular location (e.g., pass in 0,0 to set it
17511 * to the center of the object)
17513 * @param {int} iDeltaX the distance from the left
17514 * @param {int} iDeltaY the distance from the top
17516 setDelta: function(iDeltaX, iDeltaY) {
17517 this.deltaX = iDeltaX;
17518 this.deltaY = iDeltaY;
17522 * Sets the drag element to the location of the mousedown or click event,
17523 * maintaining the cursor location relative to the location on the element
17524 * that was clicked. Override this if you want to place the element in a
17525 * location other than where the cursor is.
17526 * @method setDragElPos
17527 * @param {int} iPageX the X coordinate of the mousedown or drag event
17528 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17530 setDragElPos: function(iPageX, iPageY) {
17531 // the first time we do this, we are going to check to make sure
17532 // the element has css positioning
17534 var el = this.getDragEl();
17535 this.alignElWithMouse(el, iPageX, iPageY);
17539 * Sets the element to the location of the mousedown or click event,
17540 * maintaining the cursor location relative to the location on the element
17541 * that was clicked. Override this if you want to place the element in a
17542 * location other than where the cursor is.
17543 * @method alignElWithMouse
17544 * @param {HTMLElement} el the element to move
17545 * @param {int} iPageX the X coordinate of the mousedown or drag event
17546 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17548 alignElWithMouse: function(el, iPageX, iPageY) {
17549 var oCoord = this.getTargetCoord(iPageX, iPageY);
17550 var fly = el.dom ? el : Roo.fly(el);
17551 if (!this.deltaSetXY) {
17552 var aCoord = [oCoord.x, oCoord.y];
17554 var newLeft = fly.getLeft(true);
17555 var newTop = fly.getTop(true);
17556 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17558 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17561 this.cachePosition(oCoord.x, oCoord.y);
17562 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17567 * Saves the most recent position so that we can reset the constraints and
17568 * tick marks on-demand. We need to know this so that we can calculate the
17569 * number of pixels the element is offset from its original position.
17570 * @method cachePosition
17571 * @param iPageX the current x position (optional, this just makes it so we
17572 * don't have to look it up again)
17573 * @param iPageY the current y position (optional, this just makes it so we
17574 * don't have to look it up again)
17576 cachePosition: function(iPageX, iPageY) {
17578 this.lastPageX = iPageX;
17579 this.lastPageY = iPageY;
17581 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17582 this.lastPageX = aCoord[0];
17583 this.lastPageY = aCoord[1];
17588 * Auto-scroll the window if the dragged object has been moved beyond the
17589 * visible window boundary.
17590 * @method autoScroll
17591 * @param {int} x the drag element's x position
17592 * @param {int} y the drag element's y position
17593 * @param {int} h the height of the drag element
17594 * @param {int} w the width of the drag element
17597 autoScroll: function(x, y, h, w) {
17600 // The client height
17601 var clientH = Roo.lib.Dom.getViewWidth();
17603 // The client width
17604 var clientW = Roo.lib.Dom.getViewHeight();
17606 // The amt scrolled down
17607 var st = this.DDM.getScrollTop();
17609 // The amt scrolled right
17610 var sl = this.DDM.getScrollLeft();
17612 // Location of the bottom of the element
17615 // Location of the right of the element
17618 // The distance from the cursor to the bottom of the visible area,
17619 // adjusted so that we don't scroll if the cursor is beyond the
17620 // element drag constraints
17621 var toBot = (clientH + st - y - this.deltaY);
17623 // The distance from the cursor to the right of the visible area
17624 var toRight = (clientW + sl - x - this.deltaX);
17627 // How close to the edge the cursor must be before we scroll
17628 // var thresh = (document.all) ? 100 : 40;
17631 // How many pixels to scroll per autoscroll op. This helps to reduce
17632 // clunky scrolling. IE is more sensitive about this ... it needs this
17633 // value to be higher.
17634 var scrAmt = (document.all) ? 80 : 30;
17636 // Scroll down if we are near the bottom of the visible page and the
17637 // obj extends below the crease
17638 if ( bot > clientH && toBot < thresh ) {
17639 window.scrollTo(sl, st + scrAmt);
17642 // Scroll up if the window is scrolled down and the top of the object
17643 // goes above the top border
17644 if ( y < st && st > 0 && y - st < thresh ) {
17645 window.scrollTo(sl, st - scrAmt);
17648 // Scroll right if the obj is beyond the right border and the cursor is
17649 // near the border.
17650 if ( right > clientW && toRight < thresh ) {
17651 window.scrollTo(sl + scrAmt, st);
17654 // Scroll left if the window has been scrolled to the right and the obj
17655 // extends past the left border
17656 if ( x < sl && sl > 0 && x - sl < thresh ) {
17657 window.scrollTo(sl - scrAmt, st);
17663 * Finds the location the element should be placed if we want to move
17664 * it to where the mouse location less the click offset would place us.
17665 * @method getTargetCoord
17666 * @param {int} iPageX the X coordinate of the click
17667 * @param {int} iPageY the Y coordinate of the click
17668 * @return an object that contains the coordinates (Object.x and Object.y)
17671 getTargetCoord: function(iPageX, iPageY) {
17674 var x = iPageX - this.deltaX;
17675 var y = iPageY - this.deltaY;
17677 if (this.constrainX) {
17678 if (x < this.minX) { x = this.minX; }
17679 if (x > this.maxX) { x = this.maxX; }
17682 if (this.constrainY) {
17683 if (y < this.minY) { y = this.minY; }
17684 if (y > this.maxY) { y = this.maxY; }
17687 x = this.getTick(x, this.xTicks);
17688 y = this.getTick(y, this.yTicks);
17695 * Sets up config options specific to this class. Overrides
17696 * Roo.dd.DragDrop, but all versions of this method through the
17697 * inheritance chain are called
17699 applyConfig: function() {
17700 Roo.dd.DD.superclass.applyConfig.call(this);
17701 this.scroll = (this.config.scroll !== false);
17705 * Event that fires prior to the onMouseDown event. Overrides
17708 b4MouseDown: function(e) {
17709 // this.resetConstraints();
17710 this.autoOffset(e.getPageX(),
17715 * Event that fires prior to the onDrag event. Overrides
17718 b4Drag: function(e) {
17719 this.setDragElPos(e.getPageX(),
17723 toString: function() {
17724 return ("DD " + this.id);
17727 //////////////////////////////////////////////////////////////////////////
17728 // Debugging ygDragDrop events that can be overridden
17729 //////////////////////////////////////////////////////////////////////////
17731 startDrag: function(x, y) {
17734 onDrag: function(e) {
17737 onDragEnter: function(e, id) {
17740 onDragOver: function(e, id) {
17743 onDragOut: function(e, id) {
17746 onDragDrop: function(e, id) {
17749 endDrag: function(e) {
17756 * Ext JS Library 1.1.1
17757 * Copyright(c) 2006-2007, Ext JS, LLC.
17759 * Originally Released Under LGPL - original licence link has changed is not relivant.
17762 * <script type="text/javascript">
17766 * @class Roo.dd.DDProxy
17767 * A DragDrop implementation that inserts an empty, bordered div into
17768 * the document that follows the cursor during drag operations. At the time of
17769 * the click, the frame div is resized to the dimensions of the linked html
17770 * element, and moved to the exact location of the linked element.
17772 * References to the "frame" element refer to the single proxy element that
17773 * was created to be dragged in place of all DDProxy elements on the
17776 * @extends Roo.dd.DD
17778 * @param {String} id the id of the linked html element
17779 * @param {String} sGroup the group of related DragDrop objects
17780 * @param {object} config an object containing configurable attributes
17781 * Valid properties for DDProxy in addition to those in DragDrop:
17782 * resizeFrame, centerFrame, dragElId
17784 Roo.dd.DDProxy = function(id, sGroup, config) {
17786 this.init(id, sGroup, config);
17792 * The default drag frame div id
17793 * @property Roo.dd.DDProxy.dragElId
17797 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17799 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17802 * By default we resize the drag frame to be the same size as the element
17803 * we want to drag (this is to get the frame effect). We can turn it off
17804 * if we want a different behavior.
17805 * @property resizeFrame
17811 * By default the frame is positioned exactly where the drag element is, so
17812 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17813 * you do not have constraints on the obj is to have the drag frame centered
17814 * around the cursor. Set centerFrame to true for this effect.
17815 * @property centerFrame
17818 centerFrame: false,
17821 * Creates the proxy element if it does not yet exist
17822 * @method createFrame
17824 createFrame: function() {
17826 var body = document.body;
17828 if (!body || !body.firstChild) {
17829 setTimeout( function() { self.createFrame(); }, 50 );
17833 var div = this.getDragEl();
17836 div = document.createElement("div");
17837 div.id = this.dragElId;
17840 s.position = "absolute";
17841 s.visibility = "hidden";
17843 s.border = "2px solid #aaa";
17846 // appendChild can blow up IE if invoked prior to the window load event
17847 // while rendering a table. It is possible there are other scenarios
17848 // that would cause this to happen as well.
17849 body.insertBefore(div, body.firstChild);
17854 * Initialization for the drag frame element. Must be called in the
17855 * constructor of all subclasses
17856 * @method initFrame
17858 initFrame: function() {
17859 this.createFrame();
17862 applyConfig: function() {
17863 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17865 this.resizeFrame = (this.config.resizeFrame !== false);
17866 this.centerFrame = (this.config.centerFrame);
17867 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17871 * Resizes the drag frame to the dimensions of the clicked object, positions
17872 * it over the object, and finally displays it
17873 * @method showFrame
17874 * @param {int} iPageX X click position
17875 * @param {int} iPageY Y click position
17878 showFrame: function(iPageX, iPageY) {
17879 var el = this.getEl();
17880 var dragEl = this.getDragEl();
17881 var s = dragEl.style;
17883 this._resizeProxy();
17885 if (this.centerFrame) {
17886 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17887 Math.round(parseInt(s.height, 10)/2) );
17890 this.setDragElPos(iPageX, iPageY);
17892 Roo.fly(dragEl).show();
17896 * The proxy is automatically resized to the dimensions of the linked
17897 * element when a drag is initiated, unless resizeFrame is set to false
17898 * @method _resizeProxy
17901 _resizeProxy: function() {
17902 if (this.resizeFrame) {
17903 var el = this.getEl();
17904 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17908 // overrides Roo.dd.DragDrop
17909 b4MouseDown: function(e) {
17910 var x = e.getPageX();
17911 var y = e.getPageY();
17912 this.autoOffset(x, y);
17913 this.setDragElPos(x, y);
17916 // overrides Roo.dd.DragDrop
17917 b4StartDrag: function(x, y) {
17918 // show the drag frame
17919 this.showFrame(x, y);
17922 // overrides Roo.dd.DragDrop
17923 b4EndDrag: function(e) {
17924 Roo.fly(this.getDragEl()).hide();
17927 // overrides Roo.dd.DragDrop
17928 // By default we try to move the element to the last location of the frame.
17929 // This is so that the default behavior mirrors that of Roo.dd.DD.
17930 endDrag: function(e) {
17932 var lel = this.getEl();
17933 var del = this.getDragEl();
17935 // Show the drag frame briefly so we can get its position
17936 del.style.visibility = "";
17939 // Hide the linked element before the move to get around a Safari
17941 lel.style.visibility = "hidden";
17942 Roo.dd.DDM.moveToEl(lel, del);
17943 del.style.visibility = "hidden";
17944 lel.style.visibility = "";
17949 beforeMove : function(){
17953 afterDrag : function(){
17957 toString: function() {
17958 return ("DDProxy " + this.id);
17964 * Ext JS Library 1.1.1
17965 * Copyright(c) 2006-2007, Ext JS, LLC.
17967 * Originally Released Under LGPL - original licence link has changed is not relivant.
17970 * <script type="text/javascript">
17974 * @class Roo.dd.DDTarget
17975 * A DragDrop implementation that does not move, but can be a drop
17976 * target. You would get the same result by simply omitting implementation
17977 * for the event callbacks, but this way we reduce the processing cost of the
17978 * event listener and the callbacks.
17979 * @extends Roo.dd.DragDrop
17981 * @param {String} id the id of the element that is a drop target
17982 * @param {String} sGroup the group of related DragDrop objects
17983 * @param {object} config an object containing configurable attributes
17984 * Valid properties for DDTarget in addition to those in
17988 Roo.dd.DDTarget = function(id, sGroup, config) {
17990 this.initTarget(id, sGroup, config);
17992 if (config.listeners || config.events) {
17993 Roo.dd.DragDrop.superclass.constructor.call(this, {
17994 listeners : config.listeners || {},
17995 events : config.events || {}
18000 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
18001 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
18002 toString: function() {
18003 return ("DDTarget " + this.id);
18008 * Ext JS Library 1.1.1
18009 * Copyright(c) 2006-2007, Ext JS, LLC.
18011 * Originally Released Under LGPL - original licence link has changed is not relivant.
18014 * <script type="text/javascript">
18019 * @class Roo.dd.ScrollManager
18020 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
18021 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
18024 Roo.dd.ScrollManager = function(){
18025 var ddm = Roo.dd.DragDropMgr;
18032 var onStop = function(e){
18037 var triggerRefresh = function(){
18038 if(ddm.dragCurrent){
18039 ddm.refreshCache(ddm.dragCurrent.groups);
18043 var doScroll = function(){
18044 if(ddm.dragCurrent){
18045 var dds = Roo.dd.ScrollManager;
18047 if(proc.el.scroll(proc.dir, dds.increment)){
18051 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18056 var clearProc = function(){
18058 clearInterval(proc.id);
18065 var startProc = function(el, dir){
18066 Roo.log('scroll startproc');
18070 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18073 var onFire = function(e, isDrop){
18075 if(isDrop || !ddm.dragCurrent){ return; }
18076 var dds = Roo.dd.ScrollManager;
18077 if(!dragEl || dragEl != ddm.dragCurrent){
18078 dragEl = ddm.dragCurrent;
18079 // refresh regions on drag start
18080 dds.refreshCache();
18083 var xy = Roo.lib.Event.getXY(e);
18084 var pt = new Roo.lib.Point(xy[0], xy[1]);
18085 for(var id in els){
18086 var el = els[id], r = el._region;
18087 if(r && r.contains(pt) && el.isScrollable()){
18088 if(r.bottom - pt.y <= dds.thresh){
18090 startProc(el, "down");
18093 }else if(r.right - pt.x <= dds.thresh){
18095 startProc(el, "left");
18098 }else if(pt.y - r.top <= dds.thresh){
18100 startProc(el, "up");
18103 }else if(pt.x - r.left <= dds.thresh){
18105 startProc(el, "right");
18114 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18115 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18119 * Registers new overflow element(s) to auto scroll
18120 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18122 register : function(el){
18123 if(el instanceof Array){
18124 for(var i = 0, len = el.length; i < len; i++) {
18125 this.register(el[i]);
18131 Roo.dd.ScrollManager.els = els;
18135 * Unregisters overflow element(s) so they are no longer scrolled
18136 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18138 unregister : function(el){
18139 if(el instanceof Array){
18140 for(var i = 0, len = el.length; i < len; i++) {
18141 this.unregister(el[i]);
18150 * The number of pixels from the edge of a container the pointer needs to be to
18151 * trigger scrolling (defaults to 25)
18157 * The number of pixels to scroll in each scroll increment (defaults to 50)
18163 * The frequency of scrolls in milliseconds (defaults to 500)
18169 * True to animate the scroll (defaults to true)
18175 * The animation duration in seconds -
18176 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18182 * Manually trigger a cache refresh.
18184 refreshCache : function(){
18185 for(var id in els){
18186 if(typeof els[id] == 'object'){ // for people extending the object prototype
18187 els[id]._region = els[id].getRegion();
18194 * Ext JS Library 1.1.1
18195 * Copyright(c) 2006-2007, Ext JS, LLC.
18197 * Originally Released Under LGPL - original licence link has changed is not relivant.
18200 * <script type="text/javascript">
18205 * @class Roo.dd.Registry
18206 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18207 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18210 Roo.dd.Registry = function(){
18213 var autoIdSeed = 0;
18215 var getId = function(el, autogen){
18216 if(typeof el == "string"){
18220 if(!id && autogen !== false){
18221 id = "roodd-" + (++autoIdSeed);
18229 * Register a drag drop element
18230 * @param {String|HTMLElement} element The id or DOM node to register
18231 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18232 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18233 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18234 * populated in the data object (if applicable):
18236 Value Description<br />
18237 --------- ------------------------------------------<br />
18238 handles Array of DOM nodes that trigger dragging<br />
18239 for the element being registered<br />
18240 isHandle True if the element passed in triggers<br />
18241 dragging itself, else false
18244 register : function(el, data){
18246 if(typeof el == "string"){
18247 el = document.getElementById(el);
18250 elements[getId(el)] = data;
18251 if(data.isHandle !== false){
18252 handles[data.ddel.id] = data;
18255 var hs = data.handles;
18256 for(var i = 0, len = hs.length; i < len; i++){
18257 handles[getId(hs[i])] = data;
18263 * Unregister a drag drop element
18264 * @param {String|HTMLElement} element The id or DOM node to unregister
18266 unregister : function(el){
18267 var id = getId(el, false);
18268 var data = elements[id];
18270 delete elements[id];
18272 var hs = data.handles;
18273 for(var i = 0, len = hs.length; i < len; i++){
18274 delete handles[getId(hs[i], false)];
18281 * Returns the handle registered for a DOM Node by id
18282 * @param {String|HTMLElement} id The DOM node or id to look up
18283 * @return {Object} handle The custom handle data
18285 getHandle : function(id){
18286 if(typeof id != "string"){ // must be element?
18289 return handles[id];
18293 * Returns the handle that is registered for the DOM node that is the target of the event
18294 * @param {Event} e The event
18295 * @return {Object} handle The custom handle data
18297 getHandleFromEvent : function(e){
18298 var t = Roo.lib.Event.getTarget(e);
18299 return t ? handles[t.id] : null;
18303 * Returns a custom data object that is registered for a DOM node by id
18304 * @param {String|HTMLElement} id The DOM node or id to look up
18305 * @return {Object} data The custom data
18307 getTarget : function(id){
18308 if(typeof id != "string"){ // must be element?
18311 return elements[id];
18315 * Returns a custom data object that is registered for the DOM node that is the target of the event
18316 * @param {Event} e The event
18317 * @return {Object} data The custom data
18319 getTargetFromEvent : function(e){
18320 var t = Roo.lib.Event.getTarget(e);
18321 return t ? elements[t.id] || handles[t.id] : null;
18326 * Ext JS Library 1.1.1
18327 * Copyright(c) 2006-2007, Ext JS, LLC.
18329 * Originally Released Under LGPL - original licence link has changed is not relivant.
18332 * <script type="text/javascript">
18337 * @class Roo.dd.StatusProxy
18338 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18339 * default drag proxy used by all Roo.dd components.
18341 * @param {Object} config
18343 Roo.dd.StatusProxy = function(config){
18344 Roo.apply(this, config);
18345 this.id = this.id || Roo.id();
18346 this.el = new Roo.Layer({
18348 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18349 {tag: "div", cls: "x-dd-drop-icon"},
18350 {tag: "div", cls: "x-dd-drag-ghost"}
18353 shadow: !config || config.shadow !== false
18355 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18356 this.dropStatus = this.dropNotAllowed;
18359 Roo.dd.StatusProxy.prototype = {
18361 * @cfg {String} dropAllowed
18362 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18364 dropAllowed : "x-dd-drop-ok",
18366 * @cfg {String} dropNotAllowed
18367 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18369 dropNotAllowed : "x-dd-drop-nodrop",
18372 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18373 * over the current target element.
18374 * @param {String} cssClass The css class for the new drop status indicator image
18376 setStatus : function(cssClass){
18377 cssClass = cssClass || this.dropNotAllowed;
18378 if(this.dropStatus != cssClass){
18379 this.el.replaceClass(this.dropStatus, cssClass);
18380 this.dropStatus = cssClass;
18385 * Resets the status indicator to the default dropNotAllowed value
18386 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18388 reset : function(clearGhost){
18389 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18390 this.dropStatus = this.dropNotAllowed;
18392 this.ghost.update("");
18397 * Updates the contents of the ghost element
18398 * @param {String} html The html that will replace the current innerHTML of the ghost element
18400 update : function(html){
18401 if(typeof html == "string"){
18402 this.ghost.update(html);
18404 this.ghost.update("");
18405 html.style.margin = "0";
18406 this.ghost.dom.appendChild(html);
18408 // ensure float = none set?? cant remember why though.
18409 var el = this.ghost.dom.firstChild;
18411 Roo.fly(el).setStyle('float', 'none');
18416 * Returns the underlying proxy {@link Roo.Layer}
18417 * @return {Roo.Layer} el
18419 getEl : function(){
18424 * Returns the ghost element
18425 * @return {Roo.Element} el
18427 getGhost : function(){
18433 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18435 hide : function(clear){
18443 * Stops the repair animation if it's currently running
18446 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18452 * Displays this proxy
18459 * Force the Layer to sync its shadow and shim positions to the element
18466 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18467 * invalid drop operation by the item being dragged.
18468 * @param {Array} xy The XY position of the element ([x, y])
18469 * @param {Function} callback The function to call after the repair is complete
18470 * @param {Object} scope The scope in which to execute the callback
18472 repair : function(xy, callback, scope){
18473 this.callback = callback;
18474 this.scope = scope;
18475 if(xy && this.animRepair !== false){
18476 this.el.addClass("x-dd-drag-repair");
18477 this.el.hideUnders(true);
18478 this.anim = this.el.shift({
18479 duration: this.repairDuration || .5,
18483 callback: this.afterRepair,
18487 this.afterRepair();
18492 afterRepair : function(){
18494 if(typeof this.callback == "function"){
18495 this.callback.call(this.scope || this);
18497 this.callback = null;
18502 * Ext JS Library 1.1.1
18503 * Copyright(c) 2006-2007, Ext JS, LLC.
18505 * Originally Released Under LGPL - original licence link has changed is not relivant.
18508 * <script type="text/javascript">
18512 * @class Roo.dd.DragSource
18513 * @extends Roo.dd.DDProxy
18514 * A simple class that provides the basic implementation needed to make any element draggable.
18516 * @param {String/HTMLElement/Element} el The container element
18517 * @param {Object} config
18519 Roo.dd.DragSource = function(el, config){
18520 this.el = Roo.get(el);
18521 this.dragData = {};
18523 Roo.apply(this, config);
18526 this.proxy = new Roo.dd.StatusProxy();
18529 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18530 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18532 this.dragging = false;
18535 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18537 * @cfg {String} dropAllowed
18538 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18540 dropAllowed : "x-dd-drop-ok",
18542 * @cfg {String} dropNotAllowed
18543 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18545 dropNotAllowed : "x-dd-drop-nodrop",
18548 * Returns the data object associated with this drag source
18549 * @return {Object} data An object containing arbitrary data
18551 getDragData : function(e){
18552 return this.dragData;
18556 onDragEnter : function(e, id){
18557 var target = Roo.dd.DragDropMgr.getDDById(id);
18558 this.cachedTarget = target;
18559 if(this.beforeDragEnter(target, e, id) !== false){
18560 if(target.isNotifyTarget){
18561 var status = target.notifyEnter(this, e, this.dragData);
18562 this.proxy.setStatus(status);
18564 this.proxy.setStatus(this.dropAllowed);
18567 if(this.afterDragEnter){
18569 * An empty function by default, but provided so that you can perform a custom action
18570 * when the dragged item enters the drop target by providing an implementation.
18571 * @param {Roo.dd.DragDrop} target The drop target
18572 * @param {Event} e The event object
18573 * @param {String} id The id of the dragged element
18574 * @method afterDragEnter
18576 this.afterDragEnter(target, e, id);
18582 * An empty function by default, but provided so that you can perform a custom action
18583 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18584 * @param {Roo.dd.DragDrop} target The drop target
18585 * @param {Event} e The event object
18586 * @param {String} id The id of the dragged element
18587 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18589 beforeDragEnter : function(target, e, id){
18594 alignElWithMouse: function() {
18595 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18600 onDragOver : function(e, id){
18601 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18602 if(this.beforeDragOver(target, e, id) !== false){
18603 if(target.isNotifyTarget){
18604 var status = target.notifyOver(this, e, this.dragData);
18605 this.proxy.setStatus(status);
18608 if(this.afterDragOver){
18610 * An empty function by default, but provided so that you can perform a custom action
18611 * while the dragged item is over the drop target by providing an implementation.
18612 * @param {Roo.dd.DragDrop} target The drop target
18613 * @param {Event} e The event object
18614 * @param {String} id The id of the dragged element
18615 * @method afterDragOver
18617 this.afterDragOver(target, e, id);
18623 * An empty function by default, but provided so that you can perform a custom action
18624 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18625 * @param {Roo.dd.DragDrop} target The drop target
18626 * @param {Event} e The event object
18627 * @param {String} id The id of the dragged element
18628 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18630 beforeDragOver : function(target, e, id){
18635 onDragOut : function(e, id){
18636 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18637 if(this.beforeDragOut(target, e, id) !== false){
18638 if(target.isNotifyTarget){
18639 target.notifyOut(this, e, this.dragData);
18641 this.proxy.reset();
18642 if(this.afterDragOut){
18644 * An empty function by default, but provided so that you can perform a custom action
18645 * after the dragged item is dragged out of the target without dropping.
18646 * @param {Roo.dd.DragDrop} target The drop target
18647 * @param {Event} e The event object
18648 * @param {String} id The id of the dragged element
18649 * @method afterDragOut
18651 this.afterDragOut(target, e, id);
18654 this.cachedTarget = null;
18658 * An empty function by default, but provided so that you can perform a custom action before the dragged
18659 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18660 * @param {Roo.dd.DragDrop} target The drop target
18661 * @param {Event} e The event object
18662 * @param {String} id The id of the dragged element
18663 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18665 beforeDragOut : function(target, e, id){
18670 onDragDrop : function(e, id){
18671 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18672 if(this.beforeDragDrop(target, e, id) !== false){
18673 if(target.isNotifyTarget){
18674 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18675 this.onValidDrop(target, e, id);
18677 this.onInvalidDrop(target, e, id);
18680 this.onValidDrop(target, e, id);
18683 if(this.afterDragDrop){
18685 * An empty function by default, but provided so that you can perform a custom action
18686 * after a valid drag drop has occurred by providing an implementation.
18687 * @param {Roo.dd.DragDrop} target The drop target
18688 * @param {Event} e The event object
18689 * @param {String} id The id of the dropped element
18690 * @method afterDragDrop
18692 this.afterDragDrop(target, e, id);
18695 delete this.cachedTarget;
18699 * An empty function by default, but provided so that you can perform a custom action before the dragged
18700 * item is dropped onto the target and optionally cancel the onDragDrop.
18701 * @param {Roo.dd.DragDrop} target The drop target
18702 * @param {Event} e The event object
18703 * @param {String} id The id of the dragged element
18704 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18706 beforeDragDrop : function(target, e, id){
18711 onValidDrop : function(target, e, id){
18713 if(this.afterValidDrop){
18715 * An empty function by default, but provided so that you can perform a custom action
18716 * after a valid drop has occurred by providing an implementation.
18717 * @param {Object} target The target DD
18718 * @param {Event} e The event object
18719 * @param {String} id The id of the dropped element
18720 * @method afterInvalidDrop
18722 this.afterValidDrop(target, e, id);
18727 getRepairXY : function(e, data){
18728 return this.el.getXY();
18732 onInvalidDrop : function(target, e, id){
18733 this.beforeInvalidDrop(target, e, id);
18734 if(this.cachedTarget){
18735 if(this.cachedTarget.isNotifyTarget){
18736 this.cachedTarget.notifyOut(this, e, this.dragData);
18738 this.cacheTarget = null;
18740 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18742 if(this.afterInvalidDrop){
18744 * An empty function by default, but provided so that you can perform a custom action
18745 * after an invalid drop has occurred by providing an implementation.
18746 * @param {Event} e The event object
18747 * @param {String} id The id of the dropped element
18748 * @method afterInvalidDrop
18750 this.afterInvalidDrop(e, id);
18755 afterRepair : function(){
18757 this.el.highlight(this.hlColor || "c3daf9");
18759 this.dragging = false;
18763 * An empty function by default, but provided so that you can perform a custom action after an invalid
18764 * drop has occurred.
18765 * @param {Roo.dd.DragDrop} target The drop target
18766 * @param {Event} e The event object
18767 * @param {String} id The id of the dragged element
18768 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18770 beforeInvalidDrop : function(target, e, id){
18775 handleMouseDown : function(e){
18776 if(this.dragging) {
18779 var data = this.getDragData(e);
18780 if(data && this.onBeforeDrag(data, e) !== false){
18781 this.dragData = data;
18783 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18788 * An empty function by default, but provided so that you can perform a custom action before the initial
18789 * drag event begins and optionally cancel it.
18790 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18791 * @param {Event} e The event object
18792 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18794 onBeforeDrag : function(data, e){
18799 * An empty function by default, but provided so that you can perform a custom action once the initial
18800 * drag event has begun. The drag cannot be canceled from this function.
18801 * @param {Number} x The x position of the click on the dragged object
18802 * @param {Number} y The y position of the click on the dragged object
18804 onStartDrag : Roo.emptyFn,
18806 // private - YUI override
18807 startDrag : function(x, y){
18808 this.proxy.reset();
18809 this.dragging = true;
18810 this.proxy.update("");
18811 this.onInitDrag(x, y);
18816 onInitDrag : function(x, y){
18817 var clone = this.el.dom.cloneNode(true);
18818 clone.id = Roo.id(); // prevent duplicate ids
18819 this.proxy.update(clone);
18820 this.onStartDrag(x, y);
18825 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18826 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18828 getProxy : function(){
18833 * Hides the drag source's {@link Roo.dd.StatusProxy}
18835 hideProxy : function(){
18837 this.proxy.reset(true);
18838 this.dragging = false;
18842 triggerCacheRefresh : function(){
18843 Roo.dd.DDM.refreshCache(this.groups);
18846 // private - override to prevent hiding
18847 b4EndDrag: function(e) {
18850 // private - override to prevent moving
18851 endDrag : function(e){
18852 this.onEndDrag(this.dragData, e);
18856 onEndDrag : function(data, e){
18859 // private - pin to cursor
18860 autoOffset : function(x, y) {
18861 this.setDelta(-12, -20);
18865 * Ext JS Library 1.1.1
18866 * Copyright(c) 2006-2007, Ext JS, LLC.
18868 * Originally Released Under LGPL - original licence link has changed is not relivant.
18871 * <script type="text/javascript">
18876 * @class Roo.dd.DropTarget
18877 * @extends Roo.dd.DDTarget
18878 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18879 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18881 * @param {String/HTMLElement/Element} el The container element
18882 * @param {Object} config
18884 Roo.dd.DropTarget = function(el, config){
18885 this.el = Roo.get(el);
18887 var listeners = false; ;
18888 if (config && config.listeners) {
18889 listeners= config.listeners;
18890 delete config.listeners;
18892 Roo.apply(this, config);
18894 if(this.containerScroll){
18895 Roo.dd.ScrollManager.register(this.el);
18899 * @scope Roo.dd.DropTarget
18904 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18905 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18906 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18908 * IMPORTANT : it should set this.overClass and this.dropAllowed
18910 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18911 * @param {Event} e The event
18912 * @param {Object} data An object containing arbitrary data supplied by the drag source
18918 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18919 * This method will be called on every mouse movement while the drag source is over the drop target.
18920 * This default implementation simply returns the dropAllowed config value.
18922 * IMPORTANT : it should set this.dropAllowed
18924 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18925 * @param {Event} e The event
18926 * @param {Object} data An object containing arbitrary data supplied by the drag source
18932 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18933 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18934 * overClass (if any) from the drop element.
18936 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18937 * @param {Event} e The event
18938 * @param {Object} data An object containing arbitrary data supplied by the drag source
18944 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18945 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18946 * implementation that does something to process the drop event and returns true so that the drag source's
18947 * repair action does not run.
18949 * IMPORTANT : it should set this.success
18951 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18952 * @param {Event} e The event
18953 * @param {Object} data An object containing arbitrary data supplied by the drag source
18959 Roo.dd.DropTarget.superclass.constructor.call( this,
18961 this.ddGroup || this.group,
18964 listeners : listeners || {}
18972 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18974 * @cfg {String} overClass
18975 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18978 * @cfg {String} ddGroup
18979 * The drag drop group to handle drop events for
18983 * @cfg {String} dropAllowed
18984 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18986 dropAllowed : "x-dd-drop-ok",
18988 * @cfg {String} dropNotAllowed
18989 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18991 dropNotAllowed : "x-dd-drop-nodrop",
18993 * @cfg {boolean} success
18994 * set this after drop listener..
18998 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18999 * if the drop point is valid for over/enter..
19006 isNotifyTarget : true,
19011 notifyEnter : function(dd, e, data)
19014 this.fireEvent('enter', dd, e, data);
19015 if(this.overClass){
19016 this.el.addClass(this.overClass);
19018 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19019 this.valid ? this.dropAllowed : this.dropNotAllowed
19026 notifyOver : function(dd, e, data)
19029 this.fireEvent('over', dd, e, data);
19030 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19031 this.valid ? this.dropAllowed : this.dropNotAllowed
19038 notifyOut : function(dd, e, data)
19040 this.fireEvent('out', dd, e, data);
19041 if(this.overClass){
19042 this.el.removeClass(this.overClass);
19049 notifyDrop : function(dd, e, data)
19051 this.success = false;
19052 this.fireEvent('drop', dd, e, data);
19053 return this.success;
19057 * Ext JS Library 1.1.1
19058 * Copyright(c) 2006-2007, Ext JS, LLC.
19060 * Originally Released Under LGPL - original licence link has changed is not relivant.
19063 * <script type="text/javascript">
19068 * @class Roo.dd.DragZone
19069 * @extends Roo.dd.DragSource
19070 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19071 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19073 * @param {String/HTMLElement/Element} el The container element
19074 * @param {Object} config
19076 Roo.dd.DragZone = function(el, config){
19077 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19078 if(this.containerScroll){
19079 Roo.dd.ScrollManager.register(this.el);
19083 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19085 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19086 * for auto scrolling during drag operations.
19089 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19090 * method after a failed drop (defaults to "c3daf9" - light blue)
19094 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19095 * for a valid target to drag based on the mouse down. Override this method
19096 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19097 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19098 * @param {EventObject} e The mouse down event
19099 * @return {Object} The dragData
19101 getDragData : function(e){
19102 return Roo.dd.Registry.getHandleFromEvent(e);
19106 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19107 * this.dragData.ddel
19108 * @param {Number} x The x position of the click on the dragged object
19109 * @param {Number} y The y position of the click on the dragged object
19110 * @return {Boolean} true to continue the drag, false to cancel
19112 onInitDrag : function(x, y){
19113 this.proxy.update(this.dragData.ddel.cloneNode(true));
19114 this.onStartDrag(x, y);
19119 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19121 afterRepair : function(){
19123 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19125 this.dragging = false;
19129 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19130 * the XY of this.dragData.ddel
19131 * @param {EventObject} e The mouse up event
19132 * @return {Array} The xy location (e.g. [100, 200])
19134 getRepairXY : function(e){
19135 return Roo.Element.fly(this.dragData.ddel).getXY();
19139 * Ext JS Library 1.1.1
19140 * Copyright(c) 2006-2007, Ext JS, LLC.
19142 * Originally Released Under LGPL - original licence link has changed is not relivant.
19145 * <script type="text/javascript">
19148 * @class Roo.dd.DropZone
19149 * @extends Roo.dd.DropTarget
19150 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19151 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19153 * @param {String/HTMLElement/Element} el The container element
19154 * @param {Object} config
19156 Roo.dd.DropZone = function(el, config){
19157 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19160 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19162 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19163 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19164 * provide your own custom lookup.
19165 * @param {Event} e The event
19166 * @return {Object} data The custom data
19168 getTargetFromEvent : function(e){
19169 return Roo.dd.Registry.getTargetFromEvent(e);
19173 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19174 * that it has registered. This method has no default implementation and should be overridden to provide
19175 * node-specific processing if necessary.
19176 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19177 * {@link #getTargetFromEvent} for this node)
19178 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19179 * @param {Event} e The event
19180 * @param {Object} data An object containing arbitrary data supplied by the drag source
19182 onNodeEnter : function(n, dd, e, data){
19187 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19188 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19189 * overridden to provide the proper feedback.
19190 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19191 * {@link #getTargetFromEvent} for this node)
19192 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19193 * @param {Event} e The event
19194 * @param {Object} data An object containing arbitrary data supplied by the drag source
19195 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19196 * underlying {@link Roo.dd.StatusProxy} can be updated
19198 onNodeOver : function(n, dd, e, data){
19199 return this.dropAllowed;
19203 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19204 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19205 * node-specific processing if necessary.
19206 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19207 * {@link #getTargetFromEvent} for this node)
19208 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19209 * @param {Event} e The event
19210 * @param {Object} data An object containing arbitrary data supplied by the drag source
19212 onNodeOut : function(n, dd, e, data){
19217 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19218 * the drop node. The default implementation returns false, so it should be overridden to provide the
19219 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19220 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19221 * {@link #getTargetFromEvent} for this node)
19222 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19223 * @param {Event} e The event
19224 * @param {Object} data An object containing arbitrary data supplied by the drag source
19225 * @return {Boolean} True if the drop was valid, else false
19227 onNodeDrop : function(n, dd, e, data){
19232 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19233 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19234 * it should be overridden to provide the proper feedback if necessary.
19235 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19236 * @param {Event} e The event
19237 * @param {Object} data An object containing arbitrary data supplied by the drag source
19238 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19239 * underlying {@link Roo.dd.StatusProxy} can be updated
19241 onContainerOver : function(dd, e, data){
19242 return this.dropNotAllowed;
19246 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19247 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19248 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19249 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19250 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19251 * @param {Event} e The event
19252 * @param {Object} data An object containing arbitrary data supplied by the drag source
19253 * @return {Boolean} True if the drop was valid, else false
19255 onContainerDrop : function(dd, e, data){
19260 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19261 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19262 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19263 * you should override this method and provide a custom implementation.
19264 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19265 * @param {Event} e The event
19266 * @param {Object} data An object containing arbitrary data supplied by the drag source
19267 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19268 * underlying {@link Roo.dd.StatusProxy} can be updated
19270 notifyEnter : function(dd, e, data){
19271 return this.dropNotAllowed;
19275 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19276 * This method will be called on every mouse movement while the drag source is over the drop zone.
19277 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19278 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19279 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19280 * registered node, it will call {@link #onContainerOver}.
19281 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19282 * @param {Event} e The event
19283 * @param {Object} data An object containing arbitrary data supplied by the drag source
19284 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19285 * underlying {@link Roo.dd.StatusProxy} can be updated
19287 notifyOver : function(dd, e, data){
19288 var n = this.getTargetFromEvent(e);
19289 if(!n){ // not over valid drop target
19290 if(this.lastOverNode){
19291 this.onNodeOut(this.lastOverNode, dd, e, data);
19292 this.lastOverNode = null;
19294 return this.onContainerOver(dd, e, data);
19296 if(this.lastOverNode != n){
19297 if(this.lastOverNode){
19298 this.onNodeOut(this.lastOverNode, dd, e, data);
19300 this.onNodeEnter(n, dd, e, data);
19301 this.lastOverNode = n;
19303 return this.onNodeOver(n, dd, e, data);
19307 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19308 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19309 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19310 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19311 * @param {Event} e The event
19312 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19314 notifyOut : function(dd, e, data){
19315 if(this.lastOverNode){
19316 this.onNodeOut(this.lastOverNode, dd, e, data);
19317 this.lastOverNode = null;
19322 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19323 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19324 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19325 * otherwise it will call {@link #onContainerDrop}.
19326 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19327 * @param {Event} e The event
19328 * @param {Object} data An object containing arbitrary data supplied by the drag source
19329 * @return {Boolean} True if the drop was valid, else false
19331 notifyDrop : function(dd, e, data){
19332 if(this.lastOverNode){
19333 this.onNodeOut(this.lastOverNode, dd, e, data);
19334 this.lastOverNode = null;
19336 var n = this.getTargetFromEvent(e);
19338 this.onNodeDrop(n, dd, e, data) :
19339 this.onContainerDrop(dd, e, data);
19343 triggerCacheRefresh : function(){
19344 Roo.dd.DDM.refreshCache(this.groups);
19348 * Ext JS Library 1.1.1
19349 * Copyright(c) 2006-2007, Ext JS, LLC.
19351 * Originally Released Under LGPL - original licence link has changed is not relivant.
19354 * <script type="text/javascript">
19359 * @class Roo.data.SortTypes
19361 * Defines the default sorting (casting?) comparison functions used when sorting data.
19363 Roo.data.SortTypes = {
19365 * Default sort that does nothing
19366 * @param {Mixed} s The value being converted
19367 * @return {Mixed} The comparison value
19369 none : function(s){
19374 * The regular expression used to strip tags
19378 stripTagsRE : /<\/?[^>]+>/gi,
19381 * Strips all HTML tags to sort on text only
19382 * @param {Mixed} s The value being converted
19383 * @return {String} The comparison value
19385 asText : function(s){
19386 return String(s).replace(this.stripTagsRE, "");
19390 * Strips all HTML tags to sort on text only - Case insensitive
19391 * @param {Mixed} s The value being converted
19392 * @return {String} The comparison value
19394 asUCText : function(s){
19395 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19399 * Case insensitive string
19400 * @param {Mixed} s The value being converted
19401 * @return {String} The comparison value
19403 asUCString : function(s) {
19404 return String(s).toUpperCase();
19409 * @param {Mixed} s The value being converted
19410 * @return {Number} The comparison value
19412 asDate : function(s) {
19416 if(s instanceof Date){
19417 return s.getTime();
19419 return Date.parse(String(s));
19424 * @param {Mixed} s The value being converted
19425 * @return {Float} The comparison value
19427 asFloat : function(s) {
19428 var val = parseFloat(String(s).replace(/,/g, ""));
19429 if(isNaN(val)) val = 0;
19435 * @param {Mixed} s The value being converted
19436 * @return {Number} The comparison value
19438 asInt : function(s) {
19439 var val = parseInt(String(s).replace(/,/g, ""));
19440 if(isNaN(val)) val = 0;
19445 * Ext JS Library 1.1.1
19446 * Copyright(c) 2006-2007, Ext JS, LLC.
19448 * Originally Released Under LGPL - original licence link has changed is not relivant.
19451 * <script type="text/javascript">
19455 * @class Roo.data.Record
19456 * Instances of this class encapsulate both record <em>definition</em> information, and record
19457 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19458 * to access Records cached in an {@link Roo.data.Store} object.<br>
19460 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19461 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19464 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19466 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19467 * {@link #create}. The parameters are the same.
19468 * @param {Array} data An associative Array of data values keyed by the field name.
19469 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19470 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19471 * not specified an integer id is generated.
19473 Roo.data.Record = function(data, id){
19474 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19479 * Generate a constructor for a specific record layout.
19480 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19481 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19482 * Each field definition object may contain the following properties: <ul>
19483 * <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,
19484 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19485 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19486 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19487 * is being used, then this is a string containing the javascript expression to reference the data relative to
19488 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19489 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19490 * this may be omitted.</p></li>
19491 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19492 * <ul><li>auto (Default, implies no conversion)</li>
19497 * <li>date</li></ul></p></li>
19498 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19499 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19500 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19501 * by the Reader into an object that will be stored in the Record. It is passed the
19502 * following parameters:<ul>
19503 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19505 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19507 * <br>usage:<br><pre><code>
19508 var TopicRecord = Roo.data.Record.create(
19509 {name: 'title', mapping: 'topic_title'},
19510 {name: 'author', mapping: 'username'},
19511 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19512 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19513 {name: 'lastPoster', mapping: 'user2'},
19514 {name: 'excerpt', mapping: 'post_text'}
19517 var myNewRecord = new TopicRecord({
19518 title: 'Do my job please',
19521 lastPost: new Date(),
19522 lastPoster: 'Animal',
19523 excerpt: 'No way dude!'
19525 myStore.add(myNewRecord);
19530 Roo.data.Record.create = function(o){
19531 var f = function(){
19532 f.superclass.constructor.apply(this, arguments);
19534 Roo.extend(f, Roo.data.Record);
19535 var p = f.prototype;
19536 p.fields = new Roo.util.MixedCollection(false, function(field){
19539 for(var i = 0, len = o.length; i < len; i++){
19540 p.fields.add(new Roo.data.Field(o[i]));
19542 f.getField = function(name){
19543 return p.fields.get(name);
19548 Roo.data.Record.AUTO_ID = 1000;
19549 Roo.data.Record.EDIT = 'edit';
19550 Roo.data.Record.REJECT = 'reject';
19551 Roo.data.Record.COMMIT = 'commit';
19553 Roo.data.Record.prototype = {
19555 * Readonly flag - true if this record has been modified.
19564 join : function(store){
19565 this.store = store;
19569 * Set the named field to the specified value.
19570 * @param {String} name The name of the field to set.
19571 * @param {Object} value The value to set the field to.
19573 set : function(name, value){
19574 if(this.data[name] == value){
19578 if(!this.modified){
19579 this.modified = {};
19581 if(typeof this.modified[name] == 'undefined'){
19582 this.modified[name] = this.data[name];
19584 this.data[name] = value;
19585 if(!this.editing && this.store){
19586 this.store.afterEdit(this);
19591 * Get the value of the named field.
19592 * @param {String} name The name of the field to get the value of.
19593 * @return {Object} The value of the field.
19595 get : function(name){
19596 return this.data[name];
19600 beginEdit : function(){
19601 this.editing = true;
19602 this.modified = {};
19606 cancelEdit : function(){
19607 this.editing = false;
19608 delete this.modified;
19612 endEdit : function(){
19613 this.editing = false;
19614 if(this.dirty && this.store){
19615 this.store.afterEdit(this);
19620 * Usually called by the {@link Roo.data.Store} which owns the Record.
19621 * Rejects all changes made to the Record since either creation, or the last commit operation.
19622 * Modified fields are reverted to their original values.
19624 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19625 * of reject operations.
19627 reject : function(){
19628 var m = this.modified;
19630 if(typeof m[n] != "function"){
19631 this.data[n] = m[n];
19634 this.dirty = false;
19635 delete this.modified;
19636 this.editing = false;
19638 this.store.afterReject(this);
19643 * Usually called by the {@link Roo.data.Store} which owns the Record.
19644 * Commits all changes made to the Record since either creation, or the last commit operation.
19646 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19647 * of commit operations.
19649 commit : function(){
19650 this.dirty = false;
19651 delete this.modified;
19652 this.editing = false;
19654 this.store.afterCommit(this);
19659 hasError : function(){
19660 return this.error != null;
19664 clearError : function(){
19669 * Creates a copy of this record.
19670 * @param {String} id (optional) A new record id if you don't want to use this record's id
19673 copy : function(newId) {
19674 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19678 * Ext JS Library 1.1.1
19679 * Copyright(c) 2006-2007, Ext JS, LLC.
19681 * Originally Released Under LGPL - original licence link has changed is not relivant.
19684 * <script type="text/javascript">
19690 * @class Roo.data.Store
19691 * @extends Roo.util.Observable
19692 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19693 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19695 * 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
19696 * has no knowledge of the format of the data returned by the Proxy.<br>
19698 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19699 * instances from the data object. These records are cached and made available through accessor functions.
19701 * Creates a new Store.
19702 * @param {Object} config A config object containing the objects needed for the Store to access data,
19703 * and read the data into Records.
19705 Roo.data.Store = function(config){
19706 this.data = new Roo.util.MixedCollection(false);
19707 this.data.getKey = function(o){
19710 this.baseParams = {};
19712 this.paramNames = {
19717 "multisort" : "_multisort"
19720 if(config && config.data){
19721 this.inlineData = config.data;
19722 delete config.data;
19725 Roo.apply(this, config);
19727 if(this.reader){ // reader passed
19728 this.reader = Roo.factory(this.reader, Roo.data);
19729 this.reader.xmodule = this.xmodule || false;
19730 if(!this.recordType){
19731 this.recordType = this.reader.recordType;
19733 if(this.reader.onMetaChange){
19734 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19738 if(this.recordType){
19739 this.fields = this.recordType.prototype.fields;
19741 this.modified = [];
19745 * @event datachanged
19746 * Fires when the data cache has changed, and a widget which is using this Store
19747 * as a Record cache should refresh its view.
19748 * @param {Store} this
19750 datachanged : true,
19752 * @event metachange
19753 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19754 * @param {Store} this
19755 * @param {Object} meta The JSON metadata
19760 * Fires when Records have been added to the Store
19761 * @param {Store} this
19762 * @param {Roo.data.Record[]} records The array of Records added
19763 * @param {Number} index The index at which the record(s) were added
19768 * Fires when a Record has been removed from the Store
19769 * @param {Store} this
19770 * @param {Roo.data.Record} record The Record that was removed
19771 * @param {Number} index The index at which the record was removed
19776 * Fires when a Record has been updated
19777 * @param {Store} this
19778 * @param {Roo.data.Record} record The Record that was updated
19779 * @param {String} operation The update operation being performed. Value may be one of:
19781 Roo.data.Record.EDIT
19782 Roo.data.Record.REJECT
19783 Roo.data.Record.COMMIT
19789 * Fires when the data cache has been cleared.
19790 * @param {Store} this
19794 * @event beforeload
19795 * Fires before a request is made for a new data object. If the beforeload handler returns false
19796 * the load action will be canceled.
19797 * @param {Store} this
19798 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19803 * Fires after a new set of Records has been loaded.
19804 * @param {Store} this
19805 * @param {Roo.data.Record[]} records The Records that were loaded
19806 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19810 * @event loadexception
19811 * Fires if an exception occurs in the Proxy during loading.
19812 * Called with the signature of the Proxy's "loadexception" event.
19813 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19816 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19817 * @param {Object} load options
19818 * @param {Object} jsonData from your request (normally this contains the Exception)
19820 loadexception : true
19824 this.proxy = Roo.factory(this.proxy, Roo.data);
19825 this.proxy.xmodule = this.xmodule || false;
19826 this.relayEvents(this.proxy, ["loadexception"]);
19828 this.sortToggle = {};
19829 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19831 Roo.data.Store.superclass.constructor.call(this);
19833 if(this.inlineData){
19834 this.loadData(this.inlineData);
19835 delete this.inlineData;
19838 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19840 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19841 * without a remote query - used by combo/forms at present.
19845 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19848 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19851 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19852 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19855 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19856 * on any HTTP request
19859 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19862 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19866 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19867 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19869 remoteSort : false,
19872 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19873 * loaded or when a record is removed. (defaults to false).
19875 pruneModifiedRecords : false,
19878 lastOptions : null,
19881 * Add Records to the Store and fires the add event.
19882 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19884 add : function(records){
19885 records = [].concat(records);
19886 for(var i = 0, len = records.length; i < len; i++){
19887 records[i].join(this);
19889 var index = this.data.length;
19890 this.data.addAll(records);
19891 this.fireEvent("add", this, records, index);
19895 * Remove a Record from the Store and fires the remove event.
19896 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19898 remove : function(record){
19899 var index = this.data.indexOf(record);
19900 this.data.removeAt(index);
19901 if(this.pruneModifiedRecords){
19902 this.modified.remove(record);
19904 this.fireEvent("remove", this, record, index);
19908 * Remove all Records from the Store and fires the clear event.
19910 removeAll : function(){
19912 if(this.pruneModifiedRecords){
19913 this.modified = [];
19915 this.fireEvent("clear", this);
19919 * Inserts Records to the Store at the given index and fires the add event.
19920 * @param {Number} index The start index at which to insert the passed Records.
19921 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19923 insert : function(index, records){
19924 records = [].concat(records);
19925 for(var i = 0, len = records.length; i < len; i++){
19926 this.data.insert(index, records[i]);
19927 records[i].join(this);
19929 this.fireEvent("add", this, records, index);
19933 * Get the index within the cache of the passed Record.
19934 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19935 * @return {Number} The index of the passed Record. Returns -1 if not found.
19937 indexOf : function(record){
19938 return this.data.indexOf(record);
19942 * Get the index within the cache of the Record with the passed id.
19943 * @param {String} id The id of the Record to find.
19944 * @return {Number} The index of the Record. Returns -1 if not found.
19946 indexOfId : function(id){
19947 return this.data.indexOfKey(id);
19951 * Get the Record with the specified id.
19952 * @param {String} id The id of the Record to find.
19953 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19955 getById : function(id){
19956 return this.data.key(id);
19960 * Get the Record at the specified index.
19961 * @param {Number} index The index of the Record to find.
19962 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19964 getAt : function(index){
19965 return this.data.itemAt(index);
19969 * Returns a range of Records between specified indices.
19970 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19971 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19972 * @return {Roo.data.Record[]} An array of Records
19974 getRange : function(start, end){
19975 return this.data.getRange(start, end);
19979 storeOptions : function(o){
19980 o = Roo.apply({}, o);
19983 this.lastOptions = o;
19987 * Loads the Record cache from the configured Proxy using the configured Reader.
19989 * If using remote paging, then the first load call must specify the <em>start</em>
19990 * and <em>limit</em> properties in the options.params property to establish the initial
19991 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19993 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19994 * and this call will return before the new data has been loaded. Perform any post-processing
19995 * in a callback function, or in a "load" event handler.</strong>
19997 * @param {Object} options An object containing properties which control loading options:<ul>
19998 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19999 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
20000 * passed the following arguments:<ul>
20001 * <li>r : Roo.data.Record[]</li>
20002 * <li>options: Options object from the load call</li>
20003 * <li>success: Boolean success indicator</li></ul></li>
20004 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
20005 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
20008 load : function(options){
20009 options = options || {};
20010 if(this.fireEvent("beforeload", this, options) !== false){
20011 this.storeOptions(options);
20012 var p = Roo.apply(options.params || {}, this.baseParams);
20013 // if meta was not loaded from remote source.. try requesting it.
20014 if (!this.reader.metaFromRemote) {
20015 p._requestMeta = 1;
20017 if(this.sortInfo && this.remoteSort){
20018 var pn = this.paramNames;
20019 p[pn["sort"]] = this.sortInfo.field;
20020 p[pn["dir"]] = this.sortInfo.direction;
20022 if (this.multiSort) {
20023 var pn = this.paramNames;
20024 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
20027 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20032 * Reloads the Record cache from the configured Proxy using the configured Reader and
20033 * the options from the last load operation performed.
20034 * @param {Object} options (optional) An object containing properties which may override the options
20035 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20036 * the most recently used options are reused).
20038 reload : function(options){
20039 this.load(Roo.applyIf(options||{}, this.lastOptions));
20043 // Called as a callback by the Reader during a load operation.
20044 loadRecords : function(o, options, success){
20045 if(!o || success === false){
20046 if(success !== false){
20047 this.fireEvent("load", this, [], options);
20049 if(options.callback){
20050 options.callback.call(options.scope || this, [], options, false);
20054 // if data returned failure - throw an exception.
20055 if (o.success === false) {
20056 // show a message if no listener is registered.
20057 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
20058 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
20060 // loadmask wil be hooked into this..
20061 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
20064 var r = o.records, t = o.totalRecords || r.length;
20065 if(!options || options.add !== true){
20066 if(this.pruneModifiedRecords){
20067 this.modified = [];
20069 for(var i = 0, len = r.length; i < len; i++){
20073 this.data = this.snapshot;
20074 delete this.snapshot;
20077 this.data.addAll(r);
20078 this.totalLength = t;
20080 this.fireEvent("datachanged", this);
20082 this.totalLength = Math.max(t, this.data.length+r.length);
20085 this.fireEvent("load", this, r, options);
20086 if(options.callback){
20087 options.callback.call(options.scope || this, r, options, true);
20093 * Loads data from a passed data block. A Reader which understands the format of the data
20094 * must have been configured in the constructor.
20095 * @param {Object} data The data block from which to read the Records. The format of the data expected
20096 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20097 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20099 loadData : function(o, append){
20100 var r = this.reader.readRecords(o);
20101 this.loadRecords(r, {add: append}, true);
20105 * Gets the number of cached records.
20107 * <em>If using paging, this may not be the total size of the dataset. If the data object
20108 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20109 * the data set size</em>
20111 getCount : function(){
20112 return this.data.length || 0;
20116 * Gets the total number of records in the dataset as returned by the server.
20118 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20119 * the dataset size</em>
20121 getTotalCount : function(){
20122 return this.totalLength || 0;
20126 * Returns the sort state of the Store as an object with two properties:
20128 field {String} The name of the field by which the Records are sorted
20129 direction {String} The sort order, "ASC" or "DESC"
20132 getSortState : function(){
20133 return this.sortInfo;
20137 applySort : function(){
20138 if(this.sortInfo && !this.remoteSort){
20139 var s = this.sortInfo, f = s.field;
20140 var st = this.fields.get(f).sortType;
20141 var fn = function(r1, r2){
20142 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20143 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20145 this.data.sort(s.direction, fn);
20146 if(this.snapshot && this.snapshot != this.data){
20147 this.snapshot.sort(s.direction, fn);
20153 * Sets the default sort column and order to be used by the next load operation.
20154 * @param {String} fieldName The name of the field to sort by.
20155 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20157 setDefaultSort : function(field, dir){
20158 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20162 * Sort the Records.
20163 * If remote sorting is used, the sort is performed on the server, and the cache is
20164 * reloaded. If local sorting is used, the cache is sorted internally.
20165 * @param {String} fieldName The name of the field to sort by.
20166 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20168 sort : function(fieldName, dir){
20169 var f = this.fields.get(fieldName);
20171 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20173 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20174 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20179 this.sortToggle[f.name] = dir;
20180 this.sortInfo = {field: f.name, direction: dir};
20181 if(!this.remoteSort){
20183 this.fireEvent("datachanged", this);
20185 this.load(this.lastOptions);
20190 * Calls the specified function for each of the Records in the cache.
20191 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20192 * Returning <em>false</em> aborts and exits the iteration.
20193 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20195 each : function(fn, scope){
20196 this.data.each(fn, scope);
20200 * Gets all records modified since the last commit. Modified records are persisted across load operations
20201 * (e.g., during paging).
20202 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20204 getModifiedRecords : function(){
20205 return this.modified;
20209 createFilterFn : function(property, value, anyMatch){
20210 if(!value.exec){ // not a regex
20211 value = String(value);
20212 if(value.length == 0){
20215 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20217 return function(r){
20218 return value.test(r.data[property]);
20223 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20224 * @param {String} property A field on your records
20225 * @param {Number} start The record index to start at (defaults to 0)
20226 * @param {Number} end The last record index to include (defaults to length - 1)
20227 * @return {Number} The sum
20229 sum : function(property, start, end){
20230 var rs = this.data.items, v = 0;
20231 start = start || 0;
20232 end = (end || end === 0) ? end : rs.length-1;
20234 for(var i = start; i <= end; i++){
20235 v += (rs[i].data[property] || 0);
20241 * Filter the records by a specified property.
20242 * @param {String} field A field on your records
20243 * @param {String/RegExp} value Either a string that the field
20244 * should start with or a RegExp to test against the field
20245 * @param {Boolean} anyMatch True to match any part not just the beginning
20247 filter : function(property, value, anyMatch){
20248 var fn = this.createFilterFn(property, value, anyMatch);
20249 return fn ? this.filterBy(fn) : this.clearFilter();
20253 * Filter by a function. The specified function will be called with each
20254 * record in this data source. If the function returns true the record is included,
20255 * otherwise it is filtered.
20256 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20257 * @param {Object} scope (optional) The scope of the function (defaults to this)
20259 filterBy : function(fn, scope){
20260 this.snapshot = this.snapshot || this.data;
20261 this.data = this.queryBy(fn, scope||this);
20262 this.fireEvent("datachanged", this);
20266 * Query the records by a specified property.
20267 * @param {String} field A field on your records
20268 * @param {String/RegExp} value Either a string that the field
20269 * should start with or a RegExp to test against the field
20270 * @param {Boolean} anyMatch True to match any part not just the beginning
20271 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20273 query : function(property, value, anyMatch){
20274 var fn = this.createFilterFn(property, value, anyMatch);
20275 return fn ? this.queryBy(fn) : this.data.clone();
20279 * Query by a function. The specified function will be called with each
20280 * record in this data source. If the function returns true the record is included
20282 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20283 * @param {Object} scope (optional) The scope of the function (defaults to this)
20284 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20286 queryBy : function(fn, scope){
20287 var data = this.snapshot || this.data;
20288 return data.filterBy(fn, scope||this);
20292 * Collects unique values for a particular dataIndex from this store.
20293 * @param {String} dataIndex The property to collect
20294 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20295 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20296 * @return {Array} An array of the unique values
20298 collect : function(dataIndex, allowNull, bypassFilter){
20299 var d = (bypassFilter === true && this.snapshot) ?
20300 this.snapshot.items : this.data.items;
20301 var v, sv, r = [], l = {};
20302 for(var i = 0, len = d.length; i < len; i++){
20303 v = d[i].data[dataIndex];
20305 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20314 * Revert to a view of the Record cache with no filtering applied.
20315 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20317 clearFilter : function(suppressEvent){
20318 if(this.snapshot && this.snapshot != this.data){
20319 this.data = this.snapshot;
20320 delete this.snapshot;
20321 if(suppressEvent !== true){
20322 this.fireEvent("datachanged", this);
20328 afterEdit : function(record){
20329 if(this.modified.indexOf(record) == -1){
20330 this.modified.push(record);
20332 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20336 afterReject : function(record){
20337 this.modified.remove(record);
20338 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20342 afterCommit : function(record){
20343 this.modified.remove(record);
20344 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20348 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20349 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20351 commitChanges : function(){
20352 var m = this.modified.slice(0);
20353 this.modified = [];
20354 for(var i = 0, len = m.length; i < len; i++){
20360 * Cancel outstanding changes on all changed records.
20362 rejectChanges : function(){
20363 var m = this.modified.slice(0);
20364 this.modified = [];
20365 for(var i = 0, len = m.length; i < len; i++){
20370 onMetaChange : function(meta, rtype, o){
20371 this.recordType = rtype;
20372 this.fields = rtype.prototype.fields;
20373 delete this.snapshot;
20374 this.sortInfo = meta.sortInfo || this.sortInfo;
20375 this.modified = [];
20376 this.fireEvent('metachange', this, this.reader.meta);
20380 * Ext JS Library 1.1.1
20381 * Copyright(c) 2006-2007, Ext JS, LLC.
20383 * Originally Released Under LGPL - original licence link has changed is not relivant.
20386 * <script type="text/javascript">
20390 * @class Roo.data.SimpleStore
20391 * @extends Roo.data.Store
20392 * Small helper class to make creating Stores from Array data easier.
20393 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20394 * @cfg {Array} fields An array of field definition objects, or field name strings.
20395 * @cfg {Array} data The multi-dimensional array of data
20397 * @param {Object} config
20399 Roo.data.SimpleStore = function(config){
20400 Roo.data.SimpleStore.superclass.constructor.call(this, {
20402 reader: new Roo.data.ArrayReader({
20405 Roo.data.Record.create(config.fields)
20407 proxy : new Roo.data.MemoryProxy(config.data)
20411 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
20413 * Ext JS Library 1.1.1
20414 * Copyright(c) 2006-2007, Ext JS, LLC.
20416 * Originally Released Under LGPL - original licence link has changed is not relivant.
20419 * <script type="text/javascript">
20424 * @extends Roo.data.Store
20425 * @class Roo.data.JsonStore
20426 * Small helper class to make creating Stores for JSON data easier. <br/>
20428 var store = new Roo.data.JsonStore({
20429 url: 'get-images.php',
20431 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20434 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20435 * JsonReader and HttpProxy (unless inline data is provided).</b>
20436 * @cfg {Array} fields An array of field definition objects, or field name strings.
20438 * @param {Object} config
20440 Roo.data.JsonStore = function(c){
20441 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20442 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20443 reader: new Roo.data.JsonReader(c, c.fields)
20446 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20448 * Ext JS Library 1.1.1
20449 * Copyright(c) 2006-2007, Ext JS, LLC.
20451 * Originally Released Under LGPL - original licence link has changed is not relivant.
20454 * <script type="text/javascript">
20458 Roo.data.Field = function(config){
20459 if(typeof config == "string"){
20460 config = {name: config};
20462 Roo.apply(this, config);
20465 this.type = "auto";
20468 var st = Roo.data.SortTypes;
20469 // named sortTypes are supported, here we look them up
20470 if(typeof this.sortType == "string"){
20471 this.sortType = st[this.sortType];
20474 // set default sortType for strings and dates
20475 if(!this.sortType){
20478 this.sortType = st.asUCString;
20481 this.sortType = st.asDate;
20484 this.sortType = st.none;
20489 var stripRe = /[\$,%]/g;
20491 // prebuilt conversion function for this field, instead of
20492 // switching every time we're reading a value
20494 var cv, dateFormat = this.dateFormat;
20499 cv = function(v){ return v; };
20502 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20506 return v !== undefined && v !== null && v !== '' ?
20507 parseInt(String(v).replace(stripRe, ""), 10) : '';
20512 return v !== undefined && v !== null && v !== '' ?
20513 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20518 cv = function(v){ return v === true || v === "true" || v == 1; };
20525 if(v instanceof Date){
20529 if(dateFormat == "timestamp"){
20530 return new Date(v*1000);
20532 return Date.parseDate(v, dateFormat);
20534 var parsed = Date.parse(v);
20535 return parsed ? new Date(parsed) : null;
20544 Roo.data.Field.prototype = {
20552 * Ext JS Library 1.1.1
20553 * Copyright(c) 2006-2007, Ext JS, LLC.
20555 * Originally Released Under LGPL - original licence link has changed is not relivant.
20558 * <script type="text/javascript">
20561 // Base class for reading structured data from a data source. This class is intended to be
20562 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20565 * @class Roo.data.DataReader
20566 * Base class for reading structured data from a data source. This class is intended to be
20567 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20570 Roo.data.DataReader = function(meta, recordType){
20574 this.recordType = recordType instanceof Array ?
20575 Roo.data.Record.create(recordType) : recordType;
20578 Roo.data.DataReader.prototype = {
20580 * Create an empty record
20581 * @param {Object} data (optional) - overlay some values
20582 * @return {Roo.data.Record} record created.
20584 newRow : function(d) {
20586 this.recordType.prototype.fields.each(function(c) {
20588 case 'int' : da[c.name] = 0; break;
20589 case 'date' : da[c.name] = new Date(); break;
20590 case 'float' : da[c.name] = 0.0; break;
20591 case 'boolean' : da[c.name] = false; break;
20592 default : da[c.name] = ""; break;
20596 return new this.recordType(Roo.apply(da, d));
20601 * Ext JS Library 1.1.1
20602 * Copyright(c) 2006-2007, Ext JS, LLC.
20604 * Originally Released Under LGPL - original licence link has changed is not relivant.
20607 * <script type="text/javascript">
20611 * @class Roo.data.DataProxy
20612 * @extends Roo.data.Observable
20613 * This class is an abstract base class for implementations which provide retrieval of
20614 * unformatted data objects.<br>
20616 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20617 * (of the appropriate type which knows how to parse the data object) to provide a block of
20618 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20620 * Custom implementations must implement the load method as described in
20621 * {@link Roo.data.HttpProxy#load}.
20623 Roo.data.DataProxy = function(){
20626 * @event beforeload
20627 * Fires before a network request is made to retrieve a data object.
20628 * @param {Object} This DataProxy object.
20629 * @param {Object} params The params parameter to the load function.
20634 * Fires before the load method's callback is called.
20635 * @param {Object} This DataProxy object.
20636 * @param {Object} o The data object.
20637 * @param {Object} arg The callback argument object passed to the load function.
20641 * @event loadexception
20642 * Fires if an Exception occurs during data retrieval.
20643 * @param {Object} This DataProxy object.
20644 * @param {Object} o The data object.
20645 * @param {Object} arg The callback argument object passed to the load function.
20646 * @param {Object} e The Exception.
20648 loadexception : true
20650 Roo.data.DataProxy.superclass.constructor.call(this);
20653 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20656 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20660 * Ext JS Library 1.1.1
20661 * Copyright(c) 2006-2007, Ext JS, LLC.
20663 * Originally Released Under LGPL - original licence link has changed is not relivant.
20666 * <script type="text/javascript">
20669 * @class Roo.data.MemoryProxy
20670 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20671 * to the Reader when its load method is called.
20673 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20675 Roo.data.MemoryProxy = function(data){
20679 Roo.data.MemoryProxy.superclass.constructor.call(this);
20683 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20685 * Load data from the requested source (in this case an in-memory
20686 * data object passed to the constructor), read the data object into
20687 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20688 * process that block using the passed callback.
20689 * @param {Object} params This parameter is not used by the MemoryProxy class.
20690 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20691 * object into a block of Roo.data.Records.
20692 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20693 * The function must be passed <ul>
20694 * <li>The Record block object</li>
20695 * <li>The "arg" argument from the load function</li>
20696 * <li>A boolean success indicator</li>
20698 * @param {Object} scope The scope in which to call the callback
20699 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20701 load : function(params, reader, callback, scope, arg){
20702 params = params || {};
20705 result = reader.readRecords(this.data);
20707 this.fireEvent("loadexception", this, arg, null, e);
20708 callback.call(scope, null, arg, false);
20711 callback.call(scope, result, arg, true);
20715 update : function(params, records){
20720 * Ext JS Library 1.1.1
20721 * Copyright(c) 2006-2007, Ext JS, LLC.
20723 * Originally Released Under LGPL - original licence link has changed is not relivant.
20726 * <script type="text/javascript">
20729 * @class Roo.data.HttpProxy
20730 * @extends Roo.data.DataProxy
20731 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20732 * configured to reference a certain URL.<br><br>
20734 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20735 * from which the running page was served.<br><br>
20737 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20739 * Be aware that to enable the browser to parse an XML document, the server must set
20740 * the Content-Type header in the HTTP response to "text/xml".
20742 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20743 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20744 * will be used to make the request.
20746 Roo.data.HttpProxy = function(conn){
20747 Roo.data.HttpProxy.superclass.constructor.call(this);
20748 // is conn a conn config or a real conn?
20750 this.useAjax = !conn || !conn.events;
20754 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20755 // thse are take from connection...
20758 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20761 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20762 * extra parameters to each request made by this object. (defaults to undefined)
20765 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20766 * to each request made by this object. (defaults to undefined)
20769 * @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)
20772 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20775 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20781 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20785 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20786 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20787 * a finer-grained basis than the DataProxy events.
20789 getConnection : function(){
20790 return this.useAjax ? Roo.Ajax : this.conn;
20794 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20795 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20796 * process that block using the passed callback.
20797 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20798 * for the request to the remote server.
20799 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20800 * object into a block of Roo.data.Records.
20801 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20802 * The function must be passed <ul>
20803 * <li>The Record block object</li>
20804 * <li>The "arg" argument from the load function</li>
20805 * <li>A boolean success indicator</li>
20807 * @param {Object} scope The scope in which to call the callback
20808 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20810 load : function(params, reader, callback, scope, arg){
20811 if(this.fireEvent("beforeload", this, params) !== false){
20813 params : params || {},
20815 callback : callback,
20820 callback : this.loadResponse,
20824 Roo.applyIf(o, this.conn);
20825 if(this.activeRequest){
20826 Roo.Ajax.abort(this.activeRequest);
20828 this.activeRequest = Roo.Ajax.request(o);
20830 this.conn.request(o);
20833 callback.call(scope||this, null, arg, false);
20838 loadResponse : function(o, success, response){
20839 delete this.activeRequest;
20841 this.fireEvent("loadexception", this, o, response);
20842 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20847 result = o.reader.read(response);
20849 this.fireEvent("loadexception", this, o, response, e);
20850 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20854 this.fireEvent("load", this, o, o.request.arg);
20855 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20859 update : function(dataSet){
20864 updateResponse : function(dataSet){
20869 * Ext JS Library 1.1.1
20870 * Copyright(c) 2006-2007, Ext JS, LLC.
20872 * Originally Released Under LGPL - original licence link has changed is not relivant.
20875 * <script type="text/javascript">
20879 * @class Roo.data.ScriptTagProxy
20880 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20881 * other than the originating domain of the running page.<br><br>
20883 * <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
20884 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20886 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20887 * source code that is used as the source inside a <script> tag.<br><br>
20889 * In order for the browser to process the returned data, the server must wrap the data object
20890 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20891 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20892 * depending on whether the callback name was passed:
20895 boolean scriptTag = false;
20896 String cb = request.getParameter("callback");
20899 response.setContentType("text/javascript");
20901 response.setContentType("application/x-json");
20903 Writer out = response.getWriter();
20905 out.write(cb + "(");
20907 out.print(dataBlock.toJsonString());
20914 * @param {Object} config A configuration object.
20916 Roo.data.ScriptTagProxy = function(config){
20917 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20918 Roo.apply(this, config);
20919 this.head = document.getElementsByTagName("head")[0];
20922 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20924 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20926 * @cfg {String} url The URL from which to request the data object.
20929 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20933 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20934 * the server the name of the callback function set up by the load call to process the returned data object.
20935 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20936 * javascript output which calls this named function passing the data object as its only parameter.
20938 callbackParam : "callback",
20940 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20941 * name to the request.
20946 * Load data from the configured URL, read the data object into
20947 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20948 * process that block using the passed callback.
20949 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20950 * for the request to the remote server.
20951 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20952 * object into a block of Roo.data.Records.
20953 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20954 * The function must be passed <ul>
20955 * <li>The Record block object</li>
20956 * <li>The "arg" argument from the load function</li>
20957 * <li>A boolean success indicator</li>
20959 * @param {Object} scope The scope in which to call the callback
20960 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20962 load : function(params, reader, callback, scope, arg){
20963 if(this.fireEvent("beforeload", this, params) !== false){
20965 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20967 var url = this.url;
20968 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20970 url += "&_dc=" + (new Date().getTime());
20972 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20975 cb : "stcCallback"+transId,
20976 scriptId : "stcScript"+transId,
20980 callback : callback,
20986 window[trans.cb] = function(o){
20987 conn.handleResponse(o, trans);
20990 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20992 if(this.autoAbort !== false){
20996 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20998 var script = document.createElement("script");
20999 script.setAttribute("src", url);
21000 script.setAttribute("type", "text/javascript");
21001 script.setAttribute("id", trans.scriptId);
21002 this.head.appendChild(script);
21004 this.trans = trans;
21006 callback.call(scope||this, null, arg, false);
21011 isLoading : function(){
21012 return this.trans ? true : false;
21016 * Abort the current server request.
21018 abort : function(){
21019 if(this.isLoading()){
21020 this.destroyTrans(this.trans);
21025 destroyTrans : function(trans, isLoaded){
21026 this.head.removeChild(document.getElementById(trans.scriptId));
21027 clearTimeout(trans.timeoutId);
21029 window[trans.cb] = undefined;
21031 delete window[trans.cb];
21034 // if hasn't been loaded, wait for load to remove it to prevent script error
21035 window[trans.cb] = function(){
21036 window[trans.cb] = undefined;
21038 delete window[trans.cb];
21045 handleResponse : function(o, trans){
21046 this.trans = false;
21047 this.destroyTrans(trans, true);
21050 result = trans.reader.readRecords(o);
21052 this.fireEvent("loadexception", this, o, trans.arg, e);
21053 trans.callback.call(trans.scope||window, null, trans.arg, false);
21056 this.fireEvent("load", this, o, trans.arg);
21057 trans.callback.call(trans.scope||window, result, trans.arg, true);
21061 handleFailure : function(trans){
21062 this.trans = false;
21063 this.destroyTrans(trans, false);
21064 this.fireEvent("loadexception", this, null, trans.arg);
21065 trans.callback.call(trans.scope||window, null, trans.arg, false);
21069 * Ext JS Library 1.1.1
21070 * Copyright(c) 2006-2007, Ext JS, LLC.
21072 * Originally Released Under LGPL - original licence link has changed is not relivant.
21075 * <script type="text/javascript">
21079 * @class Roo.data.JsonReader
21080 * @extends Roo.data.DataReader
21081 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21082 * based on mappings in a provided Roo.data.Record constructor.
21084 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21085 * in the reply previously.
21090 var RecordDef = Roo.data.Record.create([
21091 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21092 {name: 'occupation'} // This field will use "occupation" as the mapping.
21094 var myReader = new Roo.data.JsonReader({
21095 totalProperty: "results", // The property which contains the total dataset size (optional)
21096 root: "rows", // The property which contains an Array of row objects
21097 id: "id" // The property within each row object that provides an ID for the record (optional)
21101 * This would consume a JSON file like this:
21103 { 'results': 2, 'rows': [
21104 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21105 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21108 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21109 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21110 * paged from the remote server.
21111 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21112 * @cfg {String} root name of the property which contains the Array of row objects.
21113 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21115 * Create a new JsonReader
21116 * @param {Object} meta Metadata configuration options
21117 * @param {Object} recordType Either an Array of field definition objects,
21118 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21120 Roo.data.JsonReader = function(meta, recordType){
21123 // set some defaults:
21124 Roo.applyIf(meta, {
21125 totalProperty: 'total',
21126 successProperty : 'success',
21131 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21133 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21136 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21137 * Used by Store query builder to append _requestMeta to params.
21140 metaFromRemote : false,
21142 * This method is only used by a DataProxy which has retrieved data from a remote server.
21143 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21144 * @return {Object} data A data block which is used by an Roo.data.Store object as
21145 * a cache of Roo.data.Records.
21147 read : function(response){
21148 var json = response.responseText;
21150 var o = /* eval:var:o */ eval("("+json+")");
21152 throw {message: "JsonReader.read: Json object not found"};
21158 this.metaFromRemote = true;
21159 this.meta = o.metaData;
21160 this.recordType = Roo.data.Record.create(o.metaData.fields);
21161 this.onMetaChange(this.meta, this.recordType, o);
21163 return this.readRecords(o);
21166 // private function a store will implement
21167 onMetaChange : function(meta, recordType, o){
21174 simpleAccess: function(obj, subsc) {
21181 getJsonAccessor: function(){
21183 return function(expr) {
21185 return(re.test(expr))
21186 ? new Function("obj", "return obj." + expr)
21191 return Roo.emptyFn;
21196 * Create a data block containing Roo.data.Records from an XML document.
21197 * @param {Object} o An object which contains an Array of row objects in the property specified
21198 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21199 * which contains the total size of the dataset.
21200 * @return {Object} data A data block which is used by an Roo.data.Store object as
21201 * a cache of Roo.data.Records.
21203 readRecords : function(o){
21205 * After any data loads, the raw JSON data is available for further custom processing.
21209 var s = this.meta, Record = this.recordType,
21210 f = Record.prototype.fields, fi = f.items, fl = f.length;
21212 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21214 if(s.totalProperty) {
21215 this.getTotal = this.getJsonAccessor(s.totalProperty);
21217 if(s.successProperty) {
21218 this.getSuccess = this.getJsonAccessor(s.successProperty);
21220 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21222 var g = this.getJsonAccessor(s.id);
21223 this.getId = function(rec) {
21225 return (r === undefined || r === "") ? null : r;
21228 this.getId = function(){return null;};
21231 for(var jj = 0; jj < fl; jj++){
21233 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21234 this.ef[jj] = this.getJsonAccessor(map);
21238 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21239 if(s.totalProperty){
21240 var vt = parseInt(this.getTotal(o), 10);
21245 if(s.successProperty){
21246 var vs = this.getSuccess(o);
21247 if(vs === false || vs === 'false'){
21252 for(var i = 0; i < c; i++){
21255 var id = this.getId(n);
21256 for(var j = 0; j < fl; j++){
21258 var v = this.ef[j](n);
21260 Roo.log('missing convert for ' + f.name);
21264 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21266 var record = new Record(values, id);
21268 records[i] = record;
21273 totalRecords : totalRecords
21278 * Ext JS Library 1.1.1
21279 * Copyright(c) 2006-2007, Ext JS, LLC.
21281 * Originally Released Under LGPL - original licence link has changed is not relivant.
21284 * <script type="text/javascript">
21288 * @class Roo.data.XmlReader
21289 * @extends Roo.data.DataReader
21290 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21291 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21293 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21294 * header in the HTTP response must be set to "text/xml".</em>
21298 var RecordDef = Roo.data.Record.create([
21299 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21300 {name: 'occupation'} // This field will use "occupation" as the mapping.
21302 var myReader = new Roo.data.XmlReader({
21303 totalRecords: "results", // The element which contains the total dataset size (optional)
21304 record: "row", // The repeated element which contains row information
21305 id: "id" // The element within the row that provides an ID for the record (optional)
21309 * This would consume an XML file like this:
21313 <results>2</results>
21316 <name>Bill</name>
21317 <occupation>Gardener</occupation>
21321 <name>Ben</name>
21322 <occupation>Horticulturalist</occupation>
21326 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21327 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21328 * paged from the remote server.
21329 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21330 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21331 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21332 * a record identifier value.
21334 * Create a new XmlReader
21335 * @param {Object} meta Metadata configuration options
21336 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21337 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21338 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21340 Roo.data.XmlReader = function(meta, recordType){
21342 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21344 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21346 * This method is only used by a DataProxy which has retrieved data from a remote server.
21347 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21348 * to contain a method called 'responseXML' that returns an XML document object.
21349 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21350 * a cache of Roo.data.Records.
21352 read : function(response){
21353 var doc = response.responseXML;
21355 throw {message: "XmlReader.read: XML Document not available"};
21357 return this.readRecords(doc);
21361 * Create a data block containing Roo.data.Records from an XML document.
21362 * @param {Object} doc A parsed XML document.
21363 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21364 * a cache of Roo.data.Records.
21366 readRecords : function(doc){
21368 * After any data loads/reads, the raw XML Document is available for further custom processing.
21369 * @type XMLDocument
21371 this.xmlData = doc;
21372 var root = doc.documentElement || doc;
21373 var q = Roo.DomQuery;
21374 var recordType = this.recordType, fields = recordType.prototype.fields;
21375 var sid = this.meta.id;
21376 var totalRecords = 0, success = true;
21377 if(this.meta.totalRecords){
21378 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21381 if(this.meta.success){
21382 var sv = q.selectValue(this.meta.success, root, true);
21383 success = sv !== false && sv !== 'false';
21386 var ns = q.select(this.meta.record, root);
21387 for(var i = 0, len = ns.length; i < len; i++) {
21390 var id = sid ? q.selectValue(sid, n) : undefined;
21391 for(var j = 0, jlen = fields.length; j < jlen; j++){
21392 var f = fields.items[j];
21393 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21395 values[f.name] = v;
21397 var record = new recordType(values, id);
21399 records[records.length] = record;
21405 totalRecords : totalRecords || records.length
21410 * Ext JS Library 1.1.1
21411 * Copyright(c) 2006-2007, Ext JS, LLC.
21413 * Originally Released Under LGPL - original licence link has changed is not relivant.
21416 * <script type="text/javascript">
21420 * @class Roo.data.ArrayReader
21421 * @extends Roo.data.DataReader
21422 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21423 * Each element of that Array represents a row of data fields. The
21424 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21425 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21429 var RecordDef = Roo.data.Record.create([
21430 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21431 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21433 var myReader = new Roo.data.ArrayReader({
21434 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21438 * This would consume an Array like this:
21440 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21442 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21444 * Create a new JsonReader
21445 * @param {Object} meta Metadata configuration options.
21446 * @param {Object} recordType Either an Array of field definition objects
21447 * as specified to {@link Roo.data.Record#create},
21448 * or an {@link Roo.data.Record} object
21449 * created using {@link Roo.data.Record#create}.
21451 Roo.data.ArrayReader = function(meta, recordType){
21452 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21455 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21457 * Create a data block containing Roo.data.Records from an XML document.
21458 * @param {Object} o An Array of row objects which represents the dataset.
21459 * @return {Object} data A data block which is used by an Roo.data.Store object as
21460 * a cache of Roo.data.Records.
21462 readRecords : function(o){
21463 var sid = this.meta ? this.meta.id : null;
21464 var recordType = this.recordType, fields = recordType.prototype.fields;
21467 for(var i = 0; i < root.length; i++){
21470 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21471 for(var j = 0, jlen = fields.length; j < jlen; j++){
21472 var f = fields.items[j];
21473 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21474 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21476 values[f.name] = v;
21478 var record = new recordType(values, id);
21480 records[records.length] = record;
21484 totalRecords : records.length
21489 * Ext JS Library 1.1.1
21490 * Copyright(c) 2006-2007, Ext JS, LLC.
21492 * Originally Released Under LGPL - original licence link has changed is not relivant.
21495 * <script type="text/javascript">
21500 * @class Roo.data.Tree
21501 * @extends Roo.util.Observable
21502 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21503 * in the tree have most standard DOM functionality.
21505 * @param {Node} root (optional) The root node
21507 Roo.data.Tree = function(root){
21508 this.nodeHash = {};
21510 * The root node for this tree
21515 this.setRootNode(root);
21520 * Fires when a new child node is appended to a node in this tree.
21521 * @param {Tree} tree The owner tree
21522 * @param {Node} parent The parent node
21523 * @param {Node} node The newly appended node
21524 * @param {Number} index The index of the newly appended node
21529 * Fires when a child node is removed from a node in this tree.
21530 * @param {Tree} tree The owner tree
21531 * @param {Node} parent The parent node
21532 * @param {Node} node The child node removed
21537 * Fires when a node is moved to a new location in the tree
21538 * @param {Tree} tree The owner tree
21539 * @param {Node} node The node moved
21540 * @param {Node} oldParent The old parent of this node
21541 * @param {Node} newParent The new parent of this node
21542 * @param {Number} index The index it was moved to
21547 * Fires when a new child node is inserted in a node in this tree.
21548 * @param {Tree} tree The owner tree
21549 * @param {Node} parent The parent node
21550 * @param {Node} node The child node inserted
21551 * @param {Node} refNode The child node the node was inserted before
21555 * @event beforeappend
21556 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21557 * @param {Tree} tree The owner tree
21558 * @param {Node} parent The parent node
21559 * @param {Node} node The child node to be appended
21561 "beforeappend" : true,
21563 * @event beforeremove
21564 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21565 * @param {Tree} tree The owner tree
21566 * @param {Node} parent The parent node
21567 * @param {Node} node The child node to be removed
21569 "beforeremove" : true,
21571 * @event beforemove
21572 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21573 * @param {Tree} tree The owner tree
21574 * @param {Node} node The node being moved
21575 * @param {Node} oldParent The parent of the node
21576 * @param {Node} newParent The new parent the node is moving to
21577 * @param {Number} index The index it is being moved to
21579 "beforemove" : true,
21581 * @event beforeinsert
21582 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21583 * @param {Tree} tree The owner tree
21584 * @param {Node} parent The parent node
21585 * @param {Node} node The child node to be inserted
21586 * @param {Node} refNode The child node the node is being inserted before
21588 "beforeinsert" : true
21591 Roo.data.Tree.superclass.constructor.call(this);
21594 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21595 pathSeparator: "/",
21597 proxyNodeEvent : function(){
21598 return this.fireEvent.apply(this, arguments);
21602 * Returns the root node for this tree.
21605 getRootNode : function(){
21610 * Sets the root node for this tree.
21611 * @param {Node} node
21614 setRootNode : function(node){
21616 node.ownerTree = this;
21617 node.isRoot = true;
21618 this.registerNode(node);
21623 * Gets a node in this tree by its id.
21624 * @param {String} id
21627 getNodeById : function(id){
21628 return this.nodeHash[id];
21631 registerNode : function(node){
21632 this.nodeHash[node.id] = node;
21635 unregisterNode : function(node){
21636 delete this.nodeHash[node.id];
21639 toString : function(){
21640 return "[Tree"+(this.id?" "+this.id:"")+"]";
21645 * @class Roo.data.Node
21646 * @extends Roo.util.Observable
21647 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21648 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21650 * @param {Object} attributes The attributes/config for the node
21652 Roo.data.Node = function(attributes){
21654 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21657 this.attributes = attributes || {};
21658 this.leaf = this.attributes.leaf;
21660 * The node id. @type String
21662 this.id = this.attributes.id;
21664 this.id = Roo.id(null, "ynode-");
21665 this.attributes.id = this.id;
21670 * All child nodes of this node. @type Array
21672 this.childNodes = [];
21673 if(!this.childNodes.indexOf){ // indexOf is a must
21674 this.childNodes.indexOf = function(o){
21675 for(var i = 0, len = this.length; i < len; i++){
21684 * The parent node for this node. @type Node
21686 this.parentNode = null;
21688 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21690 this.firstChild = null;
21692 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21694 this.lastChild = null;
21696 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21698 this.previousSibling = null;
21700 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21702 this.nextSibling = null;
21707 * Fires when a new child node is appended
21708 * @param {Tree} tree The owner tree
21709 * @param {Node} this This node
21710 * @param {Node} node The newly appended node
21711 * @param {Number} index The index of the newly appended node
21716 * Fires when a child node is removed
21717 * @param {Tree} tree The owner tree
21718 * @param {Node} this This node
21719 * @param {Node} node The removed node
21724 * Fires when this node is moved to a new location in the tree
21725 * @param {Tree} tree The owner tree
21726 * @param {Node} this This node
21727 * @param {Node} oldParent The old parent of this node
21728 * @param {Node} newParent The new parent of this node
21729 * @param {Number} index The index it was moved to
21734 * Fires when a new child node is inserted.
21735 * @param {Tree} tree The owner tree
21736 * @param {Node} this This node
21737 * @param {Node} node The child node inserted
21738 * @param {Node} refNode The child node the node was inserted before
21742 * @event beforeappend
21743 * Fires before a new child is appended, return false to cancel the append.
21744 * @param {Tree} tree The owner tree
21745 * @param {Node} this This node
21746 * @param {Node} node The child node to be appended
21748 "beforeappend" : true,
21750 * @event beforeremove
21751 * Fires before a child is removed, return false to cancel the remove.
21752 * @param {Tree} tree The owner tree
21753 * @param {Node} this This node
21754 * @param {Node} node The child node to be removed
21756 "beforeremove" : true,
21758 * @event beforemove
21759 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21760 * @param {Tree} tree The owner tree
21761 * @param {Node} this This node
21762 * @param {Node} oldParent The parent of this node
21763 * @param {Node} newParent The new parent this node is moving to
21764 * @param {Number} index The index it is being moved to
21766 "beforemove" : true,
21768 * @event beforeinsert
21769 * Fires before a new child is inserted, return false to cancel the insert.
21770 * @param {Tree} tree The owner tree
21771 * @param {Node} this This node
21772 * @param {Node} node The child node to be inserted
21773 * @param {Node} refNode The child node the node is being inserted before
21775 "beforeinsert" : true
21777 this.listeners = this.attributes.listeners;
21778 Roo.data.Node.superclass.constructor.call(this);
21781 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21782 fireEvent : function(evtName){
21783 // first do standard event for this node
21784 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21787 // then bubble it up to the tree if the event wasn't cancelled
21788 var ot = this.getOwnerTree();
21790 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21798 * Returns true if this node is a leaf
21799 * @return {Boolean}
21801 isLeaf : function(){
21802 return this.leaf === true;
21806 setFirstChild : function(node){
21807 this.firstChild = node;
21811 setLastChild : function(node){
21812 this.lastChild = node;
21817 * Returns true if this node is the last child of its parent
21818 * @return {Boolean}
21820 isLast : function(){
21821 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21825 * Returns true if this node is the first child of its parent
21826 * @return {Boolean}
21828 isFirst : function(){
21829 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21832 hasChildNodes : function(){
21833 return !this.isLeaf() && this.childNodes.length > 0;
21837 * Insert node(s) as the last child node of this node.
21838 * @param {Node/Array} node The node or Array of nodes to append
21839 * @return {Node} The appended node if single append, or null if an array was passed
21841 appendChild : function(node){
21843 if(node instanceof Array){
21845 }else if(arguments.length > 1){
21848 // if passed an array or multiple args do them one by one
21850 for(var i = 0, len = multi.length; i < len; i++) {
21851 this.appendChild(multi[i]);
21854 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21857 var index = this.childNodes.length;
21858 var oldParent = node.parentNode;
21859 // it's a move, make sure we move it cleanly
21861 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21864 oldParent.removeChild(node);
21866 index = this.childNodes.length;
21868 this.setFirstChild(node);
21870 this.childNodes.push(node);
21871 node.parentNode = this;
21872 var ps = this.childNodes[index-1];
21874 node.previousSibling = ps;
21875 ps.nextSibling = node;
21877 node.previousSibling = null;
21879 node.nextSibling = null;
21880 this.setLastChild(node);
21881 node.setOwnerTree(this.getOwnerTree());
21882 this.fireEvent("append", this.ownerTree, this, node, index);
21884 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21891 * Removes a child node from this node.
21892 * @param {Node} node The node to remove
21893 * @return {Node} The removed node
21895 removeChild : function(node){
21896 var index = this.childNodes.indexOf(node);
21900 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21904 // remove it from childNodes collection
21905 this.childNodes.splice(index, 1);
21908 if(node.previousSibling){
21909 node.previousSibling.nextSibling = node.nextSibling;
21911 if(node.nextSibling){
21912 node.nextSibling.previousSibling = node.previousSibling;
21915 // update child refs
21916 if(this.firstChild == node){
21917 this.setFirstChild(node.nextSibling);
21919 if(this.lastChild == node){
21920 this.setLastChild(node.previousSibling);
21923 node.setOwnerTree(null);
21924 // clear any references from the node
21925 node.parentNode = null;
21926 node.previousSibling = null;
21927 node.nextSibling = null;
21928 this.fireEvent("remove", this.ownerTree, this, node);
21933 * Inserts the first node before the second node in this nodes childNodes collection.
21934 * @param {Node} node The node to insert
21935 * @param {Node} refNode The node to insert before (if null the node is appended)
21936 * @return {Node} The inserted node
21938 insertBefore : function(node, refNode){
21939 if(!refNode){ // like standard Dom, refNode can be null for append
21940 return this.appendChild(node);
21943 if(node == refNode){
21947 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21950 var index = this.childNodes.indexOf(refNode);
21951 var oldParent = node.parentNode;
21952 var refIndex = index;
21954 // when moving internally, indexes will change after remove
21955 if(oldParent == this && this.childNodes.indexOf(node) < index){
21959 // it's a move, make sure we move it cleanly
21961 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21964 oldParent.removeChild(node);
21967 this.setFirstChild(node);
21969 this.childNodes.splice(refIndex, 0, node);
21970 node.parentNode = this;
21971 var ps = this.childNodes[refIndex-1];
21973 node.previousSibling = ps;
21974 ps.nextSibling = node;
21976 node.previousSibling = null;
21978 node.nextSibling = refNode;
21979 refNode.previousSibling = node;
21980 node.setOwnerTree(this.getOwnerTree());
21981 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21983 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21989 * Returns the child node at the specified index.
21990 * @param {Number} index
21993 item : function(index){
21994 return this.childNodes[index];
21998 * Replaces one child node in this node with another.
21999 * @param {Node} newChild The replacement node
22000 * @param {Node} oldChild The node to replace
22001 * @return {Node} The replaced node
22003 replaceChild : function(newChild, oldChild){
22004 this.insertBefore(newChild, oldChild);
22005 this.removeChild(oldChild);
22010 * Returns the index of a child node
22011 * @param {Node} node
22012 * @return {Number} The index of the node or -1 if it was not found
22014 indexOf : function(child){
22015 return this.childNodes.indexOf(child);
22019 * Returns the tree this node is in.
22022 getOwnerTree : function(){
22023 // if it doesn't have one, look for one
22024 if(!this.ownerTree){
22028 this.ownerTree = p.ownerTree;
22034 return this.ownerTree;
22038 * Returns depth of this node (the root node has a depth of 0)
22041 getDepth : function(){
22044 while(p.parentNode){
22052 setOwnerTree : function(tree){
22053 // if it's move, we need to update everyone
22054 if(tree != this.ownerTree){
22055 if(this.ownerTree){
22056 this.ownerTree.unregisterNode(this);
22058 this.ownerTree = tree;
22059 var cs = this.childNodes;
22060 for(var i = 0, len = cs.length; i < len; i++) {
22061 cs[i].setOwnerTree(tree);
22064 tree.registerNode(this);
22070 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22071 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22072 * @return {String} The path
22074 getPath : function(attr){
22075 attr = attr || "id";
22076 var p = this.parentNode;
22077 var b = [this.attributes[attr]];
22079 b.unshift(p.attributes[attr]);
22082 var sep = this.getOwnerTree().pathSeparator;
22083 return sep + b.join(sep);
22087 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22088 * function call will be the scope provided or the current node. The arguments to the function
22089 * will be the args provided or the current node. If the function returns false at any point,
22090 * the bubble is stopped.
22091 * @param {Function} fn The function to call
22092 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22093 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22095 bubble : function(fn, scope, args){
22098 if(fn.call(scope || p, args || p) === false){
22106 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22107 * function call will be the scope provided or the current node. The arguments to the function
22108 * will be the args provided or the current node. If the function returns false at any point,
22109 * the cascade is stopped on that branch.
22110 * @param {Function} fn The function to call
22111 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22112 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22114 cascade : function(fn, scope, args){
22115 if(fn.call(scope || this, args || this) !== false){
22116 var cs = this.childNodes;
22117 for(var i = 0, len = cs.length; i < len; i++) {
22118 cs[i].cascade(fn, scope, args);
22124 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22125 * function call will be the scope provided or the current node. The arguments to the function
22126 * will be the args provided or the current node. If the function returns false at any point,
22127 * the iteration stops.
22128 * @param {Function} fn The function to call
22129 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22130 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22132 eachChild : function(fn, scope, args){
22133 var cs = this.childNodes;
22134 for(var i = 0, len = cs.length; i < len; i++) {
22135 if(fn.call(scope || this, args || cs[i]) === false){
22142 * Finds the first child that has the attribute with the specified value.
22143 * @param {String} attribute The attribute name
22144 * @param {Mixed} value The value to search for
22145 * @return {Node} The found child or null if none was found
22147 findChild : function(attribute, value){
22148 var cs = this.childNodes;
22149 for(var i = 0, len = cs.length; i < len; i++) {
22150 if(cs[i].attributes[attribute] == value){
22158 * Finds the first child by a custom function. The child matches if the function passed
22160 * @param {Function} fn
22161 * @param {Object} scope (optional)
22162 * @return {Node} The found child or null if none was found
22164 findChildBy : function(fn, scope){
22165 var cs = this.childNodes;
22166 for(var i = 0, len = cs.length; i < len; i++) {
22167 if(fn.call(scope||cs[i], cs[i]) === true){
22175 * Sorts this nodes children using the supplied sort function
22176 * @param {Function} fn
22177 * @param {Object} scope (optional)
22179 sort : function(fn, scope){
22180 var cs = this.childNodes;
22181 var len = cs.length;
22183 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22185 for(var i = 0; i < len; i++){
22187 n.previousSibling = cs[i-1];
22188 n.nextSibling = cs[i+1];
22190 this.setFirstChild(n);
22193 this.setLastChild(n);
22200 * Returns true if this node is an ancestor (at any point) of the passed node.
22201 * @param {Node} node
22202 * @return {Boolean}
22204 contains : function(node){
22205 return node.isAncestor(this);
22209 * Returns true if the passed node is an ancestor (at any point) of this node.
22210 * @param {Node} node
22211 * @return {Boolean}
22213 isAncestor : function(node){
22214 var p = this.parentNode;
22224 toString : function(){
22225 return "[Node"+(this.id?" "+this.id:"")+"]";
22229 * Ext JS Library 1.1.1
22230 * Copyright(c) 2006-2007, Ext JS, LLC.
22232 * Originally Released Under LGPL - original licence link has changed is not relivant.
22235 * <script type="text/javascript">
22240 * @class Roo.ComponentMgr
22241 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22244 Roo.ComponentMgr = function(){
22245 var all = new Roo.util.MixedCollection();
22249 * Registers a component.
22250 * @param {Roo.Component} c The component
22252 register : function(c){
22257 * Unregisters a component.
22258 * @param {Roo.Component} c The component
22260 unregister : function(c){
22265 * Returns a component by id
22266 * @param {String} id The component id
22268 get : function(id){
22269 return all.get(id);
22273 * Registers a function that will be called when a specified component is added to ComponentMgr
22274 * @param {String} id The component id
22275 * @param {Funtction} fn The callback function
22276 * @param {Object} scope The scope of the callback
22278 onAvailable : function(id, fn, scope){
22279 all.on("add", function(index, o){
22281 fn.call(scope || o, o);
22282 all.un("add", fn, scope);
22289 * Ext JS Library 1.1.1
22290 * Copyright(c) 2006-2007, Ext JS, LLC.
22292 * Originally Released Under LGPL - original licence link has changed is not relivant.
22295 * <script type="text/javascript">
22299 * @class Roo.Component
22300 * @extends Roo.util.Observable
22301 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22302 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22303 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22304 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22305 * All visual components (widgets) that require rendering into a layout should subclass Component.
22307 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22308 * 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
22309 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22311 Roo.Component = function(config){
22312 config = config || {};
22313 if(config.tagName || config.dom || typeof config == "string"){ // element object
22314 config = {el: config, id: config.id || config};
22316 this.initialConfig = config;
22318 Roo.apply(this, config);
22322 * Fires after the component is disabled.
22323 * @param {Roo.Component} this
22328 * Fires after the component is enabled.
22329 * @param {Roo.Component} this
22333 * @event beforeshow
22334 * Fires before the component is shown. Return false to stop the show.
22335 * @param {Roo.Component} this
22340 * Fires after the component is shown.
22341 * @param {Roo.Component} this
22345 * @event beforehide
22346 * Fires before the component is hidden. Return false to stop the hide.
22347 * @param {Roo.Component} this
22352 * Fires after the component is hidden.
22353 * @param {Roo.Component} this
22357 * @event beforerender
22358 * Fires before the component is rendered. Return false to stop the render.
22359 * @param {Roo.Component} this
22361 beforerender : true,
22364 * Fires after the component is rendered.
22365 * @param {Roo.Component} this
22369 * @event beforedestroy
22370 * Fires before the component is destroyed. Return false to stop the destroy.
22371 * @param {Roo.Component} this
22373 beforedestroy : true,
22376 * Fires after the component is destroyed.
22377 * @param {Roo.Component} this
22382 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22384 Roo.ComponentMgr.register(this);
22385 Roo.Component.superclass.constructor.call(this);
22386 this.initComponent();
22387 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22388 this.render(this.renderTo);
22389 delete this.renderTo;
22394 Roo.Component.AUTO_ID = 1000;
22396 Roo.extend(Roo.Component, Roo.util.Observable, {
22398 * @scope Roo.Component.prototype
22400 * true if this component is hidden. Read-only.
22405 * true if this component is disabled. Read-only.
22410 * true if this component has been rendered. Read-only.
22414 /** @cfg {String} disableClass
22415 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22417 disabledClass : "x-item-disabled",
22418 /** @cfg {Boolean} allowDomMove
22419 * Whether the component can move the Dom node when rendering (defaults to true).
22421 allowDomMove : true,
22422 /** @cfg {String} hideMode
22423 * How this component should hidden. Supported values are
22424 * "visibility" (css visibility), "offsets" (negative offset position) and
22425 * "display" (css display) - defaults to "display".
22427 hideMode: 'display',
22430 ctype : "Roo.Component",
22433 * @cfg {String} actionMode
22434 * which property holds the element that used for hide() / show() / disable() / enable()
22440 getActionEl : function(){
22441 return this[this.actionMode];
22444 initComponent : Roo.emptyFn,
22446 * If this is a lazy rendering component, render it to its container element.
22447 * @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.
22449 render : function(container, position){
22450 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22451 if(!container && this.el){
22452 this.el = Roo.get(this.el);
22453 container = this.el.dom.parentNode;
22454 this.allowDomMove = false;
22456 this.container = Roo.get(container);
22457 this.rendered = true;
22458 if(position !== undefined){
22459 if(typeof position == 'number'){
22460 position = this.container.dom.childNodes[position];
22462 position = Roo.getDom(position);
22465 this.onRender(this.container, position || null);
22467 this.el.addClass(this.cls);
22471 this.el.applyStyles(this.style);
22474 this.fireEvent("render", this);
22475 this.afterRender(this.container);
22487 // default function is not really useful
22488 onRender : function(ct, position){
22490 this.el = Roo.get(this.el);
22491 if(this.allowDomMove !== false){
22492 ct.dom.insertBefore(this.el.dom, position);
22498 getAutoCreate : function(){
22499 var cfg = typeof this.autoCreate == "object" ?
22500 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22501 if(this.id && !cfg.id){
22508 afterRender : Roo.emptyFn,
22511 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22512 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22514 destroy : function(){
22515 if(this.fireEvent("beforedestroy", this) !== false){
22516 this.purgeListeners();
22517 this.beforeDestroy();
22519 this.el.removeAllListeners();
22521 if(this.actionMode == "container"){
22522 this.container.remove();
22526 Roo.ComponentMgr.unregister(this);
22527 this.fireEvent("destroy", this);
22532 beforeDestroy : function(){
22537 onDestroy : function(){
22542 * Returns the underlying {@link Roo.Element}.
22543 * @return {Roo.Element} The element
22545 getEl : function(){
22550 * Returns the id of this component.
22553 getId : function(){
22558 * Try to focus this component.
22559 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22560 * @return {Roo.Component} this
22562 focus : function(selectText){
22565 if(selectText === true){
22566 this.el.dom.select();
22581 * Disable this component.
22582 * @return {Roo.Component} this
22584 disable : function(){
22588 this.disabled = true;
22589 this.fireEvent("disable", this);
22594 onDisable : function(){
22595 this.getActionEl().addClass(this.disabledClass);
22596 this.el.dom.disabled = true;
22600 * Enable this component.
22601 * @return {Roo.Component} this
22603 enable : function(){
22607 this.disabled = false;
22608 this.fireEvent("enable", this);
22613 onEnable : function(){
22614 this.getActionEl().removeClass(this.disabledClass);
22615 this.el.dom.disabled = false;
22619 * Convenience function for setting disabled/enabled by boolean.
22620 * @param {Boolean} disabled
22622 setDisabled : function(disabled){
22623 this[disabled ? "disable" : "enable"]();
22627 * Show this component.
22628 * @return {Roo.Component} this
22631 if(this.fireEvent("beforeshow", this) !== false){
22632 this.hidden = false;
22636 this.fireEvent("show", this);
22642 onShow : function(){
22643 var ae = this.getActionEl();
22644 if(this.hideMode == 'visibility'){
22645 ae.dom.style.visibility = "visible";
22646 }else if(this.hideMode == 'offsets'){
22647 ae.removeClass('x-hidden');
22649 ae.dom.style.display = "";
22654 * Hide this component.
22655 * @return {Roo.Component} this
22658 if(this.fireEvent("beforehide", this) !== false){
22659 this.hidden = true;
22663 this.fireEvent("hide", this);
22669 onHide : function(){
22670 var ae = this.getActionEl();
22671 if(this.hideMode == 'visibility'){
22672 ae.dom.style.visibility = "hidden";
22673 }else if(this.hideMode == 'offsets'){
22674 ae.addClass('x-hidden');
22676 ae.dom.style.display = "none";
22681 * Convenience function to hide or show this component by boolean.
22682 * @param {Boolean} visible True to show, false to hide
22683 * @return {Roo.Component} this
22685 setVisible: function(visible){
22695 * Returns true if this component is visible.
22697 isVisible : function(){
22698 return this.getActionEl().isVisible();
22701 cloneConfig : function(overrides){
22702 overrides = overrides || {};
22703 var id = overrides.id || Roo.id();
22704 var cfg = Roo.applyIf(overrides, this.initialConfig);
22705 cfg.id = id; // prevent dup id
22706 return new this.constructor(cfg);
22710 * Ext JS Library 1.1.1
22711 * Copyright(c) 2006-2007, Ext JS, LLC.
22713 * Originally Released Under LGPL - original licence link has changed is not relivant.
22716 * <script type="text/javascript">
22721 * @extends Roo.Element
22722 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22723 * automatic maintaining of shadow/shim positions.
22724 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22725 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22726 * you can pass a string with a CSS class name. False turns off the shadow.
22727 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22728 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22729 * @cfg {String} cls CSS class to add to the element
22730 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22731 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22733 * @param {Object} config An object with config options.
22734 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22737 Roo.Layer = function(config, existingEl){
22738 config = config || {};
22739 var dh = Roo.DomHelper;
22740 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22742 this.dom = Roo.getDom(existingEl);
22745 var o = config.dh || {tag: "div", cls: "x-layer"};
22746 this.dom = dh.append(pel, o);
22749 this.addClass(config.cls);
22751 this.constrain = config.constrain !== false;
22752 this.visibilityMode = Roo.Element.VISIBILITY;
22754 this.id = this.dom.id = config.id;
22756 this.id = Roo.id(this.dom);
22758 this.zindex = config.zindex || this.getZIndex();
22759 this.position("absolute", this.zindex);
22761 this.shadowOffset = config.shadowOffset || 4;
22762 this.shadow = new Roo.Shadow({
22763 offset : this.shadowOffset,
22764 mode : config.shadow
22767 this.shadowOffset = 0;
22769 this.useShim = config.shim !== false && Roo.useShims;
22770 this.useDisplay = config.useDisplay;
22774 var supr = Roo.Element.prototype;
22776 // shims are shared among layer to keep from having 100 iframes
22779 Roo.extend(Roo.Layer, Roo.Element, {
22781 getZIndex : function(){
22782 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22785 getShim : function(){
22792 var shim = shims.shift();
22794 shim = this.createShim();
22795 shim.enableDisplayMode('block');
22796 shim.dom.style.display = 'none';
22797 shim.dom.style.visibility = 'visible';
22799 var pn = this.dom.parentNode;
22800 if(shim.dom.parentNode != pn){
22801 pn.insertBefore(shim.dom, this.dom);
22803 shim.setStyle('z-index', this.getZIndex()-2);
22808 hideShim : function(){
22810 this.shim.setDisplayed(false);
22811 shims.push(this.shim);
22816 disableShadow : function(){
22818 this.shadowDisabled = true;
22819 this.shadow.hide();
22820 this.lastShadowOffset = this.shadowOffset;
22821 this.shadowOffset = 0;
22825 enableShadow : function(show){
22827 this.shadowDisabled = false;
22828 this.shadowOffset = this.lastShadowOffset;
22829 delete this.lastShadowOffset;
22837 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22838 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22839 sync : function(doShow){
22840 var sw = this.shadow;
22841 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22842 var sh = this.getShim();
22844 var w = this.getWidth(),
22845 h = this.getHeight();
22847 var l = this.getLeft(true),
22848 t = this.getTop(true);
22850 if(sw && !this.shadowDisabled){
22851 if(doShow && !sw.isVisible()){
22854 sw.realign(l, t, w, h);
22860 // fit the shim behind the shadow, so it is shimmed too
22861 var a = sw.adjusts, s = sh.dom.style;
22862 s.left = (Math.min(l, l+a.l))+"px";
22863 s.top = (Math.min(t, t+a.t))+"px";
22864 s.width = (w+a.w)+"px";
22865 s.height = (h+a.h)+"px";
22872 sh.setLeftTop(l, t);
22879 destroy : function(){
22882 this.shadow.hide();
22884 this.removeAllListeners();
22885 var pn = this.dom.parentNode;
22887 pn.removeChild(this.dom);
22889 Roo.Element.uncache(this.id);
22892 remove : function(){
22897 beginUpdate : function(){
22898 this.updating = true;
22902 endUpdate : function(){
22903 this.updating = false;
22908 hideUnders : function(negOffset){
22910 this.shadow.hide();
22916 constrainXY : function(){
22917 if(this.constrain){
22918 var vw = Roo.lib.Dom.getViewWidth(),
22919 vh = Roo.lib.Dom.getViewHeight();
22920 var s = Roo.get(document).getScroll();
22922 var xy = this.getXY();
22923 var x = xy[0], y = xy[1];
22924 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22925 // only move it if it needs it
22927 // first validate right/bottom
22928 if((x + w) > vw+s.left){
22929 x = vw - w - this.shadowOffset;
22932 if((y + h) > vh+s.top){
22933 y = vh - h - this.shadowOffset;
22936 // then make sure top/left isn't negative
22947 var ay = this.avoidY;
22948 if(y <= ay && (y+h) >= ay){
22954 supr.setXY.call(this, xy);
22960 isVisible : function(){
22961 return this.visible;
22965 showAction : function(){
22966 this.visible = true; // track visibility to prevent getStyle calls
22967 if(this.useDisplay === true){
22968 this.setDisplayed("");
22969 }else if(this.lastXY){
22970 supr.setXY.call(this, this.lastXY);
22971 }else if(this.lastLT){
22972 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22977 hideAction : function(){
22978 this.visible = false;
22979 if(this.useDisplay === true){
22980 this.setDisplayed(false);
22982 this.setLeftTop(-10000,-10000);
22986 // overridden Element method
22987 setVisible : function(v, a, d, c, e){
22992 var cb = function(){
22997 }.createDelegate(this);
22998 supr.setVisible.call(this, true, true, d, cb, e);
23001 this.hideUnders(true);
23010 }.createDelegate(this);
23012 supr.setVisible.call(this, v, a, d, cb, e);
23021 storeXY : function(xy){
23022 delete this.lastLT;
23026 storeLeftTop : function(left, top){
23027 delete this.lastXY;
23028 this.lastLT = [left, top];
23032 beforeFx : function(){
23033 this.beforeAction();
23034 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23038 afterFx : function(){
23039 Roo.Layer.superclass.afterFx.apply(this, arguments);
23040 this.sync(this.isVisible());
23044 beforeAction : function(){
23045 if(!this.updating && this.shadow){
23046 this.shadow.hide();
23050 // overridden Element method
23051 setLeft : function(left){
23052 this.storeLeftTop(left, this.getTop(true));
23053 supr.setLeft.apply(this, arguments);
23057 setTop : function(top){
23058 this.storeLeftTop(this.getLeft(true), top);
23059 supr.setTop.apply(this, arguments);
23063 setLeftTop : function(left, top){
23064 this.storeLeftTop(left, top);
23065 supr.setLeftTop.apply(this, arguments);
23069 setXY : function(xy, a, d, c, e){
23071 this.beforeAction();
23073 var cb = this.createCB(c);
23074 supr.setXY.call(this, xy, a, d, cb, e);
23081 createCB : function(c){
23092 // overridden Element method
23093 setX : function(x, a, d, c, e){
23094 this.setXY([x, this.getY()], a, d, c, e);
23097 // overridden Element method
23098 setY : function(y, a, d, c, e){
23099 this.setXY([this.getX(), y], a, d, c, e);
23102 // overridden Element method
23103 setSize : function(w, h, a, d, c, e){
23104 this.beforeAction();
23105 var cb = this.createCB(c);
23106 supr.setSize.call(this, w, h, a, d, cb, e);
23112 // overridden Element method
23113 setWidth : function(w, a, d, c, e){
23114 this.beforeAction();
23115 var cb = this.createCB(c);
23116 supr.setWidth.call(this, w, a, d, cb, e);
23122 // overridden Element method
23123 setHeight : function(h, a, d, c, e){
23124 this.beforeAction();
23125 var cb = this.createCB(c);
23126 supr.setHeight.call(this, h, a, d, cb, e);
23132 // overridden Element method
23133 setBounds : function(x, y, w, h, a, d, c, e){
23134 this.beforeAction();
23135 var cb = this.createCB(c);
23137 this.storeXY([x, y]);
23138 supr.setXY.call(this, [x, y]);
23139 supr.setSize.call(this, w, h, a, d, cb, e);
23142 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23148 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23149 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23150 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23151 * @param {Number} zindex The new z-index to set
23152 * @return {this} The Layer
23154 setZIndex : function(zindex){
23155 this.zindex = zindex;
23156 this.setStyle("z-index", zindex + 2);
23158 this.shadow.setZIndex(zindex + 1);
23161 this.shim.setStyle("z-index", zindex);
23167 * Ext JS Library 1.1.1
23168 * Copyright(c) 2006-2007, Ext JS, LLC.
23170 * Originally Released Under LGPL - original licence link has changed is not relivant.
23173 * <script type="text/javascript">
23178 * @class Roo.Shadow
23179 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23180 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23181 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23183 * Create a new Shadow
23184 * @param {Object} config The config object
23186 Roo.Shadow = function(config){
23187 Roo.apply(this, config);
23188 if(typeof this.mode != "string"){
23189 this.mode = this.defaultMode;
23191 var o = this.offset, a = {h: 0};
23192 var rad = Math.floor(this.offset/2);
23193 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23199 a.l -= this.offset + rad;
23200 a.t -= this.offset + rad;
23211 a.l -= (this.offset - rad);
23212 a.t -= this.offset + rad;
23214 a.w -= (this.offset - rad)*2;
23225 a.l -= (this.offset - rad);
23226 a.t -= (this.offset - rad);
23228 a.w -= (this.offset + rad + 1);
23229 a.h -= (this.offset + rad);
23238 Roo.Shadow.prototype = {
23240 * @cfg {String} mode
23241 * The shadow display mode. Supports the following options:<br />
23242 * sides: Shadow displays on both sides and bottom only<br />
23243 * frame: Shadow displays equally on all four sides<br />
23244 * drop: Traditional bottom-right drop shadow (default)
23247 * @cfg {String} offset
23248 * The number of pixels to offset the shadow from the element (defaults to 4)
23253 defaultMode: "drop",
23256 * Displays the shadow under the target element
23257 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23259 show : function(target){
23260 target = Roo.get(target);
23262 this.el = Roo.Shadow.Pool.pull();
23263 if(this.el.dom.nextSibling != target.dom){
23264 this.el.insertBefore(target);
23267 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23269 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23272 target.getLeft(true),
23273 target.getTop(true),
23277 this.el.dom.style.display = "block";
23281 * Returns true if the shadow is visible, else false
23283 isVisible : function(){
23284 return this.el ? true : false;
23288 * Direct alignment when values are already available. Show must be called at least once before
23289 * calling this method to ensure it is initialized.
23290 * @param {Number} left The target element left position
23291 * @param {Number} top The target element top position
23292 * @param {Number} width The target element width
23293 * @param {Number} height The target element height
23295 realign : function(l, t, w, h){
23299 var a = this.adjusts, d = this.el.dom, s = d.style;
23301 s.left = (l+a.l)+"px";
23302 s.top = (t+a.t)+"px";
23303 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23305 if(s.width != sws || s.height != shs){
23309 var cn = d.childNodes;
23310 var sww = Math.max(0, (sw-12))+"px";
23311 cn[0].childNodes[1].style.width = sww;
23312 cn[1].childNodes[1].style.width = sww;
23313 cn[2].childNodes[1].style.width = sww;
23314 cn[1].style.height = Math.max(0, (sh-12))+"px";
23320 * Hides this shadow
23324 this.el.dom.style.display = "none";
23325 Roo.Shadow.Pool.push(this.el);
23331 * Adjust the z-index of this shadow
23332 * @param {Number} zindex The new z-index
23334 setZIndex : function(z){
23337 this.el.setStyle("z-index", z);
23342 // Private utility class that manages the internal Shadow cache
23343 Roo.Shadow.Pool = function(){
23345 var markup = Roo.isIE ?
23346 '<div class="x-ie-shadow"></div>' :
23347 '<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>';
23350 var sh = p.shift();
23352 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23353 sh.autoBoxAdjust = false;
23358 push : function(sh){
23364 * Ext JS Library 1.1.1
23365 * Copyright(c) 2006-2007, Ext JS, LLC.
23367 * Originally Released Under LGPL - original licence link has changed is not relivant.
23370 * <script type="text/javascript">
23374 * @class Roo.BoxComponent
23375 * @extends Roo.Component
23376 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23377 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23378 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23379 * layout containers.
23381 * @param {Roo.Element/String/Object} config The configuration options.
23383 Roo.BoxComponent = function(config){
23384 Roo.Component.call(this, config);
23388 * Fires after the component is resized.
23389 * @param {Roo.Component} this
23390 * @param {Number} adjWidth The box-adjusted width that was set
23391 * @param {Number} adjHeight The box-adjusted height that was set
23392 * @param {Number} rawWidth The width that was originally specified
23393 * @param {Number} rawHeight The height that was originally specified
23398 * Fires after the component is moved.
23399 * @param {Roo.Component} this
23400 * @param {Number} x The new x position
23401 * @param {Number} y The new y position
23407 Roo.extend(Roo.BoxComponent, Roo.Component, {
23408 // private, set in afterRender to signify that the component has been rendered
23410 // private, used to defer height settings to subclasses
23411 deferHeight: false,
23412 /** @cfg {Number} width
23413 * width (optional) size of component
23415 /** @cfg {Number} height
23416 * height (optional) size of component
23420 * Sets the width and height of the component. This method fires the resize event. This method can accept
23421 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23422 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23423 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23424 * @return {Roo.BoxComponent} this
23426 setSize : function(w, h){
23427 // support for standard size objects
23428 if(typeof w == 'object'){
23433 if(!this.boxReady){
23439 // prevent recalcs when not needed
23440 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23443 this.lastSize = {width: w, height: h};
23445 var adj = this.adjustSize(w, h);
23446 var aw = adj.width, ah = adj.height;
23447 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23448 var rz = this.getResizeEl();
23449 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23450 rz.setSize(aw, ah);
23451 }else if(!this.deferHeight && ah !== undefined){
23453 }else if(aw !== undefined){
23456 this.onResize(aw, ah, w, h);
23457 this.fireEvent('resize', this, aw, ah, w, h);
23463 * Gets the current size of the component's underlying element.
23464 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23466 getSize : function(){
23467 return this.el.getSize();
23471 * Gets the current XY position of the component's underlying element.
23472 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23473 * @return {Array} The XY position of the element (e.g., [100, 200])
23475 getPosition : function(local){
23476 if(local === true){
23477 return [this.el.getLeft(true), this.el.getTop(true)];
23479 return this.xy || this.el.getXY();
23483 * Gets the current box measurements of the component's underlying element.
23484 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23485 * @returns {Object} box An object in the format {x, y, width, height}
23487 getBox : function(local){
23488 var s = this.el.getSize();
23490 s.x = this.el.getLeft(true);
23491 s.y = this.el.getTop(true);
23493 var xy = this.xy || this.el.getXY();
23501 * Sets the current box measurements of the component's underlying element.
23502 * @param {Object} box An object in the format {x, y, width, height}
23503 * @returns {Roo.BoxComponent} this
23505 updateBox : function(box){
23506 this.setSize(box.width, box.height);
23507 this.setPagePosition(box.x, box.y);
23512 getResizeEl : function(){
23513 return this.resizeEl || this.el;
23517 getPositionEl : function(){
23518 return this.positionEl || this.el;
23522 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23523 * This method fires the move event.
23524 * @param {Number} left The new left
23525 * @param {Number} top The new top
23526 * @returns {Roo.BoxComponent} this
23528 setPosition : function(x, y){
23531 if(!this.boxReady){
23534 var adj = this.adjustPosition(x, y);
23535 var ax = adj.x, ay = adj.y;
23537 var el = this.getPositionEl();
23538 if(ax !== undefined || ay !== undefined){
23539 if(ax !== undefined && ay !== undefined){
23540 el.setLeftTop(ax, ay);
23541 }else if(ax !== undefined){
23543 }else if(ay !== undefined){
23546 this.onPosition(ax, ay);
23547 this.fireEvent('move', this, ax, ay);
23553 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23554 * This method fires the move event.
23555 * @param {Number} x The new x position
23556 * @param {Number} y The new y position
23557 * @returns {Roo.BoxComponent} this
23559 setPagePosition : function(x, y){
23562 if(!this.boxReady){
23565 if(x === undefined || y === undefined){ // cannot translate undefined points
23568 var p = this.el.translatePoints(x, y);
23569 this.setPosition(p.left, p.top);
23574 onRender : function(ct, position){
23575 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23577 this.resizeEl = Roo.get(this.resizeEl);
23579 if(this.positionEl){
23580 this.positionEl = Roo.get(this.positionEl);
23585 afterRender : function(){
23586 Roo.BoxComponent.superclass.afterRender.call(this);
23587 this.boxReady = true;
23588 this.setSize(this.width, this.height);
23589 if(this.x || this.y){
23590 this.setPosition(this.x, this.y);
23592 if(this.pageX || this.pageY){
23593 this.setPagePosition(this.pageX, this.pageY);
23598 * Force the component's size to recalculate based on the underlying element's current height and width.
23599 * @returns {Roo.BoxComponent} this
23601 syncSize : function(){
23602 delete this.lastSize;
23603 this.setSize(this.el.getWidth(), this.el.getHeight());
23608 * Called after the component is resized, this method is empty by default but can be implemented by any
23609 * subclass that needs to perform custom logic after a resize occurs.
23610 * @param {Number} adjWidth The box-adjusted width that was set
23611 * @param {Number} adjHeight The box-adjusted height that was set
23612 * @param {Number} rawWidth The width that was originally specified
23613 * @param {Number} rawHeight The height that was originally specified
23615 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23620 * Called after the component is moved, this method is empty by default but can be implemented by any
23621 * subclass that needs to perform custom logic after a move occurs.
23622 * @param {Number} x The new x position
23623 * @param {Number} y The new y position
23625 onPosition : function(x, y){
23630 adjustSize : function(w, h){
23631 if(this.autoWidth){
23634 if(this.autoHeight){
23637 return {width : w, height: h};
23641 adjustPosition : function(x, y){
23642 return {x : x, y: y};
23646 * Ext JS Library 1.1.1
23647 * Copyright(c) 2006-2007, Ext JS, LLC.
23649 * Originally Released Under LGPL - original licence link has changed is not relivant.
23652 * <script type="text/javascript">
23657 * @class Roo.SplitBar
23658 * @extends Roo.util.Observable
23659 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23663 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23664 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23665 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23666 split.minSize = 100;
23667 split.maxSize = 600;
23668 split.animate = true;
23669 split.on('moved', splitterMoved);
23672 * Create a new SplitBar
23673 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23674 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23675 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23676 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23677 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23678 position of the SplitBar).
23680 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23683 this.el = Roo.get(dragElement, true);
23684 this.el.dom.unselectable = "on";
23686 this.resizingEl = Roo.get(resizingElement, true);
23690 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23691 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23694 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23697 * The minimum size of the resizing element. (Defaults to 0)
23703 * The maximum size of the resizing element. (Defaults to 2000)
23706 this.maxSize = 2000;
23709 * Whether to animate the transition to the new size
23712 this.animate = false;
23715 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23718 this.useShim = false;
23723 if(!existingProxy){
23725 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23727 this.proxy = Roo.get(existingProxy).dom;
23730 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23733 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23736 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23739 this.dragSpecs = {};
23742 * @private The adapter to use to positon and resize elements
23744 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23745 this.adapter.init(this);
23747 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23749 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23750 this.el.addClass("x-splitbar-h");
23753 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23754 this.el.addClass("x-splitbar-v");
23760 * Fires when the splitter is moved (alias for {@link #event-moved})
23761 * @param {Roo.SplitBar} this
23762 * @param {Number} newSize the new width or height
23767 * Fires when the splitter is moved
23768 * @param {Roo.SplitBar} this
23769 * @param {Number} newSize the new width or height
23773 * @event beforeresize
23774 * Fires before the splitter is dragged
23775 * @param {Roo.SplitBar} this
23777 "beforeresize" : true,
23779 "beforeapply" : true
23782 Roo.util.Observable.call(this);
23785 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23786 onStartProxyDrag : function(x, y){
23787 this.fireEvent("beforeresize", this);
23789 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23791 o.enableDisplayMode("block");
23792 // all splitbars share the same overlay
23793 Roo.SplitBar.prototype.overlay = o;
23795 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23796 this.overlay.show();
23797 Roo.get(this.proxy).setDisplayed("block");
23798 var size = this.adapter.getElementSize(this);
23799 this.activeMinSize = this.getMinimumSize();;
23800 this.activeMaxSize = this.getMaximumSize();;
23801 var c1 = size - this.activeMinSize;
23802 var c2 = Math.max(this.activeMaxSize - size, 0);
23803 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23804 this.dd.resetConstraints();
23805 this.dd.setXConstraint(
23806 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23807 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23809 this.dd.setYConstraint(0, 0);
23811 this.dd.resetConstraints();
23812 this.dd.setXConstraint(0, 0);
23813 this.dd.setYConstraint(
23814 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23815 this.placement == Roo.SplitBar.TOP ? c2 : c1
23818 this.dragSpecs.startSize = size;
23819 this.dragSpecs.startPoint = [x, y];
23820 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23824 * @private Called after the drag operation by the DDProxy
23826 onEndProxyDrag : function(e){
23827 Roo.get(this.proxy).setDisplayed(false);
23828 var endPoint = Roo.lib.Event.getXY(e);
23830 this.overlay.hide();
23833 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23834 newSize = this.dragSpecs.startSize +
23835 (this.placement == Roo.SplitBar.LEFT ?
23836 endPoint[0] - this.dragSpecs.startPoint[0] :
23837 this.dragSpecs.startPoint[0] - endPoint[0]
23840 newSize = this.dragSpecs.startSize +
23841 (this.placement == Roo.SplitBar.TOP ?
23842 endPoint[1] - this.dragSpecs.startPoint[1] :
23843 this.dragSpecs.startPoint[1] - endPoint[1]
23846 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23847 if(newSize != this.dragSpecs.startSize){
23848 if(this.fireEvent('beforeapply', this, newSize) !== false){
23849 this.adapter.setElementSize(this, newSize);
23850 this.fireEvent("moved", this, newSize);
23851 this.fireEvent("resize", this, newSize);
23857 * Get the adapter this SplitBar uses
23858 * @return The adapter object
23860 getAdapter : function(){
23861 return this.adapter;
23865 * Set the adapter this SplitBar uses
23866 * @param {Object} adapter A SplitBar adapter object
23868 setAdapter : function(adapter){
23869 this.adapter = adapter;
23870 this.adapter.init(this);
23874 * Gets the minimum size for the resizing element
23875 * @return {Number} The minimum size
23877 getMinimumSize : function(){
23878 return this.minSize;
23882 * Sets the minimum size for the resizing element
23883 * @param {Number} minSize The minimum size
23885 setMinimumSize : function(minSize){
23886 this.minSize = minSize;
23890 * Gets the maximum size for the resizing element
23891 * @return {Number} The maximum size
23893 getMaximumSize : function(){
23894 return this.maxSize;
23898 * Sets the maximum size for the resizing element
23899 * @param {Number} maxSize The maximum size
23901 setMaximumSize : function(maxSize){
23902 this.maxSize = maxSize;
23906 * Sets the initialize size for the resizing element
23907 * @param {Number} size The initial size
23909 setCurrentSize : function(size){
23910 var oldAnimate = this.animate;
23911 this.animate = false;
23912 this.adapter.setElementSize(this, size);
23913 this.animate = oldAnimate;
23917 * Destroy this splitbar.
23918 * @param {Boolean} removeEl True to remove the element
23920 destroy : function(removeEl){
23922 this.shim.remove();
23925 this.proxy.parentNode.removeChild(this.proxy);
23933 * @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.
23935 Roo.SplitBar.createProxy = function(dir){
23936 var proxy = new Roo.Element(document.createElement("div"));
23937 proxy.unselectable();
23938 var cls = 'x-splitbar-proxy';
23939 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23940 document.body.appendChild(proxy.dom);
23945 * @class Roo.SplitBar.BasicLayoutAdapter
23946 * Default Adapter. It assumes the splitter and resizing element are not positioned
23947 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23949 Roo.SplitBar.BasicLayoutAdapter = function(){
23952 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23953 // do nothing for now
23954 init : function(s){
23958 * Called before drag operations to get the current size of the resizing element.
23959 * @param {Roo.SplitBar} s The SplitBar using this adapter
23961 getElementSize : function(s){
23962 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23963 return s.resizingEl.getWidth();
23965 return s.resizingEl.getHeight();
23970 * Called after drag operations to set the size of the resizing element.
23971 * @param {Roo.SplitBar} s The SplitBar using this adapter
23972 * @param {Number} newSize The new size to set
23973 * @param {Function} onComplete A function to be invoked when resizing is complete
23975 setElementSize : function(s, newSize, onComplete){
23976 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23978 s.resizingEl.setWidth(newSize);
23980 onComplete(s, newSize);
23983 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23988 s.resizingEl.setHeight(newSize);
23990 onComplete(s, newSize);
23993 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24000 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24001 * @extends Roo.SplitBar.BasicLayoutAdapter
24002 * Adapter that moves the splitter element to align with the resized sizing element.
24003 * Used with an absolute positioned SplitBar.
24004 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24005 * document.body, make sure you assign an id to the body element.
24007 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24008 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24009 this.container = Roo.get(container);
24012 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24013 init : function(s){
24014 this.basic.init(s);
24017 getElementSize : function(s){
24018 return this.basic.getElementSize(s);
24021 setElementSize : function(s, newSize, onComplete){
24022 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24025 moveSplitter : function(s){
24026 var yes = Roo.SplitBar;
24027 switch(s.placement){
24029 s.el.setX(s.resizingEl.getRight());
24032 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24035 s.el.setY(s.resizingEl.getBottom());
24038 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24045 * Orientation constant - Create a vertical SplitBar
24049 Roo.SplitBar.VERTICAL = 1;
24052 * Orientation constant - Create a horizontal SplitBar
24056 Roo.SplitBar.HORIZONTAL = 2;
24059 * Placement constant - The resizing element is to the left of the splitter element
24063 Roo.SplitBar.LEFT = 1;
24066 * Placement constant - The resizing element is to the right of the splitter element
24070 Roo.SplitBar.RIGHT = 2;
24073 * Placement constant - The resizing element is positioned above the splitter element
24077 Roo.SplitBar.TOP = 3;
24080 * Placement constant - The resizing element is positioned under splitter element
24084 Roo.SplitBar.BOTTOM = 4;
24087 * Ext JS Library 1.1.1
24088 * Copyright(c) 2006-2007, Ext JS, LLC.
24090 * Originally Released Under LGPL - original licence link has changed is not relivant.
24093 * <script type="text/javascript">
24098 * @extends Roo.util.Observable
24099 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24100 * This class also supports single and multi selection modes. <br>
24101 * Create a data model bound view:
24103 var store = new Roo.data.Store(...);
24105 var view = new Roo.View({
24107 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24109 singleSelect: true,
24110 selectedClass: "ydataview-selected",
24114 // listen for node click?
24115 view.on("click", function(vw, index, node, e){
24116 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24120 dataModel.load("foobar.xml");
24122 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24124 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24125 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24127 * Note: old style constructor is still suported (container, template, config)
24130 * Create a new View
24131 * @param {Object} config The config object
24134 Roo.View = function(config, depreciated_tpl, depreciated_config){
24136 if (typeof(depreciated_tpl) == 'undefined') {
24137 // new way.. - universal constructor.
24138 Roo.apply(this, config);
24139 this.el = Roo.get(this.el);
24142 this.el = Roo.get(config);
24143 this.tpl = depreciated_tpl;
24144 Roo.apply(this, depreciated_config);
24148 if(typeof(this.tpl) == "string"){
24149 this.tpl = new Roo.Template(this.tpl);
24151 // support xtype ctors..
24152 this.tpl = new Roo.factory(this.tpl, Roo);
24156 this.tpl.compile();
24163 * @event beforeclick
24164 * Fires before a click is processed. Returns false to cancel the default action.
24165 * @param {Roo.View} this
24166 * @param {Number} index The index of the target node
24167 * @param {HTMLElement} node The target node
24168 * @param {Roo.EventObject} e The raw event object
24170 "beforeclick" : true,
24173 * Fires when a template node is clicked.
24174 * @param {Roo.View} this
24175 * @param {Number} index The index of the target node
24176 * @param {HTMLElement} node The target node
24177 * @param {Roo.EventObject} e The raw event object
24182 * Fires when a template node is double clicked.
24183 * @param {Roo.View} this
24184 * @param {Number} index The index of the target node
24185 * @param {HTMLElement} node The target node
24186 * @param {Roo.EventObject} e The raw event object
24190 * @event contextmenu
24191 * Fires when a template node is right clicked.
24192 * @param {Roo.View} this
24193 * @param {Number} index The index of the target node
24194 * @param {HTMLElement} node The target node
24195 * @param {Roo.EventObject} e The raw event object
24197 "contextmenu" : true,
24199 * @event selectionchange
24200 * Fires when the selected nodes change.
24201 * @param {Roo.View} this
24202 * @param {Array} selections Array of the selected nodes
24204 "selectionchange" : true,
24207 * @event beforeselect
24208 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24209 * @param {Roo.View} this
24210 * @param {HTMLElement} node The node to be selected
24211 * @param {Array} selections Array of currently selected nodes
24213 "beforeselect" : true,
24215 * @event preparedata
24216 * Fires on every row to render, to allow you to change the data.
24217 * @param {Roo.View} this
24218 * @param {Object} data to be rendered (change this)
24220 "preparedata" : true
24224 "click": this.onClick,
24225 "dblclick": this.onDblClick,
24226 "contextmenu": this.onContextMenu,
24230 this.selections = [];
24232 this.cmp = new Roo.CompositeElementLite([]);
24234 this.store = Roo.factory(this.store, Roo.data);
24235 this.setStore(this.store, true);
24237 Roo.View.superclass.constructor.call(this);
24240 Roo.extend(Roo.View, Roo.util.Observable, {
24243 * @cfg {Roo.data.Store} store Data store to load data from.
24248 * @cfg {String|Roo.Element} el The container element.
24253 * @cfg {String|Roo.Template} tpl The template used by this View
24257 * @cfg {String} dataName the named area of the template to use as the data area
24258 * Works with domtemplates roo-name="name"
24262 * @cfg {String} selectedClass The css class to add to selected nodes
24264 selectedClass : "x-view-selected",
24266 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24270 * @cfg {Boolean} multiSelect Allow multiple selection
24272 multiSelect : false,
24274 * @cfg {Boolean} singleSelect Allow single selection
24276 singleSelect: false,
24279 * @cfg {Boolean} toggleSelect - selecting
24281 toggleSelect : false,
24284 * Returns the element this view is bound to.
24285 * @return {Roo.Element}
24287 getEl : function(){
24292 * Refreshes the view.
24294 refresh : function(){
24297 // if we are using something like 'domtemplate', then
24298 // the what gets used is:
24299 // t.applySubtemplate(NAME, data, wrapping data..)
24300 // the outer template then get' applied with
24301 // the store 'extra data'
24302 // and the body get's added to the
24303 // roo-name="data" node?
24304 // <span class='roo-tpl-{name}'></span> ?????
24308 this.clearSelections();
24309 this.el.update("");
24311 var records = this.store.getRange();
24312 if(records.length < 1) {
24314 // is this valid?? = should it render a template??
24316 this.el.update(this.emptyText);
24320 if (this.dataName) {
24321 this.el.update(t.apply(this.store.meta)); //????
24322 el = this.el.child('.roo-tpl-' + this.dataName);
24325 for(var i = 0, len = records.length; i < len; i++){
24326 var data = this.prepareData(records[i].data, i, records[i]);
24327 this.fireEvent("preparedata", this, data, i, records[i]);
24328 html[html.length] = Roo.util.Format.trim(
24330 t.applySubtemplate(this.dataName, data, this.store.meta) :
24337 el.update(html.join(""));
24338 this.nodes = el.dom.childNodes;
24339 this.updateIndexes(0);
24343 * Function to override to reformat the data that is sent to
24344 * the template for each node.
24345 * DEPRICATED - use the preparedata event handler.
24346 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24347 * a JSON object for an UpdateManager bound view).
24349 prepareData : function(data, index, record)
24351 this.fireEvent("preparedata", this, data, index, record);
24355 onUpdate : function(ds, record){
24356 this.clearSelections();
24357 var index = this.store.indexOf(record);
24358 var n = this.nodes[index];
24359 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24360 n.parentNode.removeChild(n);
24361 this.updateIndexes(index, index);
24367 onAdd : function(ds, records, index)
24369 this.clearSelections();
24370 if(this.nodes.length == 0){
24374 var n = this.nodes[index];
24375 for(var i = 0, len = records.length; i < len; i++){
24376 var d = this.prepareData(records[i].data, i, records[i]);
24378 this.tpl.insertBefore(n, d);
24381 this.tpl.append(this.el, d);
24384 this.updateIndexes(index);
24387 onRemove : function(ds, record, index){
24388 this.clearSelections();
24389 var el = this.dataName ?
24390 this.el.child('.roo-tpl-' + this.dataName) :
24392 el.dom.removeChild(this.nodes[index]);
24393 this.updateIndexes(index);
24397 * Refresh an individual node.
24398 * @param {Number} index
24400 refreshNode : function(index){
24401 this.onUpdate(this.store, this.store.getAt(index));
24404 updateIndexes : function(startIndex, endIndex){
24405 var ns = this.nodes;
24406 startIndex = startIndex || 0;
24407 endIndex = endIndex || ns.length - 1;
24408 for(var i = startIndex; i <= endIndex; i++){
24409 ns[i].nodeIndex = i;
24414 * Changes the data store this view uses and refresh the view.
24415 * @param {Store} store
24417 setStore : function(store, initial){
24418 if(!initial && this.store){
24419 this.store.un("datachanged", this.refresh);
24420 this.store.un("add", this.onAdd);
24421 this.store.un("remove", this.onRemove);
24422 this.store.un("update", this.onUpdate);
24423 this.store.un("clear", this.refresh);
24427 store.on("datachanged", this.refresh, this);
24428 store.on("add", this.onAdd, this);
24429 store.on("remove", this.onRemove, this);
24430 store.on("update", this.onUpdate, this);
24431 store.on("clear", this.refresh, this);
24440 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24441 * @param {HTMLElement} node
24442 * @return {HTMLElement} The template node
24444 findItemFromChild : function(node){
24445 var el = this.dataName ?
24446 this.el.child('.roo-tpl-' + this.dataName,true) :
24449 if(!node || node.parentNode == el){
24452 var p = node.parentNode;
24453 while(p && p != el){
24454 if(p.parentNode == el){
24463 onClick : function(e){
24464 var item = this.findItemFromChild(e.getTarget());
24466 var index = this.indexOf(item);
24467 if(this.onItemClick(item, index, e) !== false){
24468 this.fireEvent("click", this, index, item, e);
24471 this.clearSelections();
24476 onContextMenu : function(e){
24477 var item = this.findItemFromChild(e.getTarget());
24479 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24484 onDblClick : function(e){
24485 var item = this.findItemFromChild(e.getTarget());
24487 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24491 onItemClick : function(item, index, e)
24493 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24496 if (this.toggleSelect) {
24497 var m = this.isSelected(item) ? 'unselect' : 'select';
24500 _t[m](item, true, false);
24503 if(this.multiSelect || this.singleSelect){
24504 if(this.multiSelect && e.shiftKey && this.lastSelection){
24505 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24507 this.select(item, this.multiSelect && e.ctrlKey);
24508 this.lastSelection = item;
24510 e.preventDefault();
24516 * Get the number of selected nodes.
24519 getSelectionCount : function(){
24520 return this.selections.length;
24524 * Get the currently selected nodes.
24525 * @return {Array} An array of HTMLElements
24527 getSelectedNodes : function(){
24528 return this.selections;
24532 * Get the indexes of the selected nodes.
24535 getSelectedIndexes : function(){
24536 var indexes = [], s = this.selections;
24537 for(var i = 0, len = s.length; i < len; i++){
24538 indexes.push(s[i].nodeIndex);
24544 * Clear all selections
24545 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24547 clearSelections : function(suppressEvent){
24548 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24549 this.cmp.elements = this.selections;
24550 this.cmp.removeClass(this.selectedClass);
24551 this.selections = [];
24552 if(!suppressEvent){
24553 this.fireEvent("selectionchange", this, this.selections);
24559 * Returns true if the passed node is selected
24560 * @param {HTMLElement/Number} node The node or node index
24561 * @return {Boolean}
24563 isSelected : function(node){
24564 var s = this.selections;
24568 node = this.getNode(node);
24569 return s.indexOf(node) !== -1;
24574 * @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
24575 * @param {Boolean} keepExisting (optional) true to keep existing selections
24576 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24578 select : function(nodeInfo, keepExisting, suppressEvent){
24579 if(nodeInfo instanceof Array){
24581 this.clearSelections(true);
24583 for(var i = 0, len = nodeInfo.length; i < len; i++){
24584 this.select(nodeInfo[i], true, true);
24588 var node = this.getNode(nodeInfo);
24589 if(!node || this.isSelected(node)){
24590 return; // already selected.
24593 this.clearSelections(true);
24595 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24596 Roo.fly(node).addClass(this.selectedClass);
24597 this.selections.push(node);
24598 if(!suppressEvent){
24599 this.fireEvent("selectionchange", this, this.selections);
24607 * @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
24608 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24609 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24611 unselect : function(nodeInfo, keepExisting, suppressEvent)
24613 if(nodeInfo instanceof Array){
24614 Roo.each(this.selections, function(s) {
24615 this.unselect(s, nodeInfo);
24619 var node = this.getNode(nodeInfo);
24620 if(!node || !this.isSelected(node)){
24621 Roo.log("not selected");
24622 return; // not selected.
24626 Roo.each(this.selections, function(s) {
24628 Roo.fly(node).removeClass(this.selectedClass);
24635 this.selections= ns;
24636 this.fireEvent("selectionchange", this, this.selections);
24640 * Gets a template node.
24641 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24642 * @return {HTMLElement} The node or null if it wasn't found
24644 getNode : function(nodeInfo){
24645 if(typeof nodeInfo == "string"){
24646 return document.getElementById(nodeInfo);
24647 }else if(typeof nodeInfo == "number"){
24648 return this.nodes[nodeInfo];
24654 * Gets a range template nodes.
24655 * @param {Number} startIndex
24656 * @param {Number} endIndex
24657 * @return {Array} An array of nodes
24659 getNodes : function(start, end){
24660 var ns = this.nodes;
24661 start = start || 0;
24662 end = typeof end == "undefined" ? ns.length - 1 : end;
24665 for(var i = start; i <= end; i++){
24669 for(var i = start; i >= end; i--){
24677 * Finds the index of the passed node
24678 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24679 * @return {Number} The index of the node or -1
24681 indexOf : function(node){
24682 node = this.getNode(node);
24683 if(typeof node.nodeIndex == "number"){
24684 return node.nodeIndex;
24686 var ns = this.nodes;
24687 for(var i = 0, len = ns.length; i < len; i++){
24697 * Ext JS Library 1.1.1
24698 * Copyright(c) 2006-2007, Ext JS, LLC.
24700 * Originally Released Under LGPL - original licence link has changed is not relivant.
24703 * <script type="text/javascript">
24707 * @class Roo.JsonView
24708 * @extends Roo.View
24709 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24711 var view = new Roo.JsonView({
24712 container: "my-element",
24713 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24718 // listen for node click?
24719 view.on("click", function(vw, index, node, e){
24720 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24723 // direct load of JSON data
24724 view.load("foobar.php");
24726 // Example from my blog list
24727 var tpl = new Roo.Template(
24728 '<div class="entry">' +
24729 '<a class="entry-title" href="{link}">{title}</a>' +
24730 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24731 "</div><hr />"
24734 var moreView = new Roo.JsonView({
24735 container : "entry-list",
24739 moreView.on("beforerender", this.sortEntries, this);
24741 url: "/blog/get-posts.php",
24742 params: "allposts=true",
24743 text: "Loading Blog Entries..."
24747 * Note: old code is supported with arguments : (container, template, config)
24751 * Create a new JsonView
24753 * @param {Object} config The config object
24756 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24759 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24761 var um = this.el.getUpdateManager();
24762 um.setRenderer(this);
24763 um.on("update", this.onLoad, this);
24764 um.on("failure", this.onLoadException, this);
24767 * @event beforerender
24768 * Fires before rendering of the downloaded JSON data.
24769 * @param {Roo.JsonView} this
24770 * @param {Object} data The JSON data loaded
24774 * Fires when data is loaded.
24775 * @param {Roo.JsonView} this
24776 * @param {Object} data The JSON data loaded
24777 * @param {Object} response The raw Connect response object
24780 * @event loadexception
24781 * Fires when loading fails.
24782 * @param {Roo.JsonView} this
24783 * @param {Object} response The raw Connect response object
24786 'beforerender' : true,
24788 'loadexception' : true
24791 Roo.extend(Roo.JsonView, Roo.View, {
24793 * @type {String} The root property in the loaded JSON object that contains the data
24798 * Refreshes the view.
24800 refresh : function(){
24801 this.clearSelections();
24802 this.el.update("");
24804 var o = this.jsonData;
24805 if(o && o.length > 0){
24806 for(var i = 0, len = o.length; i < len; i++){
24807 var data = this.prepareData(o[i], i, o);
24808 html[html.length] = this.tpl.apply(data);
24811 html.push(this.emptyText);
24813 this.el.update(html.join(""));
24814 this.nodes = this.el.dom.childNodes;
24815 this.updateIndexes(0);
24819 * 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.
24820 * @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:
24823 url: "your-url.php",
24824 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24825 callback: yourFunction,
24826 scope: yourObject, //(optional scope)
24829 text: "Loading...",
24834 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24835 * 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.
24836 * @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}
24837 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24838 * @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.
24841 var um = this.el.getUpdateManager();
24842 um.update.apply(um, arguments);
24845 render : function(el, response){
24846 this.clearSelections();
24847 this.el.update("");
24850 o = Roo.util.JSON.decode(response.responseText);
24853 o = o[this.jsonRoot];
24858 * The current JSON data or null
24861 this.beforeRender();
24866 * Get the number of records in the current JSON dataset
24869 getCount : function(){
24870 return this.jsonData ? this.jsonData.length : 0;
24874 * Returns the JSON object for the specified node(s)
24875 * @param {HTMLElement/Array} node The node or an array of nodes
24876 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24877 * you get the JSON object for the node
24879 getNodeData : function(node){
24880 if(node instanceof Array){
24882 for(var i = 0, len = node.length; i < len; i++){
24883 data.push(this.getNodeData(node[i]));
24887 return this.jsonData[this.indexOf(node)] || null;
24890 beforeRender : function(){
24891 this.snapshot = this.jsonData;
24893 this.sort.apply(this, this.sortInfo);
24895 this.fireEvent("beforerender", this, this.jsonData);
24898 onLoad : function(el, o){
24899 this.fireEvent("load", this, this.jsonData, o);
24902 onLoadException : function(el, o){
24903 this.fireEvent("loadexception", this, o);
24907 * Filter the data by a specific property.
24908 * @param {String} property A property on your JSON objects
24909 * @param {String/RegExp} value Either string that the property values
24910 * should start with, or a RegExp to test against the property
24912 filter : function(property, value){
24915 var ss = this.snapshot;
24916 if(typeof value == "string"){
24917 var vlen = value.length;
24919 this.clearFilter();
24922 value = value.toLowerCase();
24923 for(var i = 0, len = ss.length; i < len; i++){
24925 if(o[property].substr(0, vlen).toLowerCase() == value){
24929 } else if(value.exec){ // regex?
24930 for(var i = 0, len = ss.length; i < len; i++){
24932 if(value.test(o[property])){
24939 this.jsonData = data;
24945 * Filter by a function. The passed function will be called with each
24946 * object in the current dataset. If the function returns true the value is kept,
24947 * otherwise it is filtered.
24948 * @param {Function} fn
24949 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24951 filterBy : function(fn, scope){
24954 var ss = this.snapshot;
24955 for(var i = 0, len = ss.length; i < len; i++){
24957 if(fn.call(scope || this, o)){
24961 this.jsonData = data;
24967 * Clears the current filter.
24969 clearFilter : function(){
24970 if(this.snapshot && this.jsonData != this.snapshot){
24971 this.jsonData = this.snapshot;
24978 * Sorts the data for this view and refreshes it.
24979 * @param {String} property A property on your JSON objects to sort on
24980 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24981 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24983 sort : function(property, dir, sortType){
24984 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24987 var dsc = dir && dir.toLowerCase() == "desc";
24988 var f = function(o1, o2){
24989 var v1 = sortType ? sortType(o1[p]) : o1[p];
24990 var v2 = sortType ? sortType(o2[p]) : o2[p];
24993 return dsc ? +1 : -1;
24994 } else if(v1 > v2){
24995 return dsc ? -1 : +1;
25000 this.jsonData.sort(f);
25002 if(this.jsonData != this.snapshot){
25003 this.snapshot.sort(f);
25009 * Ext JS Library 1.1.1
25010 * Copyright(c) 2006-2007, Ext JS, LLC.
25012 * Originally Released Under LGPL - original licence link has changed is not relivant.
25015 * <script type="text/javascript">
25020 * @class Roo.ColorPalette
25021 * @extends Roo.Component
25022 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25023 * Here's an example of typical usage:
25025 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25026 cp.render('my-div');
25028 cp.on('select', function(palette, selColor){
25029 // do something with selColor
25033 * Create a new ColorPalette
25034 * @param {Object} config The config object
25036 Roo.ColorPalette = function(config){
25037 Roo.ColorPalette.superclass.constructor.call(this, config);
25041 * Fires when a color is selected
25042 * @param {ColorPalette} this
25043 * @param {String} color The 6-digit color hex code (without the # symbol)
25049 this.on("select", this.handler, this.scope, true);
25052 Roo.extend(Roo.ColorPalette, Roo.Component, {
25054 * @cfg {String} itemCls
25055 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25057 itemCls : "x-color-palette",
25059 * @cfg {String} value
25060 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25061 * the hex codes are case-sensitive.
25064 clickEvent:'click',
25066 ctype: "Roo.ColorPalette",
25069 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25071 allowReselect : false,
25074 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25075 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25076 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25077 * of colors with the width setting until the box is symmetrical.</p>
25078 * <p>You can override individual colors if needed:</p>
25080 var cp = new Roo.ColorPalette();
25081 cp.colors[0] = "FF0000"; // change the first box to red
25084 Or you can provide a custom array of your own for complete control:
25086 var cp = new Roo.ColorPalette();
25087 cp.colors = ["000000", "993300", "333300"];
25092 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25093 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25094 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25095 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25096 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25100 onRender : function(container, position){
25101 var t = new Roo.MasterTemplate(
25102 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25104 var c = this.colors;
25105 for(var i = 0, len = c.length; i < len; i++){
25108 var el = document.createElement("div");
25109 el.className = this.itemCls;
25111 container.dom.insertBefore(el, position);
25112 this.el = Roo.get(el);
25113 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25114 if(this.clickEvent != 'click'){
25115 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25120 afterRender : function(){
25121 Roo.ColorPalette.superclass.afterRender.call(this);
25123 var s = this.value;
25130 handleClick : function(e, t){
25131 e.preventDefault();
25132 if(!this.disabled){
25133 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25134 this.select(c.toUpperCase());
25139 * Selects the specified color in the palette (fires the select event)
25140 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25142 select : function(color){
25143 color = color.replace("#", "");
25144 if(color != this.value || this.allowReselect){
25147 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25149 el.child("a.color-"+color).addClass("x-color-palette-sel");
25150 this.value = color;
25151 this.fireEvent("select", this, color);
25156 * Ext JS Library 1.1.1
25157 * Copyright(c) 2006-2007, Ext JS, LLC.
25159 * Originally Released Under LGPL - original licence link has changed is not relivant.
25162 * <script type="text/javascript">
25166 * @class Roo.DatePicker
25167 * @extends Roo.Component
25168 * Simple date picker class.
25170 * Create a new DatePicker
25171 * @param {Object} config The config object
25173 Roo.DatePicker = function(config){
25174 Roo.DatePicker.superclass.constructor.call(this, config);
25176 this.value = config && config.value ?
25177 config.value.clearTime() : new Date().clearTime();
25182 * Fires when a date is selected
25183 * @param {DatePicker} this
25184 * @param {Date} date The selected date
25188 * @event monthchange
25189 * Fires when the displayed month changes
25190 * @param {DatePicker} this
25191 * @param {Date} date The selected month
25193 'monthchange': true
25197 this.on("select", this.handler, this.scope || this);
25199 // build the disabledDatesRE
25200 if(!this.disabledDatesRE && this.disabledDates){
25201 var dd = this.disabledDates;
25203 for(var i = 0; i < dd.length; i++){
25205 if(i != dd.length-1) re += "|";
25207 this.disabledDatesRE = new RegExp(re + ")");
25211 Roo.extend(Roo.DatePicker, Roo.Component, {
25213 * @cfg {String} todayText
25214 * The text to display on the button that selects the current date (defaults to "Today")
25216 todayText : "Today",
25218 * @cfg {String} okText
25219 * The text to display on the ok button
25221 okText : " OK ", //   to give the user extra clicking room
25223 * @cfg {String} cancelText
25224 * The text to display on the cancel button
25226 cancelText : "Cancel",
25228 * @cfg {String} todayTip
25229 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25231 todayTip : "{0} (Spacebar)",
25233 * @cfg {Date} minDate
25234 * Minimum allowable date (JavaScript date object, defaults to null)
25238 * @cfg {Date} maxDate
25239 * Maximum allowable date (JavaScript date object, defaults to null)
25243 * @cfg {String} minText
25244 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25246 minText : "This date is before the minimum date",
25248 * @cfg {String} maxText
25249 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25251 maxText : "This date is after the maximum date",
25253 * @cfg {String} format
25254 * The default date format string which can be overriden for localization support. The format must be
25255 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25259 * @cfg {Array} disabledDays
25260 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25262 disabledDays : null,
25264 * @cfg {String} disabledDaysText
25265 * The tooltip to display when the date falls on a disabled day (defaults to "")
25267 disabledDaysText : "",
25269 * @cfg {RegExp} disabledDatesRE
25270 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25272 disabledDatesRE : null,
25274 * @cfg {String} disabledDatesText
25275 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25277 disabledDatesText : "",
25279 * @cfg {Boolean} constrainToViewport
25280 * True to constrain the date picker to the viewport (defaults to true)
25282 constrainToViewport : true,
25284 * @cfg {Array} monthNames
25285 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25287 monthNames : Date.monthNames,
25289 * @cfg {Array} dayNames
25290 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25292 dayNames : Date.dayNames,
25294 * @cfg {String} nextText
25295 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25297 nextText: 'Next Month (Control+Right)',
25299 * @cfg {String} prevText
25300 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25302 prevText: 'Previous Month (Control+Left)',
25304 * @cfg {String} monthYearText
25305 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25307 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25309 * @cfg {Number} startDay
25310 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25314 * @cfg {Bool} showClear
25315 * Show a clear button (usefull for date form elements that can be blank.)
25321 * Sets the value of the date field
25322 * @param {Date} value The date to set
25324 setValue : function(value){
25325 var old = this.value;
25326 this.value = value.clearTime(true);
25328 this.update(this.value);
25333 * Gets the current selected value of the date field
25334 * @return {Date} The selected date
25336 getValue : function(){
25341 focus : function(){
25343 this.update(this.activeDate);
25348 onRender : function(container, position){
25350 '<table cellspacing="0">',
25351 '<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>',
25352 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25353 var dn = this.dayNames;
25354 for(var i = 0; i < 7; i++){
25355 var d = this.startDay+i;
25359 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25361 m[m.length] = "</tr></thead><tbody><tr>";
25362 for(var i = 0; i < 42; i++) {
25363 if(i % 7 == 0 && i != 0){
25364 m[m.length] = "</tr><tr>";
25366 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25368 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25369 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25371 var el = document.createElement("div");
25372 el.className = "x-date-picker";
25373 el.innerHTML = m.join("");
25375 container.dom.insertBefore(el, position);
25377 this.el = Roo.get(el);
25378 this.eventEl = Roo.get(el.firstChild);
25380 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25381 handler: this.showPrevMonth,
25383 preventDefault:true,
25387 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25388 handler: this.showNextMonth,
25390 preventDefault:true,
25394 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25396 this.monthPicker = this.el.down('div.x-date-mp');
25397 this.monthPicker.enableDisplayMode('block');
25399 var kn = new Roo.KeyNav(this.eventEl, {
25400 "left" : function(e){
25402 this.showPrevMonth() :
25403 this.update(this.activeDate.add("d", -1));
25406 "right" : function(e){
25408 this.showNextMonth() :
25409 this.update(this.activeDate.add("d", 1));
25412 "up" : function(e){
25414 this.showNextYear() :
25415 this.update(this.activeDate.add("d", -7));
25418 "down" : function(e){
25420 this.showPrevYear() :
25421 this.update(this.activeDate.add("d", 7));
25424 "pageUp" : function(e){
25425 this.showNextMonth();
25428 "pageDown" : function(e){
25429 this.showPrevMonth();
25432 "enter" : function(e){
25433 e.stopPropagation();
25440 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25442 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25444 this.el.unselectable();
25446 this.cells = this.el.select("table.x-date-inner tbody td");
25447 this.textNodes = this.el.query("table.x-date-inner tbody span");
25449 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25451 tooltip: this.monthYearText
25454 this.mbtn.on('click', this.showMonthPicker, this);
25455 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25458 var today = (new Date()).dateFormat(this.format);
25460 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25461 if (this.showClear) {
25462 baseTb.add( new Roo.Toolbar.Fill());
25465 text: String.format(this.todayText, today),
25466 tooltip: String.format(this.todayTip, today),
25467 handler: this.selectToday,
25471 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25474 if (this.showClear) {
25476 baseTb.add( new Roo.Toolbar.Fill());
25479 cls: 'x-btn-icon x-btn-clear',
25480 handler: function() {
25482 this.fireEvent("select", this, '');
25492 this.update(this.value);
25495 createMonthPicker : function(){
25496 if(!this.monthPicker.dom.firstChild){
25497 var buf = ['<table border="0" cellspacing="0">'];
25498 for(var i = 0; i < 6; i++){
25500 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25501 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25503 '<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>' :
25504 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25508 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25510 '</button><button type="button" class="x-date-mp-cancel">',
25512 '</button></td></tr>',
25515 this.monthPicker.update(buf.join(''));
25516 this.monthPicker.on('click', this.onMonthClick, this);
25517 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25519 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25520 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25522 this.mpMonths.each(function(m, a, i){
25525 m.dom.xmonth = 5 + Math.round(i * .5);
25527 m.dom.xmonth = Math.round((i-1) * .5);
25533 showMonthPicker : function(){
25534 this.createMonthPicker();
25535 var size = this.el.getSize();
25536 this.monthPicker.setSize(size);
25537 this.monthPicker.child('table').setSize(size);
25539 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25540 this.updateMPMonth(this.mpSelMonth);
25541 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25542 this.updateMPYear(this.mpSelYear);
25544 this.monthPicker.slideIn('t', {duration:.2});
25547 updateMPYear : function(y){
25549 var ys = this.mpYears.elements;
25550 for(var i = 1; i <= 10; i++){
25551 var td = ys[i-1], y2;
25553 y2 = y + Math.round(i * .5);
25554 td.firstChild.innerHTML = y2;
25557 y2 = y - (5-Math.round(i * .5));
25558 td.firstChild.innerHTML = y2;
25561 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25565 updateMPMonth : function(sm){
25566 this.mpMonths.each(function(m, a, i){
25567 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25571 selectMPMonth: function(m){
25575 onMonthClick : function(e, t){
25577 var el = new Roo.Element(t), pn;
25578 if(el.is('button.x-date-mp-cancel')){
25579 this.hideMonthPicker();
25581 else if(el.is('button.x-date-mp-ok')){
25582 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25583 this.hideMonthPicker();
25585 else if(pn = el.up('td.x-date-mp-month', 2)){
25586 this.mpMonths.removeClass('x-date-mp-sel');
25587 pn.addClass('x-date-mp-sel');
25588 this.mpSelMonth = pn.dom.xmonth;
25590 else if(pn = el.up('td.x-date-mp-year', 2)){
25591 this.mpYears.removeClass('x-date-mp-sel');
25592 pn.addClass('x-date-mp-sel');
25593 this.mpSelYear = pn.dom.xyear;
25595 else if(el.is('a.x-date-mp-prev')){
25596 this.updateMPYear(this.mpyear-10);
25598 else if(el.is('a.x-date-mp-next')){
25599 this.updateMPYear(this.mpyear+10);
25603 onMonthDblClick : function(e, t){
25605 var el = new Roo.Element(t), pn;
25606 if(pn = el.up('td.x-date-mp-month', 2)){
25607 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25608 this.hideMonthPicker();
25610 else if(pn = el.up('td.x-date-mp-year', 2)){
25611 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25612 this.hideMonthPicker();
25616 hideMonthPicker : function(disableAnim){
25617 if(this.monthPicker){
25618 if(disableAnim === true){
25619 this.monthPicker.hide();
25621 this.monthPicker.slideOut('t', {duration:.2});
25627 showPrevMonth : function(e){
25628 this.update(this.activeDate.add("mo", -1));
25632 showNextMonth : function(e){
25633 this.update(this.activeDate.add("mo", 1));
25637 showPrevYear : function(){
25638 this.update(this.activeDate.add("y", -1));
25642 showNextYear : function(){
25643 this.update(this.activeDate.add("y", 1));
25647 handleMouseWheel : function(e){
25648 var delta = e.getWheelDelta();
25650 this.showPrevMonth();
25652 } else if(delta < 0){
25653 this.showNextMonth();
25659 handleDateClick : function(e, t){
25661 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25662 this.setValue(new Date(t.dateValue));
25663 this.fireEvent("select", this, this.value);
25668 selectToday : function(){
25669 this.setValue(new Date().clearTime());
25670 this.fireEvent("select", this, this.value);
25674 update : function(date)
25676 var vd = this.activeDate;
25677 this.activeDate = date;
25679 var t = date.getTime();
25680 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25681 this.cells.removeClass("x-date-selected");
25682 this.cells.each(function(c){
25683 if(c.dom.firstChild.dateValue == t){
25684 c.addClass("x-date-selected");
25685 setTimeout(function(){
25686 try{c.dom.firstChild.focus();}catch(e){}
25695 var days = date.getDaysInMonth();
25696 var firstOfMonth = date.getFirstDateOfMonth();
25697 var startingPos = firstOfMonth.getDay()-this.startDay;
25699 if(startingPos <= this.startDay){
25703 var pm = date.add("mo", -1);
25704 var prevStart = pm.getDaysInMonth()-startingPos;
25706 var cells = this.cells.elements;
25707 var textEls = this.textNodes;
25708 days += startingPos;
25710 // convert everything to numbers so it's fast
25711 var day = 86400000;
25712 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25713 var today = new Date().clearTime().getTime();
25714 var sel = date.clearTime().getTime();
25715 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25716 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25717 var ddMatch = this.disabledDatesRE;
25718 var ddText = this.disabledDatesText;
25719 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25720 var ddaysText = this.disabledDaysText;
25721 var format = this.format;
25723 var setCellClass = function(cal, cell){
25725 var t = d.getTime();
25726 cell.firstChild.dateValue = t;
25728 cell.className += " x-date-today";
25729 cell.title = cal.todayText;
25732 cell.className += " x-date-selected";
25733 setTimeout(function(){
25734 try{cell.firstChild.focus();}catch(e){}
25739 cell.className = " x-date-disabled";
25740 cell.title = cal.minText;
25744 cell.className = " x-date-disabled";
25745 cell.title = cal.maxText;
25749 if(ddays.indexOf(d.getDay()) != -1){
25750 cell.title = ddaysText;
25751 cell.className = " x-date-disabled";
25754 if(ddMatch && format){
25755 var fvalue = d.dateFormat(format);
25756 if(ddMatch.test(fvalue)){
25757 cell.title = ddText.replace("%0", fvalue);
25758 cell.className = " x-date-disabled";
25764 for(; i < startingPos; i++) {
25765 textEls[i].innerHTML = (++prevStart);
25766 d.setDate(d.getDate()+1);
25767 cells[i].className = "x-date-prevday";
25768 setCellClass(this, cells[i]);
25770 for(; i < days; i++){
25771 intDay = i - startingPos + 1;
25772 textEls[i].innerHTML = (intDay);
25773 d.setDate(d.getDate()+1);
25774 cells[i].className = "x-date-active";
25775 setCellClass(this, cells[i]);
25778 for(; i < 42; i++) {
25779 textEls[i].innerHTML = (++extraDays);
25780 d.setDate(d.getDate()+1);
25781 cells[i].className = "x-date-nextday";
25782 setCellClass(this, cells[i]);
25785 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25786 this.fireEvent('monthchange', this, date);
25788 if(!this.internalRender){
25789 var main = this.el.dom.firstChild;
25790 var w = main.offsetWidth;
25791 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25792 Roo.fly(main).setWidth(w);
25793 this.internalRender = true;
25794 // opera does not respect the auto grow header center column
25795 // then, after it gets a width opera refuses to recalculate
25796 // without a second pass
25797 if(Roo.isOpera && !this.secondPass){
25798 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25799 this.secondPass = true;
25800 this.update.defer(10, this, [date]);
25808 * Ext JS Library 1.1.1
25809 * Copyright(c) 2006-2007, Ext JS, LLC.
25811 * Originally Released Under LGPL - original licence link has changed is not relivant.
25814 * <script type="text/javascript">
25817 * @class Roo.TabPanel
25818 * @extends Roo.util.Observable
25819 * A lightweight tab container.
25823 // basic tabs 1, built from existing content
25824 var tabs = new Roo.TabPanel("tabs1");
25825 tabs.addTab("script", "View Script");
25826 tabs.addTab("markup", "View Markup");
25827 tabs.activate("script");
25829 // more advanced tabs, built from javascript
25830 var jtabs = new Roo.TabPanel("jtabs");
25831 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25833 // set up the UpdateManager
25834 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25835 var updater = tab2.getUpdateManager();
25836 updater.setDefaultUrl("ajax1.htm");
25837 tab2.on('activate', updater.refresh, updater, true);
25839 // Use setUrl for Ajax loading
25840 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25841 tab3.setUrl("ajax2.htm", null, true);
25844 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25847 jtabs.activate("jtabs-1");
25850 * Create a new TabPanel.
25851 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25852 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25854 Roo.TabPanel = function(container, config){
25856 * The container element for this TabPanel.
25857 * @type Roo.Element
25859 this.el = Roo.get(container, true);
25861 if(typeof config == "boolean"){
25862 this.tabPosition = config ? "bottom" : "top";
25864 Roo.apply(this, config);
25867 if(this.tabPosition == "bottom"){
25868 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25869 this.el.addClass("x-tabs-bottom");
25871 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25872 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25873 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25875 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25877 if(this.tabPosition != "bottom"){
25878 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25879 * @type Roo.Element
25881 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25882 this.el.addClass("x-tabs-top");
25886 this.bodyEl.setStyle("position", "relative");
25888 this.active = null;
25889 this.activateDelegate = this.activate.createDelegate(this);
25894 * Fires when the active tab changes
25895 * @param {Roo.TabPanel} this
25896 * @param {Roo.TabPanelItem} activePanel The new active tab
25900 * @event beforetabchange
25901 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25902 * @param {Roo.TabPanel} this
25903 * @param {Object} e Set cancel to true on this object to cancel the tab change
25904 * @param {Roo.TabPanelItem} tab The tab being changed to
25906 "beforetabchange" : true
25909 Roo.EventManager.onWindowResize(this.onResize, this);
25910 this.cpad = this.el.getPadding("lr");
25911 this.hiddenCount = 0;
25914 // toolbar on the tabbar support...
25915 if (this.toolbar) {
25916 var tcfg = this.toolbar;
25917 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25918 this.toolbar = new Roo.Toolbar(tcfg);
25919 if (Roo.isSafari) {
25920 var tbl = tcfg.container.child('table', true);
25921 tbl.setAttribute('width', '100%');
25928 Roo.TabPanel.superclass.constructor.call(this);
25931 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25933 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25935 tabPosition : "top",
25937 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25939 currentTabWidth : 0,
25941 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25945 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25949 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25951 preferredTabWidth : 175,
25953 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25955 resizeTabs : false,
25957 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25959 monitorResize : true,
25961 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25966 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25967 * @param {String} id The id of the div to use <b>or create</b>
25968 * @param {String} text The text for the tab
25969 * @param {String} content (optional) Content to put in the TabPanelItem body
25970 * @param {Boolean} closable (optional) True to create a close icon on the tab
25971 * @return {Roo.TabPanelItem} The created TabPanelItem
25973 addTab : function(id, text, content, closable){
25974 var item = new Roo.TabPanelItem(this, id, text, closable);
25975 this.addTabItem(item);
25977 item.setContent(content);
25983 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25984 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25985 * @return {Roo.TabPanelItem}
25987 getTab : function(id){
25988 return this.items[id];
25992 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25993 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25995 hideTab : function(id){
25996 var t = this.items[id];
25999 this.hiddenCount++;
26000 this.autoSizeTabs();
26005 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26006 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26008 unhideTab : function(id){
26009 var t = this.items[id];
26011 t.setHidden(false);
26012 this.hiddenCount--;
26013 this.autoSizeTabs();
26018 * Adds an existing {@link Roo.TabPanelItem}.
26019 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26021 addTabItem : function(item){
26022 this.items[item.id] = item;
26023 this.items.push(item);
26024 if(this.resizeTabs){
26025 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26026 this.autoSizeTabs();
26033 * Removes a {@link Roo.TabPanelItem}.
26034 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26036 removeTab : function(id){
26037 var items = this.items;
26038 var tab = items[id];
26039 if(!tab) { return; }
26040 var index = items.indexOf(tab);
26041 if(this.active == tab && items.length > 1){
26042 var newTab = this.getNextAvailable(index);
26047 this.stripEl.dom.removeChild(tab.pnode.dom);
26048 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26049 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26051 items.splice(index, 1);
26052 delete this.items[tab.id];
26053 tab.fireEvent("close", tab);
26054 tab.purgeListeners();
26055 this.autoSizeTabs();
26058 getNextAvailable : function(start){
26059 var items = this.items;
26061 // look for a next tab that will slide over to
26062 // replace the one being removed
26063 while(index < items.length){
26064 var item = items[++index];
26065 if(item && !item.isHidden()){
26069 // if one isn't found select the previous tab (on the left)
26072 var item = items[--index];
26073 if(item && !item.isHidden()){
26081 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26082 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26084 disableTab : function(id){
26085 var tab = this.items[id];
26086 if(tab && this.active != tab){
26092 * Enables a {@link Roo.TabPanelItem} that is disabled.
26093 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26095 enableTab : function(id){
26096 var tab = this.items[id];
26101 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26102 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26103 * @return {Roo.TabPanelItem} The TabPanelItem.
26105 activate : function(id){
26106 var tab = this.items[id];
26110 if(tab == this.active || tab.disabled){
26114 this.fireEvent("beforetabchange", this, e, tab);
26115 if(e.cancel !== true && !tab.disabled){
26117 this.active.hide();
26119 this.active = this.items[id];
26120 this.active.show();
26121 this.fireEvent("tabchange", this, this.active);
26127 * Gets the active {@link Roo.TabPanelItem}.
26128 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26130 getActiveTab : function(){
26131 return this.active;
26135 * Updates the tab body element to fit the height of the container element
26136 * for overflow scrolling
26137 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26139 syncHeight : function(targetHeight){
26140 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26141 var bm = this.bodyEl.getMargins();
26142 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26143 this.bodyEl.setHeight(newHeight);
26147 onResize : function(){
26148 if(this.monitorResize){
26149 this.autoSizeTabs();
26154 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26156 beginUpdate : function(){
26157 this.updating = true;
26161 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26163 endUpdate : function(){
26164 this.updating = false;
26165 this.autoSizeTabs();
26169 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26171 autoSizeTabs : function(){
26172 var count = this.items.length;
26173 var vcount = count - this.hiddenCount;
26174 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26175 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26176 var availWidth = Math.floor(w / vcount);
26177 var b = this.stripBody;
26178 if(b.getWidth() > w){
26179 var tabs = this.items;
26180 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26181 if(availWidth < this.minTabWidth){
26182 /*if(!this.sleft){ // incomplete scrolling code
26183 this.createScrollButtons();
26186 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26189 if(this.currentTabWidth < this.preferredTabWidth){
26190 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26196 * Returns the number of tabs in this TabPanel.
26199 getCount : function(){
26200 return this.items.length;
26204 * Resizes all the tabs to the passed width
26205 * @param {Number} The new width
26207 setTabWidth : function(width){
26208 this.currentTabWidth = width;
26209 for(var i = 0, len = this.items.length; i < len; i++) {
26210 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26215 * Destroys this TabPanel
26216 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26218 destroy : function(removeEl){
26219 Roo.EventManager.removeResizeListener(this.onResize, this);
26220 for(var i = 0, len = this.items.length; i < len; i++){
26221 this.items[i].purgeListeners();
26223 if(removeEl === true){
26224 this.el.update("");
26231 * @class Roo.TabPanelItem
26232 * @extends Roo.util.Observable
26233 * Represents an individual item (tab plus body) in a TabPanel.
26234 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26235 * @param {String} id The id of this TabPanelItem
26236 * @param {String} text The text for the tab of this TabPanelItem
26237 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26239 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26241 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26242 * @type Roo.TabPanel
26244 this.tabPanel = tabPanel;
26246 * The id for this TabPanelItem
26251 this.disabled = false;
26255 this.loaded = false;
26256 this.closable = closable;
26259 * The body element for this TabPanelItem.
26260 * @type Roo.Element
26262 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26263 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26264 this.bodyEl.setStyle("display", "block");
26265 this.bodyEl.setStyle("zoom", "1");
26268 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26270 this.el = Roo.get(els.el, true);
26271 this.inner = Roo.get(els.inner, true);
26272 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26273 this.pnode = Roo.get(els.el.parentNode, true);
26274 this.el.on("mousedown", this.onTabMouseDown, this);
26275 this.el.on("click", this.onTabClick, this);
26278 var c = Roo.get(els.close, true);
26279 c.dom.title = this.closeText;
26280 c.addClassOnOver("close-over");
26281 c.on("click", this.closeClick, this);
26287 * Fires when this tab becomes the active tab.
26288 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26289 * @param {Roo.TabPanelItem} this
26293 * @event beforeclose
26294 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26295 * @param {Roo.TabPanelItem} this
26296 * @param {Object} e Set cancel to true on this object to cancel the close.
26298 "beforeclose": true,
26301 * Fires when this tab is closed.
26302 * @param {Roo.TabPanelItem} this
26306 * @event deactivate
26307 * Fires when this tab is no longer the active tab.
26308 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26309 * @param {Roo.TabPanelItem} this
26311 "deactivate" : true
26313 this.hidden = false;
26315 Roo.TabPanelItem.superclass.constructor.call(this);
26318 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26319 purgeListeners : function(){
26320 Roo.util.Observable.prototype.purgeListeners.call(this);
26321 this.el.removeAllListeners();
26324 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26327 this.pnode.addClass("on");
26330 this.tabPanel.stripWrap.repaint();
26332 this.fireEvent("activate", this.tabPanel, this);
26336 * Returns true if this tab is the active tab.
26337 * @return {Boolean}
26339 isActive : function(){
26340 return this.tabPanel.getActiveTab() == this;
26344 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26347 this.pnode.removeClass("on");
26349 this.fireEvent("deactivate", this.tabPanel, this);
26352 hideAction : function(){
26353 this.bodyEl.hide();
26354 this.bodyEl.setStyle("position", "absolute");
26355 this.bodyEl.setLeft("-20000px");
26356 this.bodyEl.setTop("-20000px");
26359 showAction : function(){
26360 this.bodyEl.setStyle("position", "relative");
26361 this.bodyEl.setTop("");
26362 this.bodyEl.setLeft("");
26363 this.bodyEl.show();
26367 * Set the tooltip for the tab.
26368 * @param {String} tooltip The tab's tooltip
26370 setTooltip : function(text){
26371 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26372 this.textEl.dom.qtip = text;
26373 this.textEl.dom.removeAttribute('title');
26375 this.textEl.dom.title = text;
26379 onTabClick : function(e){
26380 e.preventDefault();
26381 this.tabPanel.activate(this.id);
26384 onTabMouseDown : function(e){
26385 e.preventDefault();
26386 this.tabPanel.activate(this.id);
26389 getWidth : function(){
26390 return this.inner.getWidth();
26393 setWidth : function(width){
26394 var iwidth = width - this.pnode.getPadding("lr");
26395 this.inner.setWidth(iwidth);
26396 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26397 this.pnode.setWidth(width);
26401 * Show or hide the tab
26402 * @param {Boolean} hidden True to hide or false to show.
26404 setHidden : function(hidden){
26405 this.hidden = hidden;
26406 this.pnode.setStyle("display", hidden ? "none" : "");
26410 * Returns true if this tab is "hidden"
26411 * @return {Boolean}
26413 isHidden : function(){
26414 return this.hidden;
26418 * Returns the text for this tab
26421 getText : function(){
26425 autoSize : function(){
26426 //this.el.beginMeasure();
26427 this.textEl.setWidth(1);
26428 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26429 //this.el.endMeasure();
26433 * Sets the text for the tab (Note: this also sets the tooltip text)
26434 * @param {String} text The tab's text and tooltip
26436 setText : function(text){
26438 this.textEl.update(text);
26439 this.setTooltip(text);
26440 if(!this.tabPanel.resizeTabs){
26445 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26447 activate : function(){
26448 this.tabPanel.activate(this.id);
26452 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26454 disable : function(){
26455 if(this.tabPanel.active != this){
26456 this.disabled = true;
26457 this.pnode.addClass("disabled");
26462 * Enables this TabPanelItem if it was previously disabled.
26464 enable : function(){
26465 this.disabled = false;
26466 this.pnode.removeClass("disabled");
26470 * Sets the content for this TabPanelItem.
26471 * @param {String} content The content
26472 * @param {Boolean} loadScripts true to look for and load scripts
26474 setContent : function(content, loadScripts){
26475 this.bodyEl.update(content, loadScripts);
26479 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26480 * @return {Roo.UpdateManager} The UpdateManager
26482 getUpdateManager : function(){
26483 return this.bodyEl.getUpdateManager();
26487 * Set a URL to be used to load the content for this TabPanelItem.
26488 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26489 * @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)
26490 * @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)
26491 * @return {Roo.UpdateManager} The UpdateManager
26493 setUrl : function(url, params, loadOnce){
26494 if(this.refreshDelegate){
26495 this.un('activate', this.refreshDelegate);
26497 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26498 this.on("activate", this.refreshDelegate);
26499 return this.bodyEl.getUpdateManager();
26503 _handleRefresh : function(url, params, loadOnce){
26504 if(!loadOnce || !this.loaded){
26505 var updater = this.bodyEl.getUpdateManager();
26506 updater.update(url, params, this._setLoaded.createDelegate(this));
26511 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26512 * Will fail silently if the setUrl method has not been called.
26513 * This does not activate the panel, just updates its content.
26515 refresh : function(){
26516 if(this.refreshDelegate){
26517 this.loaded = false;
26518 this.refreshDelegate();
26523 _setLoaded : function(){
26524 this.loaded = true;
26528 closeClick : function(e){
26531 this.fireEvent("beforeclose", this, o);
26532 if(o.cancel !== true){
26533 this.tabPanel.removeTab(this.id);
26537 * The text displayed in the tooltip for the close icon.
26540 closeText : "Close this tab"
26544 Roo.TabPanel.prototype.createStrip = function(container){
26545 var strip = document.createElement("div");
26546 strip.className = "x-tabs-wrap";
26547 container.appendChild(strip);
26551 Roo.TabPanel.prototype.createStripList = function(strip){
26552 // div wrapper for retard IE
26553 // returns the "tr" element.
26554 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26555 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26556 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26557 return strip.firstChild.firstChild.firstChild.firstChild;
26560 Roo.TabPanel.prototype.createBody = function(container){
26561 var body = document.createElement("div");
26562 Roo.id(body, "tab-body");
26563 Roo.fly(body).addClass("x-tabs-body");
26564 container.appendChild(body);
26568 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26569 var body = Roo.getDom(id);
26571 body = document.createElement("div");
26574 Roo.fly(body).addClass("x-tabs-item-body");
26575 bodyEl.insertBefore(body, bodyEl.firstChild);
26579 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26580 var td = document.createElement("td");
26581 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26582 //stripEl.appendChild(td);
26584 td.className = "x-tabs-closable";
26585 if(!this.closeTpl){
26586 this.closeTpl = new Roo.Template(
26587 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26588 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26589 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26592 var el = this.closeTpl.overwrite(td, {"text": text});
26593 var close = el.getElementsByTagName("div")[0];
26594 var inner = el.getElementsByTagName("em")[0];
26595 return {"el": el, "close": close, "inner": inner};
26598 this.tabTpl = new Roo.Template(
26599 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26600 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26603 var el = this.tabTpl.overwrite(td, {"text": text});
26604 var inner = el.getElementsByTagName("em")[0];
26605 return {"el": el, "inner": inner};
26609 * Ext JS Library 1.1.1
26610 * Copyright(c) 2006-2007, Ext JS, LLC.
26612 * Originally Released Under LGPL - original licence link has changed is not relivant.
26615 * <script type="text/javascript">
26619 * @class Roo.Button
26620 * @extends Roo.util.Observable
26621 * Simple Button class
26622 * @cfg {String} text The button text
26623 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26624 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26625 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26626 * @cfg {Object} scope The scope of the handler
26627 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26628 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26629 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26630 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26631 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26632 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26633 applies if enableToggle = true)
26634 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26635 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26636 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26638 * Create a new button
26639 * @param {Object} config The config object
26641 Roo.Button = function(renderTo, config)
26645 renderTo = config.renderTo || false;
26648 Roo.apply(this, config);
26652 * Fires when this button is clicked
26653 * @param {Button} this
26654 * @param {EventObject} e The click event
26659 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26660 * @param {Button} this
26661 * @param {Boolean} pressed
26666 * Fires when the mouse hovers over the button
26667 * @param {Button} this
26668 * @param {Event} e The event object
26670 'mouseover' : true,
26673 * Fires when the mouse exits the button
26674 * @param {Button} this
26675 * @param {Event} e The event object
26680 * Fires when the button is rendered
26681 * @param {Button} this
26686 this.menu = Roo.menu.MenuMgr.get(this.menu);
26688 // register listeners first!! - so render can be captured..
26689 Roo.util.Observable.call(this);
26691 this.render(renderTo);
26697 Roo.extend(Roo.Button, Roo.util.Observable, {
26703 * Read-only. True if this button is hidden
26708 * Read-only. True if this button is disabled
26713 * Read-only. True if this button is pressed (only if enableToggle = true)
26719 * @cfg {Number} tabIndex
26720 * The DOM tabIndex for this button (defaults to undefined)
26722 tabIndex : undefined,
26725 * @cfg {Boolean} enableToggle
26726 * True to enable pressed/not pressed toggling (defaults to false)
26728 enableToggle: false,
26730 * @cfg {Mixed} menu
26731 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26735 * @cfg {String} menuAlign
26736 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26738 menuAlign : "tl-bl?",
26741 * @cfg {String} iconCls
26742 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26744 iconCls : undefined,
26746 * @cfg {String} type
26747 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26752 menuClassTarget: 'tr',
26755 * @cfg {String} clickEvent
26756 * The type of event to map to the button's event handler (defaults to 'click')
26758 clickEvent : 'click',
26761 * @cfg {Boolean} handleMouseEvents
26762 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26764 handleMouseEvents : true,
26767 * @cfg {String} tooltipType
26768 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26770 tooltipType : 'qtip',
26773 * @cfg {String} cls
26774 * A CSS class to apply to the button's main element.
26778 * @cfg {Roo.Template} template (Optional)
26779 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26780 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26781 * require code modifications if required elements (e.g. a button) aren't present.
26785 render : function(renderTo){
26787 if(this.hideParent){
26788 this.parentEl = Roo.get(renderTo);
26790 if(!this.dhconfig){
26791 if(!this.template){
26792 if(!Roo.Button.buttonTemplate){
26793 // hideous table template
26794 Roo.Button.buttonTemplate = new Roo.Template(
26795 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26796 '<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>',
26797 "</tr></tbody></table>");
26799 this.template = Roo.Button.buttonTemplate;
26801 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26802 var btnEl = btn.child("button:first");
26803 btnEl.on('focus', this.onFocus, this);
26804 btnEl.on('blur', this.onBlur, this);
26806 btn.addClass(this.cls);
26809 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26812 btnEl.addClass(this.iconCls);
26814 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26817 if(this.tabIndex !== undefined){
26818 btnEl.dom.tabIndex = this.tabIndex;
26821 if(typeof this.tooltip == 'object'){
26822 Roo.QuickTips.tips(Roo.apply({
26826 btnEl.dom[this.tooltipType] = this.tooltip;
26830 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26834 this.el.dom.id = this.el.id = this.id;
26837 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26838 this.menu.on("show", this.onMenuShow, this);
26839 this.menu.on("hide", this.onMenuHide, this);
26841 btn.addClass("x-btn");
26842 if(Roo.isIE && !Roo.isIE7){
26843 this.autoWidth.defer(1, this);
26847 if(this.handleMouseEvents){
26848 btn.on("mouseover", this.onMouseOver, this);
26849 btn.on("mouseout", this.onMouseOut, this);
26850 btn.on("mousedown", this.onMouseDown, this);
26852 btn.on(this.clickEvent, this.onClick, this);
26853 //btn.on("mouseup", this.onMouseUp, this);
26860 Roo.ButtonToggleMgr.register(this);
26862 this.el.addClass("x-btn-pressed");
26865 var repeater = new Roo.util.ClickRepeater(btn,
26866 typeof this.repeat == "object" ? this.repeat : {}
26868 repeater.on("click", this.onClick, this);
26871 this.fireEvent('render', this);
26875 * Returns the button's underlying element
26876 * @return {Roo.Element} The element
26878 getEl : function(){
26883 * Destroys this Button and removes any listeners.
26885 destroy : function(){
26886 Roo.ButtonToggleMgr.unregister(this);
26887 this.el.removeAllListeners();
26888 this.purgeListeners();
26893 autoWidth : function(){
26895 this.el.setWidth("auto");
26896 if(Roo.isIE7 && Roo.isStrict){
26897 var ib = this.el.child('button');
26898 if(ib && ib.getWidth() > 20){
26900 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26905 this.el.beginMeasure();
26907 if(this.el.getWidth() < this.minWidth){
26908 this.el.setWidth(this.minWidth);
26911 this.el.endMeasure();
26918 * Assigns this button's click handler
26919 * @param {Function} handler The function to call when the button is clicked
26920 * @param {Object} scope (optional) Scope for the function passed in
26922 setHandler : function(handler, scope){
26923 this.handler = handler;
26924 this.scope = scope;
26928 * Sets this button's text
26929 * @param {String} text The button text
26931 setText : function(text){
26934 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26940 * Gets the text for this button
26941 * @return {String} The button text
26943 getText : function(){
26951 this.hidden = false;
26953 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26961 this.hidden = true;
26963 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26968 * Convenience function for boolean show/hide
26969 * @param {Boolean} visible True to show, false to hide
26971 setVisible: function(visible){
26980 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26981 * @param {Boolean} state (optional) Force a particular state
26983 toggle : function(state){
26984 state = state === undefined ? !this.pressed : state;
26985 if(state != this.pressed){
26987 this.el.addClass("x-btn-pressed");
26988 this.pressed = true;
26989 this.fireEvent("toggle", this, true);
26991 this.el.removeClass("x-btn-pressed");
26992 this.pressed = false;
26993 this.fireEvent("toggle", this, false);
26995 if(this.toggleHandler){
26996 this.toggleHandler.call(this.scope || this, this, state);
27004 focus : function(){
27005 this.el.child('button:first').focus();
27009 * Disable this button
27011 disable : function(){
27013 this.el.addClass("x-btn-disabled");
27015 this.disabled = true;
27019 * Enable this button
27021 enable : function(){
27023 this.el.removeClass("x-btn-disabled");
27025 this.disabled = false;
27029 * Convenience function for boolean enable/disable
27030 * @param {Boolean} enabled True to enable, false to disable
27032 setDisabled : function(v){
27033 this[v !== true ? "enable" : "disable"]();
27037 onClick : function(e){
27039 e.preventDefault();
27044 if(!this.disabled){
27045 if(this.enableToggle){
27048 if(this.menu && !this.menu.isVisible()){
27049 this.menu.show(this.el, this.menuAlign);
27051 this.fireEvent("click", this, e);
27053 this.el.removeClass("x-btn-over");
27054 this.handler.call(this.scope || this, this, e);
27059 onMouseOver : function(e){
27060 if(!this.disabled){
27061 this.el.addClass("x-btn-over");
27062 this.fireEvent('mouseover', this, e);
27066 onMouseOut : function(e){
27067 if(!e.within(this.el, true)){
27068 this.el.removeClass("x-btn-over");
27069 this.fireEvent('mouseout', this, e);
27073 onFocus : function(e){
27074 if(!this.disabled){
27075 this.el.addClass("x-btn-focus");
27079 onBlur : function(e){
27080 this.el.removeClass("x-btn-focus");
27083 onMouseDown : function(e){
27084 if(!this.disabled && e.button == 0){
27085 this.el.addClass("x-btn-click");
27086 Roo.get(document).on('mouseup', this.onMouseUp, this);
27090 onMouseUp : function(e){
27092 this.el.removeClass("x-btn-click");
27093 Roo.get(document).un('mouseup', this.onMouseUp, this);
27097 onMenuShow : function(e){
27098 this.el.addClass("x-btn-menu-active");
27101 onMenuHide : function(e){
27102 this.el.removeClass("x-btn-menu-active");
27106 // Private utility class used by Button
27107 Roo.ButtonToggleMgr = function(){
27110 function toggleGroup(btn, state){
27112 var g = groups[btn.toggleGroup];
27113 for(var i = 0, l = g.length; i < l; i++){
27115 g[i].toggle(false);
27122 register : function(btn){
27123 if(!btn.toggleGroup){
27126 var g = groups[btn.toggleGroup];
27128 g = groups[btn.toggleGroup] = [];
27131 btn.on("toggle", toggleGroup);
27134 unregister : function(btn){
27135 if(!btn.toggleGroup){
27138 var g = groups[btn.toggleGroup];
27141 btn.un("toggle", toggleGroup);
27147 * Ext JS Library 1.1.1
27148 * Copyright(c) 2006-2007, Ext JS, LLC.
27150 * Originally Released Under LGPL - original licence link has changed is not relivant.
27153 * <script type="text/javascript">
27157 * @class Roo.SplitButton
27158 * @extends Roo.Button
27159 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27160 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27161 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27162 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27163 * @cfg {String} arrowTooltip The title attribute of the arrow
27165 * Create a new menu button
27166 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27167 * @param {Object} config The config object
27169 Roo.SplitButton = function(renderTo, config){
27170 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27172 * @event arrowclick
27173 * Fires when this button's arrow is clicked
27174 * @param {SplitButton} this
27175 * @param {EventObject} e The click event
27177 this.addEvents({"arrowclick":true});
27180 Roo.extend(Roo.SplitButton, Roo.Button, {
27181 render : function(renderTo){
27182 // this is one sweet looking template!
27183 var tpl = new Roo.Template(
27184 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27185 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27186 '<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>',
27187 "</tbody></table></td><td>",
27188 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27189 '<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>',
27190 "</tbody></table></td></tr></table>"
27192 var btn = tpl.append(renderTo, [this.text, this.type], true);
27193 var btnEl = btn.child("button");
27195 btn.addClass(this.cls);
27198 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27201 btnEl.addClass(this.iconCls);
27203 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27207 if(this.handleMouseEvents){
27208 btn.on("mouseover", this.onMouseOver, this);
27209 btn.on("mouseout", this.onMouseOut, this);
27210 btn.on("mousedown", this.onMouseDown, this);
27211 btn.on("mouseup", this.onMouseUp, this);
27213 btn.on(this.clickEvent, this.onClick, this);
27215 if(typeof this.tooltip == 'object'){
27216 Roo.QuickTips.tips(Roo.apply({
27220 btnEl.dom[this.tooltipType] = this.tooltip;
27223 if(this.arrowTooltip){
27224 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27233 this.el.addClass("x-btn-pressed");
27235 if(Roo.isIE && !Roo.isIE7){
27236 this.autoWidth.defer(1, this);
27241 this.menu.on("show", this.onMenuShow, this);
27242 this.menu.on("hide", this.onMenuHide, this);
27244 this.fireEvent('render', this);
27248 autoWidth : function(){
27250 var tbl = this.el.child("table:first");
27251 var tbl2 = this.el.child("table:last");
27252 this.el.setWidth("auto");
27253 tbl.setWidth("auto");
27254 if(Roo.isIE7 && Roo.isStrict){
27255 var ib = this.el.child('button:first');
27256 if(ib && ib.getWidth() > 20){
27258 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27263 this.el.beginMeasure();
27265 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27266 tbl.setWidth(this.minWidth-tbl2.getWidth());
27269 this.el.endMeasure();
27272 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27276 * Sets this button's click handler
27277 * @param {Function} handler The function to call when the button is clicked
27278 * @param {Object} scope (optional) Scope for the function passed above
27280 setHandler : function(handler, scope){
27281 this.handler = handler;
27282 this.scope = scope;
27286 * Sets this button's arrow click handler
27287 * @param {Function} handler The function to call when the arrow is clicked
27288 * @param {Object} scope (optional) Scope for the function passed above
27290 setArrowHandler : function(handler, scope){
27291 this.arrowHandler = handler;
27292 this.scope = scope;
27298 focus : function(){
27300 this.el.child("button:first").focus();
27305 onClick : function(e){
27306 e.preventDefault();
27307 if(!this.disabled){
27308 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27309 if(this.menu && !this.menu.isVisible()){
27310 this.menu.show(this.el, this.menuAlign);
27312 this.fireEvent("arrowclick", this, e);
27313 if(this.arrowHandler){
27314 this.arrowHandler.call(this.scope || this, this, e);
27317 this.fireEvent("click", this, e);
27319 this.handler.call(this.scope || this, this, e);
27325 onMouseDown : function(e){
27326 if(!this.disabled){
27327 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27331 onMouseUp : function(e){
27332 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27337 // backwards compat
27338 Roo.MenuButton = Roo.SplitButton;/*
27340 * Ext JS Library 1.1.1
27341 * Copyright(c) 2006-2007, Ext JS, LLC.
27343 * Originally Released Under LGPL - original licence link has changed is not relivant.
27346 * <script type="text/javascript">
27350 * @class Roo.Toolbar
27351 * Basic Toolbar class.
27353 * Creates a new Toolbar
27354 * @param {Object} container The config object
27356 Roo.Toolbar = function(container, buttons, config)
27358 /// old consturctor format still supported..
27359 if(container instanceof Array){ // omit the container for later rendering
27360 buttons = container;
27364 if (typeof(container) == 'object' && container.xtype) {
27365 config = container;
27366 container = config.container;
27367 buttons = config.buttons || []; // not really - use items!!
27370 if (config && config.items) {
27371 xitems = config.items;
27372 delete config.items;
27374 Roo.apply(this, config);
27375 this.buttons = buttons;
27378 this.render(container);
27380 this.xitems = xitems;
27381 Roo.each(xitems, function(b) {
27387 Roo.Toolbar.prototype = {
27389 * @cfg {Array} items
27390 * array of button configs or elements to add (will be converted to a MixedCollection)
27394 * @cfg {String/HTMLElement/Element} container
27395 * The id or element that will contain the toolbar
27398 render : function(ct){
27399 this.el = Roo.get(ct);
27401 this.el.addClass(this.cls);
27403 // using a table allows for vertical alignment
27404 // 100% width is needed by Safari...
27405 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27406 this.tr = this.el.child("tr", true);
27408 this.items = new Roo.util.MixedCollection(false, function(o){
27409 return o.id || ("item" + (++autoId));
27412 this.add.apply(this, this.buttons);
27413 delete this.buttons;
27418 * Adds element(s) to the toolbar -- this function takes a variable number of
27419 * arguments of mixed type and adds them to the toolbar.
27420 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27422 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27423 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27424 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27425 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27426 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27427 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27428 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27429 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27430 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27432 * @param {Mixed} arg2
27433 * @param {Mixed} etc.
27436 var a = arguments, l = a.length;
27437 for(var i = 0; i < l; i++){
27442 _add : function(el) {
27445 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27448 if (el.applyTo){ // some kind of form field
27449 return this.addField(el);
27451 if (el.render){ // some kind of Toolbar.Item
27452 return this.addItem(el);
27454 if (typeof el == "string"){ // string
27455 if(el == "separator" || el == "-"){
27456 return this.addSeparator();
27459 return this.addSpacer();
27462 return this.addFill();
27464 return this.addText(el);
27467 if(el.tagName){ // element
27468 return this.addElement(el);
27470 if(typeof el == "object"){ // must be button config?
27471 return this.addButton(el);
27473 // and now what?!?!
27479 * Add an Xtype element
27480 * @param {Object} xtype Xtype Object
27481 * @return {Object} created Object
27483 addxtype : function(e){
27484 return this.add(e);
27488 * Returns the Element for this toolbar.
27489 * @return {Roo.Element}
27491 getEl : function(){
27497 * @return {Roo.Toolbar.Item} The separator item
27499 addSeparator : function(){
27500 return this.addItem(new Roo.Toolbar.Separator());
27504 * Adds a spacer element
27505 * @return {Roo.Toolbar.Spacer} The spacer item
27507 addSpacer : function(){
27508 return this.addItem(new Roo.Toolbar.Spacer());
27512 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27513 * @return {Roo.Toolbar.Fill} The fill item
27515 addFill : function(){
27516 return this.addItem(new Roo.Toolbar.Fill());
27520 * Adds any standard HTML element to the toolbar
27521 * @param {String/HTMLElement/Element} el The element or id of the element to add
27522 * @return {Roo.Toolbar.Item} The element's item
27524 addElement : function(el){
27525 return this.addItem(new Roo.Toolbar.Item(el));
27528 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27529 * @type Roo.util.MixedCollection
27534 * Adds any Toolbar.Item or subclass
27535 * @param {Roo.Toolbar.Item} item
27536 * @return {Roo.Toolbar.Item} The item
27538 addItem : function(item){
27539 var td = this.nextBlock();
27541 this.items.add(item);
27546 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27547 * @param {Object/Array} config A button config or array of configs
27548 * @return {Roo.Toolbar.Button/Array}
27550 addButton : function(config){
27551 if(config instanceof Array){
27553 for(var i = 0, len = config.length; i < len; i++) {
27554 buttons.push(this.addButton(config[i]));
27559 if(!(config instanceof Roo.Toolbar.Button)){
27561 new Roo.Toolbar.SplitButton(config) :
27562 new Roo.Toolbar.Button(config);
27564 var td = this.nextBlock();
27571 * Adds text to the toolbar
27572 * @param {String} text The text to add
27573 * @return {Roo.Toolbar.Item} The element's item
27575 addText : function(text){
27576 return this.addItem(new Roo.Toolbar.TextItem(text));
27580 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27581 * @param {Number} index The index where the item is to be inserted
27582 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27583 * @return {Roo.Toolbar.Button/Item}
27585 insertButton : function(index, item){
27586 if(item instanceof Array){
27588 for(var i = 0, len = item.length; i < len; i++) {
27589 buttons.push(this.insertButton(index + i, item[i]));
27593 if (!(item instanceof Roo.Toolbar.Button)){
27594 item = new Roo.Toolbar.Button(item);
27596 var td = document.createElement("td");
27597 this.tr.insertBefore(td, this.tr.childNodes[index]);
27599 this.items.insert(index, item);
27604 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27605 * @param {Object} config
27606 * @return {Roo.Toolbar.Item} The element's item
27608 addDom : function(config, returnEl){
27609 var td = this.nextBlock();
27610 Roo.DomHelper.overwrite(td, config);
27611 var ti = new Roo.Toolbar.Item(td.firstChild);
27613 this.items.add(ti);
27618 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27619 * @type Roo.util.MixedCollection
27624 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27625 * Note: the field should not have been rendered yet. For a field that has already been
27626 * rendered, use {@link #addElement}.
27627 * @param {Roo.form.Field} field
27628 * @return {Roo.ToolbarItem}
27632 addField : function(field) {
27633 if (!this.fields) {
27635 this.fields = new Roo.util.MixedCollection(false, function(o){
27636 return o.id || ("item" + (++autoId));
27641 var td = this.nextBlock();
27643 var ti = new Roo.Toolbar.Item(td.firstChild);
27645 this.items.add(ti);
27646 this.fields.add(field);
27657 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27658 this.el.child('div').hide();
27666 this.el.child('div').show();
27670 nextBlock : function(){
27671 var td = document.createElement("td");
27672 this.tr.appendChild(td);
27677 destroy : function(){
27678 if(this.items){ // rendered?
27679 Roo.destroy.apply(Roo, this.items.items);
27681 if(this.fields){ // rendered?
27682 Roo.destroy.apply(Roo, this.fields.items);
27684 Roo.Element.uncache(this.el, this.tr);
27689 * @class Roo.Toolbar.Item
27690 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27692 * Creates a new Item
27693 * @param {HTMLElement} el
27695 Roo.Toolbar.Item = function(el){
27696 this.el = Roo.getDom(el);
27697 this.id = Roo.id(this.el);
27698 this.hidden = false;
27701 Roo.Toolbar.Item.prototype = {
27704 * Get this item's HTML Element
27705 * @return {HTMLElement}
27707 getEl : function(){
27712 render : function(td){
27714 td.appendChild(this.el);
27718 * Removes and destroys this item.
27720 destroy : function(){
27721 this.td.parentNode.removeChild(this.td);
27728 this.hidden = false;
27729 this.td.style.display = "";
27736 this.hidden = true;
27737 this.td.style.display = "none";
27741 * Convenience function for boolean show/hide.
27742 * @param {Boolean} visible true to show/false to hide
27744 setVisible: function(visible){
27753 * Try to focus this item.
27755 focus : function(){
27756 Roo.fly(this.el).focus();
27760 * Disables this item.
27762 disable : function(){
27763 Roo.fly(this.td).addClass("x-item-disabled");
27764 this.disabled = true;
27765 this.el.disabled = true;
27769 * Enables this item.
27771 enable : function(){
27772 Roo.fly(this.td).removeClass("x-item-disabled");
27773 this.disabled = false;
27774 this.el.disabled = false;
27780 * @class Roo.Toolbar.Separator
27781 * @extends Roo.Toolbar.Item
27782 * A simple toolbar separator class
27784 * Creates a new Separator
27786 Roo.Toolbar.Separator = function(){
27787 var s = document.createElement("span");
27788 s.className = "ytb-sep";
27789 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27791 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27792 enable:Roo.emptyFn,
27793 disable:Roo.emptyFn,
27798 * @class Roo.Toolbar.Spacer
27799 * @extends Roo.Toolbar.Item
27800 * A simple element that adds extra horizontal space to a toolbar.
27802 * Creates a new Spacer
27804 Roo.Toolbar.Spacer = function(){
27805 var s = document.createElement("div");
27806 s.className = "ytb-spacer";
27807 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27809 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27810 enable:Roo.emptyFn,
27811 disable:Roo.emptyFn,
27816 * @class Roo.Toolbar.Fill
27817 * @extends Roo.Toolbar.Spacer
27818 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27820 * Creates a new Spacer
27822 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27824 render : function(td){
27825 td.style.width = '100%';
27826 Roo.Toolbar.Fill.superclass.render.call(this, td);
27831 * @class Roo.Toolbar.TextItem
27832 * @extends Roo.Toolbar.Item
27833 * A simple class that renders text directly into a toolbar.
27835 * Creates a new TextItem
27836 * @param {String} text
27838 Roo.Toolbar.TextItem = function(text){
27839 if (typeof(text) == 'object') {
27842 var s = document.createElement("span");
27843 s.className = "ytb-text";
27844 s.innerHTML = text;
27845 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27847 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27848 enable:Roo.emptyFn,
27849 disable:Roo.emptyFn,
27854 * @class Roo.Toolbar.Button
27855 * @extends Roo.Button
27856 * A button that renders into a toolbar.
27858 * Creates a new Button
27859 * @param {Object} config A standard {@link Roo.Button} config object
27861 Roo.Toolbar.Button = function(config){
27862 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27864 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27865 render : function(td){
27867 Roo.Toolbar.Button.superclass.render.call(this, td);
27871 * Removes and destroys this button
27873 destroy : function(){
27874 Roo.Toolbar.Button.superclass.destroy.call(this);
27875 this.td.parentNode.removeChild(this.td);
27879 * Shows this button
27882 this.hidden = false;
27883 this.td.style.display = "";
27887 * Hides this button
27890 this.hidden = true;
27891 this.td.style.display = "none";
27895 * Disables this item
27897 disable : function(){
27898 Roo.fly(this.td).addClass("x-item-disabled");
27899 this.disabled = true;
27903 * Enables this item
27905 enable : function(){
27906 Roo.fly(this.td).removeClass("x-item-disabled");
27907 this.disabled = false;
27910 // backwards compat
27911 Roo.ToolbarButton = Roo.Toolbar.Button;
27914 * @class Roo.Toolbar.SplitButton
27915 * @extends Roo.SplitButton
27916 * A menu button that renders into a toolbar.
27918 * Creates a new SplitButton
27919 * @param {Object} config A standard {@link Roo.SplitButton} config object
27921 Roo.Toolbar.SplitButton = function(config){
27922 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27924 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27925 render : function(td){
27927 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27931 * Removes and destroys this button
27933 destroy : function(){
27934 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27935 this.td.parentNode.removeChild(this.td);
27939 * Shows this button
27942 this.hidden = false;
27943 this.td.style.display = "";
27947 * Hides this button
27950 this.hidden = true;
27951 this.td.style.display = "none";
27955 // backwards compat
27956 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27958 * Ext JS Library 1.1.1
27959 * Copyright(c) 2006-2007, Ext JS, LLC.
27961 * Originally Released Under LGPL - original licence link has changed is not relivant.
27964 * <script type="text/javascript">
27968 * @class Roo.PagingToolbar
27969 * @extends Roo.Toolbar
27970 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27972 * Create a new PagingToolbar
27973 * @param {Object} config The config object
27975 Roo.PagingToolbar = function(el, ds, config)
27977 // old args format still supported... - xtype is prefered..
27978 if (typeof(el) == 'object' && el.xtype) {
27979 // created from xtype...
27981 ds = el.dataSource;
27982 el = config.container;
27985 if (config.items) {
27986 items = config.items;
27990 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27993 this.renderButtons(this.el);
27996 // supprot items array.
27998 Roo.each(items, function(e) {
27999 this.add(Roo.factory(e));
28004 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28006 * @cfg {Roo.data.Store} dataSource
28007 * The underlying data store providing the paged data
28010 * @cfg {String/HTMLElement/Element} container
28011 * container The id or element that will contain the toolbar
28014 * @cfg {Boolean} displayInfo
28015 * True to display the displayMsg (defaults to false)
28018 * @cfg {Number} pageSize
28019 * The number of records to display per page (defaults to 20)
28023 * @cfg {String} displayMsg
28024 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28026 displayMsg : 'Displaying {0} - {1} of {2}',
28028 * @cfg {String} emptyMsg
28029 * The message to display when no records are found (defaults to "No data to display")
28031 emptyMsg : 'No data to display',
28033 * Customizable piece of the default paging text (defaults to "Page")
28036 beforePageText : "Page",
28038 * Customizable piece of the default paging text (defaults to "of %0")
28041 afterPageText : "of {0}",
28043 * Customizable piece of the default paging text (defaults to "First Page")
28046 firstText : "First Page",
28048 * Customizable piece of the default paging text (defaults to "Previous Page")
28051 prevText : "Previous Page",
28053 * Customizable piece of the default paging text (defaults to "Next Page")
28056 nextText : "Next Page",
28058 * Customizable piece of the default paging text (defaults to "Last Page")
28061 lastText : "Last Page",
28063 * Customizable piece of the default paging text (defaults to "Refresh")
28066 refreshText : "Refresh",
28069 renderButtons : function(el){
28070 Roo.PagingToolbar.superclass.render.call(this, el);
28071 this.first = this.addButton({
28072 tooltip: this.firstText,
28073 cls: "x-btn-icon x-grid-page-first",
28075 handler: this.onClick.createDelegate(this, ["first"])
28077 this.prev = this.addButton({
28078 tooltip: this.prevText,
28079 cls: "x-btn-icon x-grid-page-prev",
28081 handler: this.onClick.createDelegate(this, ["prev"])
28083 //this.addSeparator();
28084 this.add(this.beforePageText);
28085 this.field = Roo.get(this.addDom({
28090 cls: "x-grid-page-number"
28092 this.field.on("keydown", this.onPagingKeydown, this);
28093 this.field.on("focus", function(){this.dom.select();});
28094 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28095 this.field.setHeight(18);
28096 //this.addSeparator();
28097 this.next = this.addButton({
28098 tooltip: this.nextText,
28099 cls: "x-btn-icon x-grid-page-next",
28101 handler: this.onClick.createDelegate(this, ["next"])
28103 this.last = this.addButton({
28104 tooltip: this.lastText,
28105 cls: "x-btn-icon x-grid-page-last",
28107 handler: this.onClick.createDelegate(this, ["last"])
28109 //this.addSeparator();
28110 this.loading = this.addButton({
28111 tooltip: this.refreshText,
28112 cls: "x-btn-icon x-grid-loading",
28113 handler: this.onClick.createDelegate(this, ["refresh"])
28116 if(this.displayInfo){
28117 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28122 updateInfo : function(){
28123 if(this.displayEl){
28124 var count = this.ds.getCount();
28125 var msg = count == 0 ?
28129 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28131 this.displayEl.update(msg);
28136 onLoad : function(ds, r, o){
28137 this.cursor = o.params ? o.params.start : 0;
28138 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28140 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28141 this.field.dom.value = ap;
28142 this.first.setDisabled(ap == 1);
28143 this.prev.setDisabled(ap == 1);
28144 this.next.setDisabled(ap == ps);
28145 this.last.setDisabled(ap == ps);
28146 this.loading.enable();
28151 getPageData : function(){
28152 var total = this.ds.getTotalCount();
28155 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28156 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28161 onLoadError : function(){
28162 this.loading.enable();
28166 onPagingKeydown : function(e){
28167 var k = e.getKey();
28168 var d = this.getPageData();
28170 var v = this.field.dom.value, pageNum;
28171 if(!v || isNaN(pageNum = parseInt(v, 10))){
28172 this.field.dom.value = d.activePage;
28175 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28176 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28179 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))
28181 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28182 this.field.dom.value = pageNum;
28183 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28186 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28188 var v = this.field.dom.value, pageNum;
28189 var increment = (e.shiftKey) ? 10 : 1;
28190 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28192 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28193 this.field.dom.value = d.activePage;
28196 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28198 this.field.dom.value = parseInt(v, 10) + increment;
28199 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28200 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28207 beforeLoad : function(){
28209 this.loading.disable();
28214 onClick : function(which){
28218 ds.load({params:{start: 0, limit: this.pageSize}});
28221 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28224 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28227 var total = ds.getTotalCount();
28228 var extra = total % this.pageSize;
28229 var lastStart = extra ? (total - extra) : total-this.pageSize;
28230 ds.load({params:{start: lastStart, limit: this.pageSize}});
28233 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28239 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28240 * @param {Roo.data.Store} store The data store to unbind
28242 unbind : function(ds){
28243 ds.un("beforeload", this.beforeLoad, this);
28244 ds.un("load", this.onLoad, this);
28245 ds.un("loadexception", this.onLoadError, this);
28246 ds.un("remove", this.updateInfo, this);
28247 ds.un("add", this.updateInfo, this);
28248 this.ds = undefined;
28252 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28253 * @param {Roo.data.Store} store The data store to bind
28255 bind : function(ds){
28256 ds.on("beforeload", this.beforeLoad, this);
28257 ds.on("load", this.onLoad, this);
28258 ds.on("loadexception", this.onLoadError, this);
28259 ds.on("remove", this.updateInfo, this);
28260 ds.on("add", this.updateInfo, this);
28265 * Ext JS Library 1.1.1
28266 * Copyright(c) 2006-2007, Ext JS, LLC.
28268 * Originally Released Under LGPL - original licence link has changed is not relivant.
28271 * <script type="text/javascript">
28275 * @class Roo.Resizable
28276 * @extends Roo.util.Observable
28277 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28278 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28279 * 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
28280 * the element will be wrapped for you automatically.</p>
28281 * <p>Here is the list of valid resize handles:</p>
28284 ------ -------------------
28293 'hd' horizontal drag
28296 * <p>Here's an example showing the creation of a typical Resizable:</p>
28298 var resizer = new Roo.Resizable("element-id", {
28306 resizer.on("resize", myHandler);
28308 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28309 * resizer.east.setDisplayed(false);</p>
28310 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28311 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28312 * resize operation's new size (defaults to [0, 0])
28313 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28314 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28315 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28316 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28317 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28318 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28319 * @cfg {Number} width The width of the element in pixels (defaults to null)
28320 * @cfg {Number} height The height of the element in pixels (defaults to null)
28321 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28322 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28323 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28324 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28325 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28326 * in favor of the handles config option (defaults to false)
28327 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28328 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28329 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28330 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28331 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28332 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28333 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28334 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28335 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28336 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28337 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28339 * Create a new resizable component
28340 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28341 * @param {Object} config configuration options
28343 Roo.Resizable = function(el, config)
28345 this.el = Roo.get(el);
28347 if(config && config.wrap){
28348 config.resizeChild = this.el;
28349 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28350 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28351 this.el.setStyle("overflow", "hidden");
28352 this.el.setPositioning(config.resizeChild.getPositioning());
28353 config.resizeChild.clearPositioning();
28354 if(!config.width || !config.height){
28355 var csize = config.resizeChild.getSize();
28356 this.el.setSize(csize.width, csize.height);
28358 if(config.pinned && !config.adjustments){
28359 config.adjustments = "auto";
28363 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28364 this.proxy.unselectable();
28365 this.proxy.enableDisplayMode('block');
28367 Roo.apply(this, config);
28370 this.disableTrackOver = true;
28371 this.el.addClass("x-resizable-pinned");
28373 // if the element isn't positioned, make it relative
28374 var position = this.el.getStyle("position");
28375 if(position != "absolute" && position != "fixed"){
28376 this.el.setStyle("position", "relative");
28378 if(!this.handles){ // no handles passed, must be legacy style
28379 this.handles = 's,e,se';
28380 if(this.multiDirectional){
28381 this.handles += ',n,w';
28384 if(this.handles == "all"){
28385 this.handles = "n s e w ne nw se sw";
28387 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28388 var ps = Roo.Resizable.positions;
28389 for(var i = 0, len = hs.length; i < len; i++){
28390 if(hs[i] && ps[hs[i]]){
28391 var pos = ps[hs[i]];
28392 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28396 this.corner = this.southeast;
28398 // updateBox = the box can move..
28399 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28400 this.updateBox = true;
28403 this.activeHandle = null;
28405 if(this.resizeChild){
28406 if(typeof this.resizeChild == "boolean"){
28407 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28409 this.resizeChild = Roo.get(this.resizeChild, true);
28413 if(this.adjustments == "auto"){
28414 var rc = this.resizeChild;
28415 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28416 if(rc && (hw || hn)){
28417 rc.position("relative");
28418 rc.setLeft(hw ? hw.el.getWidth() : 0);
28419 rc.setTop(hn ? hn.el.getHeight() : 0);
28421 this.adjustments = [
28422 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28423 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28427 if(this.draggable){
28428 this.dd = this.dynamic ?
28429 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28430 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28436 * @event beforeresize
28437 * Fired before resize is allowed. Set enabled to false to cancel resize.
28438 * @param {Roo.Resizable} this
28439 * @param {Roo.EventObject} e The mousedown event
28441 "beforeresize" : true,
28444 * Fired after a resize.
28445 * @param {Roo.Resizable} this
28446 * @param {Number} width The new width
28447 * @param {Number} height The new height
28448 * @param {Roo.EventObject} e The mouseup event
28453 if(this.width !== null && this.height !== null){
28454 this.resizeTo(this.width, this.height);
28456 this.updateChildSize();
28459 this.el.dom.style.zoom = 1;
28461 Roo.Resizable.superclass.constructor.call(this);
28464 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28465 resizeChild : false,
28466 adjustments : [0, 0],
28476 multiDirectional : false,
28477 disableTrackOver : false,
28478 easing : 'easeOutStrong',
28479 widthIncrement : 0,
28480 heightIncrement : 0,
28484 preserveRatio : false,
28485 transparent: false,
28491 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28493 constrainTo: undefined,
28495 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28497 resizeRegion: undefined,
28501 * Perform a manual resize
28502 * @param {Number} width
28503 * @param {Number} height
28505 resizeTo : function(width, height){
28506 this.el.setSize(width, height);
28507 this.updateChildSize();
28508 this.fireEvent("resize", this, width, height, null);
28512 startSizing : function(e, handle){
28513 this.fireEvent("beforeresize", this, e);
28514 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28517 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28518 this.overlay.unselectable();
28519 this.overlay.enableDisplayMode("block");
28520 this.overlay.on("mousemove", this.onMouseMove, this);
28521 this.overlay.on("mouseup", this.onMouseUp, this);
28523 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28525 this.resizing = true;
28526 this.startBox = this.el.getBox();
28527 this.startPoint = e.getXY();
28528 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28529 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28531 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28532 this.overlay.show();
28534 if(this.constrainTo) {
28535 var ct = Roo.get(this.constrainTo);
28536 this.resizeRegion = ct.getRegion().adjust(
28537 ct.getFrameWidth('t'),
28538 ct.getFrameWidth('l'),
28539 -ct.getFrameWidth('b'),
28540 -ct.getFrameWidth('r')
28544 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28546 this.proxy.setBox(this.startBox);
28548 this.proxy.setStyle('visibility', 'visible');
28554 onMouseDown : function(handle, e){
28557 this.activeHandle = handle;
28558 this.startSizing(e, handle);
28563 onMouseUp : function(e){
28564 var size = this.resizeElement();
28565 this.resizing = false;
28567 this.overlay.hide();
28569 this.fireEvent("resize", this, size.width, size.height, e);
28573 updateChildSize : function(){
28574 if(this.resizeChild){
28576 var child = this.resizeChild;
28577 var adj = this.adjustments;
28578 if(el.dom.offsetWidth){
28579 var b = el.getSize(true);
28580 child.setSize(b.width+adj[0], b.height+adj[1]);
28582 // Second call here for IE
28583 // The first call enables instant resizing and
28584 // the second call corrects scroll bars if they
28587 setTimeout(function(){
28588 if(el.dom.offsetWidth){
28589 var b = el.getSize(true);
28590 child.setSize(b.width+adj[0], b.height+adj[1]);
28598 snap : function(value, inc, min){
28599 if(!inc || !value) return value;
28600 var newValue = value;
28601 var m = value % inc;
28604 newValue = value + (inc-m);
28606 newValue = value - m;
28609 return Math.max(min, newValue);
28613 resizeElement : function(){
28614 var box = this.proxy.getBox();
28615 if(this.updateBox){
28616 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28618 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28620 this.updateChildSize();
28628 constrain : function(v, diff, m, mx){
28631 }else if(v - diff > mx){
28638 onMouseMove : function(e){
28640 try{// try catch so if something goes wrong the user doesn't get hung
28642 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28646 //var curXY = this.startPoint;
28647 var curSize = this.curSize || this.startBox;
28648 var x = this.startBox.x, y = this.startBox.y;
28649 var ox = x, oy = y;
28650 var w = curSize.width, h = curSize.height;
28651 var ow = w, oh = h;
28652 var mw = this.minWidth, mh = this.minHeight;
28653 var mxw = this.maxWidth, mxh = this.maxHeight;
28654 var wi = this.widthIncrement;
28655 var hi = this.heightIncrement;
28657 var eventXY = e.getXY();
28658 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28659 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28661 var pos = this.activeHandle.position;
28666 w = Math.min(Math.max(mw, w), mxw);
28671 h = Math.min(Math.max(mh, h), mxh);
28676 w = Math.min(Math.max(mw, w), mxw);
28677 h = Math.min(Math.max(mh, h), mxh);
28680 diffY = this.constrain(h, diffY, mh, mxh);
28687 var adiffX = Math.abs(diffX);
28688 var sub = (adiffX % wi); // how much
28689 if (sub > (wi/2)) { // far enough to snap
28690 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28692 // remove difference..
28693 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28697 x = Math.max(this.minX, x);
28700 diffX = this.constrain(w, diffX, mw, mxw);
28706 w = Math.min(Math.max(mw, w), mxw);
28707 diffY = this.constrain(h, diffY, mh, mxh);
28712 diffX = this.constrain(w, diffX, mw, mxw);
28713 diffY = this.constrain(h, diffY, mh, mxh);
28720 diffX = this.constrain(w, diffX, mw, mxw);
28722 h = Math.min(Math.max(mh, h), mxh);
28728 var sw = this.snap(w, wi, mw);
28729 var sh = this.snap(h, hi, mh);
28730 if(sw != w || sh != h){
28753 if(this.preserveRatio){
28758 h = Math.min(Math.max(mh, h), mxh);
28763 w = Math.min(Math.max(mw, w), mxw);
28768 w = Math.min(Math.max(mw, w), mxw);
28774 w = Math.min(Math.max(mw, w), mxw);
28780 h = Math.min(Math.max(mh, h), mxh);
28788 h = Math.min(Math.max(mh, h), mxh);
28798 h = Math.min(Math.max(mh, h), mxh);
28806 if (pos == 'hdrag') {
28809 this.proxy.setBounds(x, y, w, h);
28811 this.resizeElement();
28818 handleOver : function(){
28820 this.el.addClass("x-resizable-over");
28825 handleOut : function(){
28826 if(!this.resizing){
28827 this.el.removeClass("x-resizable-over");
28832 * Returns the element this component is bound to.
28833 * @return {Roo.Element}
28835 getEl : function(){
28840 * Returns the resizeChild element (or null).
28841 * @return {Roo.Element}
28843 getResizeChild : function(){
28844 return this.resizeChild;
28848 * Destroys this resizable. If the element was wrapped and
28849 * removeEl is not true then the element remains.
28850 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28852 destroy : function(removeEl){
28853 this.proxy.remove();
28855 this.overlay.removeAllListeners();
28856 this.overlay.remove();
28858 var ps = Roo.Resizable.positions;
28860 if(typeof ps[k] != "function" && this[ps[k]]){
28861 var h = this[ps[k]];
28862 h.el.removeAllListeners();
28867 this.el.update("");
28874 // hash to map config positions to true positions
28875 Roo.Resizable.positions = {
28876 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28881 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28883 // only initialize the template if resizable is used
28884 var tpl = Roo.DomHelper.createTemplate(
28885 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28888 Roo.Resizable.Handle.prototype.tpl = tpl;
28890 this.position = pos;
28892 // show north drag fro topdra
28893 var handlepos = pos == 'hdrag' ? 'north' : pos;
28895 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28896 if (pos == 'hdrag') {
28897 this.el.setStyle('cursor', 'pointer');
28899 this.el.unselectable();
28901 this.el.setOpacity(0);
28903 this.el.on("mousedown", this.onMouseDown, this);
28904 if(!disableTrackOver){
28905 this.el.on("mouseover", this.onMouseOver, this);
28906 this.el.on("mouseout", this.onMouseOut, this);
28911 Roo.Resizable.Handle.prototype = {
28912 afterResize : function(rz){
28916 onMouseDown : function(e){
28917 this.rz.onMouseDown(this, e);
28920 onMouseOver : function(e){
28921 this.rz.handleOver(this, e);
28924 onMouseOut : function(e){
28925 this.rz.handleOut(this, e);
28929 * Ext JS Library 1.1.1
28930 * Copyright(c) 2006-2007, Ext JS, LLC.
28932 * Originally Released Under LGPL - original licence link has changed is not relivant.
28935 * <script type="text/javascript">
28939 * @class Roo.Editor
28940 * @extends Roo.Component
28941 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28943 * Create a new Editor
28944 * @param {Roo.form.Field} field The Field object (or descendant)
28945 * @param {Object} config The config object
28947 Roo.Editor = function(field, config){
28948 Roo.Editor.superclass.constructor.call(this, config);
28949 this.field = field;
28952 * @event beforestartedit
28953 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28954 * false from the handler of this event.
28955 * @param {Editor} this
28956 * @param {Roo.Element} boundEl The underlying element bound to this editor
28957 * @param {Mixed} value The field value being set
28959 "beforestartedit" : true,
28962 * Fires when this editor is displayed
28963 * @param {Roo.Element} boundEl The underlying element bound to this editor
28964 * @param {Mixed} value The starting field value
28966 "startedit" : true,
28968 * @event beforecomplete
28969 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28970 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28971 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28972 * event will not fire since no edit actually occurred.
28973 * @param {Editor} this
28974 * @param {Mixed} value The current field value
28975 * @param {Mixed} startValue The original field value
28977 "beforecomplete" : true,
28980 * Fires after editing is complete and any changed value has been written to the underlying field.
28981 * @param {Editor} this
28982 * @param {Mixed} value The current field value
28983 * @param {Mixed} startValue The original field value
28987 * @event specialkey
28988 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28989 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28990 * @param {Roo.form.Field} this
28991 * @param {Roo.EventObject} e The event object
28993 "specialkey" : true
28997 Roo.extend(Roo.Editor, Roo.Component, {
28999 * @cfg {Boolean/String} autosize
29000 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29001 * or "height" to adopt the height only (defaults to false)
29004 * @cfg {Boolean} revertInvalid
29005 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29006 * validation fails (defaults to true)
29009 * @cfg {Boolean} ignoreNoChange
29010 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29011 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29012 * will never be ignored.
29015 * @cfg {Boolean} hideEl
29016 * False to keep the bound element visible while the editor is displayed (defaults to true)
29019 * @cfg {Mixed} value
29020 * The data value of the underlying field (defaults to "")
29024 * @cfg {String} alignment
29025 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29029 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29030 * for bottom-right shadow (defaults to "frame")
29034 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29038 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29040 completeOnEnter : false,
29042 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29044 cancelOnEsc : false,
29046 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29051 onRender : function(ct, position){
29052 this.el = new Roo.Layer({
29053 shadow: this.shadow,
29059 constrain: this.constrain
29061 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29062 if(this.field.msgTarget != 'title'){
29063 this.field.msgTarget = 'qtip';
29065 this.field.render(this.el);
29067 this.field.el.dom.setAttribute('autocomplete', 'off');
29069 this.field.on("specialkey", this.onSpecialKey, this);
29070 if(this.swallowKeys){
29071 this.field.el.swallowEvent(['keydown','keypress']);
29074 this.field.on("blur", this.onBlur, this);
29075 if(this.field.grow){
29076 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29080 onSpecialKey : function(field, e)
29082 //Roo.log('editor onSpecialKey');
29083 if(this.completeOnEnter && e.getKey() == e.ENTER){
29085 this.completeEdit();
29088 // do not fire special key otherwise it might hide close the editor...
29089 if(e.getKey() == e.ENTER){
29092 if(this.cancelOnEsc && e.getKey() == e.ESC){
29096 this.fireEvent('specialkey', field, e);
29101 * Starts the editing process and shows the editor.
29102 * @param {String/HTMLElement/Element} el The element to edit
29103 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29104 * to the innerHTML of el.
29106 startEdit : function(el, value){
29108 this.completeEdit();
29110 this.boundEl = Roo.get(el);
29111 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29112 if(!this.rendered){
29113 this.render(this.parentEl || document.body);
29115 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29118 this.startValue = v;
29119 this.field.setValue(v);
29121 var sz = this.boundEl.getSize();
29122 switch(this.autoSize){
29124 this.setSize(sz.width, "");
29127 this.setSize("", sz.height);
29130 this.setSize(sz.width, sz.height);
29133 this.el.alignTo(this.boundEl, this.alignment);
29134 this.editing = true;
29136 Roo.QuickTips.disable();
29142 * Sets the height and width of this editor.
29143 * @param {Number} width The new width
29144 * @param {Number} height The new height
29146 setSize : function(w, h){
29147 this.field.setSize(w, h);
29154 * Realigns the editor to the bound field based on the current alignment config value.
29156 realign : function(){
29157 this.el.alignTo(this.boundEl, this.alignment);
29161 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29162 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29164 completeEdit : function(remainVisible){
29168 var v = this.getValue();
29169 if(this.revertInvalid !== false && !this.field.isValid()){
29170 v = this.startValue;
29171 this.cancelEdit(true);
29173 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29174 this.editing = false;
29178 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29179 this.editing = false;
29180 if(this.updateEl && this.boundEl){
29181 this.boundEl.update(v);
29183 if(remainVisible !== true){
29186 this.fireEvent("complete", this, v, this.startValue);
29191 onShow : function(){
29193 if(this.hideEl !== false){
29194 this.boundEl.hide();
29197 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29198 this.fixIEFocus = true;
29199 this.deferredFocus.defer(50, this);
29201 this.field.focus();
29203 this.fireEvent("startedit", this.boundEl, this.startValue);
29206 deferredFocus : function(){
29208 this.field.focus();
29213 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29214 * reverted to the original starting value.
29215 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29216 * cancel (defaults to false)
29218 cancelEdit : function(remainVisible){
29220 this.setValue(this.startValue);
29221 if(remainVisible !== true){
29228 onBlur : function(){
29229 if(this.allowBlur !== true && this.editing){
29230 this.completeEdit();
29235 onHide : function(){
29237 this.completeEdit();
29241 if(this.field.collapse){
29242 this.field.collapse();
29245 if(this.hideEl !== false){
29246 this.boundEl.show();
29249 Roo.QuickTips.enable();
29254 * Sets the data value of the editor
29255 * @param {Mixed} value Any valid value supported by the underlying field
29257 setValue : function(v){
29258 this.field.setValue(v);
29262 * Gets the data value of the editor
29263 * @return {Mixed} The data value
29265 getValue : function(){
29266 return this.field.getValue();
29270 * Ext JS Library 1.1.1
29271 * Copyright(c) 2006-2007, Ext JS, LLC.
29273 * Originally Released Under LGPL - original licence link has changed is not relivant.
29276 * <script type="text/javascript">
29280 * @class Roo.BasicDialog
29281 * @extends Roo.util.Observable
29282 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29284 var dlg = new Roo.BasicDialog("my-dlg", {
29293 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29294 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29295 dlg.addButton('Cancel', dlg.hide, dlg);
29298 <b>A Dialog should always be a direct child of the body element.</b>
29299 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29300 * @cfg {String} title Default text to display in the title bar (defaults to null)
29301 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29302 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29303 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29304 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29305 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29306 * (defaults to null with no animation)
29307 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29308 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29309 * property for valid values (defaults to 'all')
29310 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29311 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29312 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29313 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29314 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29315 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29316 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29317 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29318 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29319 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29320 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29321 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29322 * draggable = true (defaults to false)
29323 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29324 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29325 * shadow (defaults to false)
29326 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29327 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29328 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29329 * @cfg {Array} buttons Array of buttons
29330 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29332 * Create a new BasicDialog.
29333 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29334 * @param {Object} config Configuration options
29336 Roo.BasicDialog = function(el, config){
29337 this.el = Roo.get(el);
29338 var dh = Roo.DomHelper;
29339 if(!this.el && config && config.autoCreate){
29340 if(typeof config.autoCreate == "object"){
29341 if(!config.autoCreate.id){
29342 config.autoCreate.id = el;
29344 this.el = dh.append(document.body,
29345 config.autoCreate, true);
29347 this.el = dh.append(document.body,
29348 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29352 el.setDisplayed(true);
29353 el.hide = this.hideAction;
29355 el.addClass("x-dlg");
29357 Roo.apply(this, config);
29359 this.proxy = el.createProxy("x-dlg-proxy");
29360 this.proxy.hide = this.hideAction;
29361 this.proxy.setOpacity(.5);
29365 el.setWidth(config.width);
29368 el.setHeight(config.height);
29370 this.size = el.getSize();
29371 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29372 this.xy = [config.x,config.y];
29374 this.xy = el.getCenterXY(true);
29376 /** The header element @type Roo.Element */
29377 this.header = el.child("> .x-dlg-hd");
29378 /** The body element @type Roo.Element */
29379 this.body = el.child("> .x-dlg-bd");
29380 /** The footer element @type Roo.Element */
29381 this.footer = el.child("> .x-dlg-ft");
29384 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29387 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29390 this.header.unselectable();
29392 this.header.update(this.title);
29394 // this element allows the dialog to be focused for keyboard event
29395 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29396 this.focusEl.swallowEvent("click", true);
29398 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29400 // wrap the body and footer for special rendering
29401 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29403 this.bwrap.dom.appendChild(this.footer.dom);
29406 this.bg = this.el.createChild({
29407 tag: "div", cls:"x-dlg-bg",
29408 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29410 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29413 if(this.autoScroll !== false && !this.autoTabs){
29414 this.body.setStyle("overflow", "auto");
29417 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29419 if(this.closable !== false){
29420 this.el.addClass("x-dlg-closable");
29421 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29422 this.close.on("click", this.closeClick, this);
29423 this.close.addClassOnOver("x-dlg-close-over");
29425 if(this.collapsible !== false){
29426 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29427 this.collapseBtn.on("click", this.collapseClick, this);
29428 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29429 this.header.on("dblclick", this.collapseClick, this);
29431 if(this.resizable !== false){
29432 this.el.addClass("x-dlg-resizable");
29433 this.resizer = new Roo.Resizable(el, {
29434 minWidth: this.minWidth || 80,
29435 minHeight:this.minHeight || 80,
29436 handles: this.resizeHandles || "all",
29439 this.resizer.on("beforeresize", this.beforeResize, this);
29440 this.resizer.on("resize", this.onResize, this);
29442 if(this.draggable !== false){
29443 el.addClass("x-dlg-draggable");
29444 if (!this.proxyDrag) {
29445 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29448 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29450 dd.setHandleElId(this.header.id);
29451 dd.endDrag = this.endMove.createDelegate(this);
29452 dd.startDrag = this.startMove.createDelegate(this);
29453 dd.onDrag = this.onDrag.createDelegate(this);
29458 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29459 this.mask.enableDisplayMode("block");
29461 this.el.addClass("x-dlg-modal");
29464 this.shadow = new Roo.Shadow({
29465 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29466 offset : this.shadowOffset
29469 this.shadowOffset = 0;
29471 if(Roo.useShims && this.shim !== false){
29472 this.shim = this.el.createShim();
29473 this.shim.hide = this.hideAction;
29481 if (this.buttons) {
29482 var bts= this.buttons;
29484 Roo.each(bts, function(b) {
29493 * Fires when a key is pressed
29494 * @param {Roo.BasicDialog} this
29495 * @param {Roo.EventObject} e
29500 * Fires when this dialog is moved by the user.
29501 * @param {Roo.BasicDialog} this
29502 * @param {Number} x The new page X
29503 * @param {Number} y The new page Y
29508 * Fires when this dialog is resized by the user.
29509 * @param {Roo.BasicDialog} this
29510 * @param {Number} width The new width
29511 * @param {Number} height The new height
29515 * @event beforehide
29516 * Fires before this dialog is hidden.
29517 * @param {Roo.BasicDialog} this
29519 "beforehide" : true,
29522 * Fires when this dialog is hidden.
29523 * @param {Roo.BasicDialog} this
29527 * @event beforeshow
29528 * Fires before this dialog is shown.
29529 * @param {Roo.BasicDialog} this
29531 "beforeshow" : true,
29534 * Fires when this dialog is shown.
29535 * @param {Roo.BasicDialog} this
29539 el.on("keydown", this.onKeyDown, this);
29540 el.on("mousedown", this.toFront, this);
29541 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29543 Roo.DialogManager.register(this);
29544 Roo.BasicDialog.superclass.constructor.call(this);
29547 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29548 shadowOffset: Roo.isIE ? 6 : 5,
29551 minButtonWidth: 75,
29552 defaultButton: null,
29553 buttonAlign: "right",
29558 * Sets the dialog title text
29559 * @param {String} text The title text to display
29560 * @return {Roo.BasicDialog} this
29562 setTitle : function(text){
29563 this.header.update(text);
29568 closeClick : function(){
29573 collapseClick : function(){
29574 this[this.collapsed ? "expand" : "collapse"]();
29578 * Collapses the dialog to its minimized state (only the title bar is visible).
29579 * Equivalent to the user clicking the collapse dialog button.
29581 collapse : function(){
29582 if(!this.collapsed){
29583 this.collapsed = true;
29584 this.el.addClass("x-dlg-collapsed");
29585 this.restoreHeight = this.el.getHeight();
29586 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29591 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29592 * clicking the expand dialog button.
29594 expand : function(){
29595 if(this.collapsed){
29596 this.collapsed = false;
29597 this.el.removeClass("x-dlg-collapsed");
29598 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29603 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29604 * @return {Roo.TabPanel} The tabs component
29606 initTabs : function(){
29607 var tabs = this.getTabs();
29608 while(tabs.getTab(0)){
29611 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29613 tabs.addTab(Roo.id(dom), dom.title);
29621 beforeResize : function(){
29622 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29626 onResize : function(){
29627 this.refreshSize();
29628 this.syncBodyHeight();
29629 this.adjustAssets();
29631 this.fireEvent("resize", this, this.size.width, this.size.height);
29635 onKeyDown : function(e){
29636 if(this.isVisible()){
29637 this.fireEvent("keydown", this, e);
29642 * Resizes the dialog.
29643 * @param {Number} width
29644 * @param {Number} height
29645 * @return {Roo.BasicDialog} this
29647 resizeTo : function(width, height){
29648 this.el.setSize(width, height);
29649 this.size = {width: width, height: height};
29650 this.syncBodyHeight();
29651 if(this.fixedcenter){
29654 if(this.isVisible()){
29655 this.constrainXY();
29656 this.adjustAssets();
29658 this.fireEvent("resize", this, width, height);
29664 * Resizes the dialog to fit the specified content size.
29665 * @param {Number} width
29666 * @param {Number} height
29667 * @return {Roo.BasicDialog} this
29669 setContentSize : function(w, h){
29670 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29671 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29672 //if(!this.el.isBorderBox()){
29673 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29674 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29677 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29678 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29680 this.resizeTo(w, h);
29685 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29686 * executed in response to a particular key being pressed while the dialog is active.
29687 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29688 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29689 * @param {Function} fn The function to call
29690 * @param {Object} scope (optional) The scope of the function
29691 * @return {Roo.BasicDialog} this
29693 addKeyListener : function(key, fn, scope){
29694 var keyCode, shift, ctrl, alt;
29695 if(typeof key == "object" && !(key instanceof Array)){
29696 keyCode = key["key"];
29697 shift = key["shift"];
29698 ctrl = key["ctrl"];
29703 var handler = function(dlg, e){
29704 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29705 var k = e.getKey();
29706 if(keyCode instanceof Array){
29707 for(var i = 0, len = keyCode.length; i < len; i++){
29708 if(keyCode[i] == k){
29709 fn.call(scope || window, dlg, k, e);
29715 fn.call(scope || window, dlg, k, e);
29720 this.on("keydown", handler);
29725 * Returns the TabPanel component (creates it if it doesn't exist).
29726 * Note: If you wish to simply check for the existence of tabs without creating them,
29727 * check for a null 'tabs' property.
29728 * @return {Roo.TabPanel} The tabs component
29730 getTabs : function(){
29732 this.el.addClass("x-dlg-auto-tabs");
29733 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29734 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29740 * Adds a button to the footer section of the dialog.
29741 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29742 * object or a valid Roo.DomHelper element config
29743 * @param {Function} handler The function called when the button is clicked
29744 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29745 * @return {Roo.Button} The new button
29747 addButton : function(config, handler, scope){
29748 var dh = Roo.DomHelper;
29750 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29752 if(!this.btnContainer){
29753 var tb = this.footer.createChild({
29755 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29756 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29758 this.btnContainer = tb.firstChild.firstChild.firstChild;
29763 minWidth: this.minButtonWidth,
29766 if(typeof config == "string"){
29767 bconfig.text = config;
29770 bconfig.dhconfig = config;
29772 Roo.apply(bconfig, config);
29776 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29777 bconfig.position = Math.max(0, bconfig.position);
29778 fc = this.btnContainer.childNodes[bconfig.position];
29781 var btn = new Roo.Button(
29783 this.btnContainer.insertBefore(document.createElement("td"),fc)
29784 : this.btnContainer.appendChild(document.createElement("td")),
29785 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29788 this.syncBodyHeight();
29791 * Array of all the buttons that have been added to this dialog via addButton
29796 this.buttons.push(btn);
29801 * Sets the default button to be focused when the dialog is displayed.
29802 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29803 * @return {Roo.BasicDialog} this
29805 setDefaultButton : function(btn){
29806 this.defaultButton = btn;
29811 getHeaderFooterHeight : function(safe){
29814 height += this.header.getHeight();
29817 var fm = this.footer.getMargins();
29818 height += (this.footer.getHeight()+fm.top+fm.bottom);
29820 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29821 height += this.centerBg.getPadding("tb");
29826 syncBodyHeight : function(){
29827 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29828 var height = this.size.height - this.getHeaderFooterHeight(false);
29829 bd.setHeight(height-bd.getMargins("tb"));
29830 var hh = this.header.getHeight();
29831 var h = this.size.height-hh;
29833 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29834 bw.setHeight(h-cb.getPadding("tb"));
29835 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29836 bd.setWidth(bw.getWidth(true));
29838 this.tabs.syncHeight();
29840 this.tabs.el.repaint();
29846 * Restores the previous state of the dialog if Roo.state is configured.
29847 * @return {Roo.BasicDialog} this
29849 restoreState : function(){
29850 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29851 if(box && box.width){
29852 this.xy = [box.x, box.y];
29853 this.resizeTo(box.width, box.height);
29859 beforeShow : function(){
29861 if(this.fixedcenter){
29862 this.xy = this.el.getCenterXY(true);
29865 Roo.get(document.body).addClass("x-body-masked");
29866 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29869 this.constrainXY();
29873 animShow : function(){
29874 var b = Roo.get(this.animateTarget).getBox();
29875 this.proxy.setSize(b.width, b.height);
29876 this.proxy.setLocation(b.x, b.y);
29878 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29879 true, .35, this.showEl.createDelegate(this));
29883 * Shows the dialog.
29884 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29885 * @return {Roo.BasicDialog} this
29887 show : function(animateTarget){
29888 if (this.fireEvent("beforeshow", this) === false){
29891 if(this.syncHeightBeforeShow){
29892 this.syncBodyHeight();
29893 }else if(this.firstShow){
29894 this.firstShow = false;
29895 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29897 this.animateTarget = animateTarget || this.animateTarget;
29898 if(!this.el.isVisible()){
29900 if(this.animateTarget && Roo.get(this.animateTarget)){
29910 showEl : function(){
29912 this.el.setXY(this.xy);
29914 this.adjustAssets(true);
29917 // IE peekaboo bug - fix found by Dave Fenwick
29921 this.fireEvent("show", this);
29925 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29926 * dialog itself will receive focus.
29928 focus : function(){
29929 if(this.defaultButton){
29930 this.defaultButton.focus();
29932 this.focusEl.focus();
29937 constrainXY : function(){
29938 if(this.constraintoviewport !== false){
29939 if(!this.viewSize){
29940 if(this.container){
29941 var s = this.container.getSize();
29942 this.viewSize = [s.width, s.height];
29944 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29947 var s = Roo.get(this.container||document).getScroll();
29949 var x = this.xy[0], y = this.xy[1];
29950 var w = this.size.width, h = this.size.height;
29951 var vw = this.viewSize[0], vh = this.viewSize[1];
29952 // only move it if it needs it
29954 // first validate right/bottom
29955 if(x + w > vw+s.left){
29959 if(y + h > vh+s.top){
29963 // then make sure top/left isn't negative
29975 if(this.isVisible()){
29976 this.el.setLocation(x, y);
29977 this.adjustAssets();
29984 onDrag : function(){
29985 if(!this.proxyDrag){
29986 this.xy = this.el.getXY();
29987 this.adjustAssets();
29992 adjustAssets : function(doShow){
29993 var x = this.xy[0], y = this.xy[1];
29994 var w = this.size.width, h = this.size.height;
29995 if(doShow === true){
29997 this.shadow.show(this.el);
30003 if(this.shadow && this.shadow.isVisible()){
30004 this.shadow.show(this.el);
30006 if(this.shim && this.shim.isVisible()){
30007 this.shim.setBounds(x, y, w, h);
30012 adjustViewport : function(w, h){
30014 w = Roo.lib.Dom.getViewWidth();
30015 h = Roo.lib.Dom.getViewHeight();
30018 this.viewSize = [w, h];
30019 if(this.modal && this.mask.isVisible()){
30020 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30021 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30023 if(this.isVisible()){
30024 this.constrainXY();
30029 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30030 * shadow, proxy, mask, etc.) Also removes all event listeners.
30031 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30033 destroy : function(removeEl){
30034 if(this.isVisible()){
30035 this.animateTarget = null;
30038 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30040 this.tabs.destroy(removeEl);
30053 for(var i = 0, len = this.buttons.length; i < len; i++){
30054 this.buttons[i].destroy();
30057 this.el.removeAllListeners();
30058 if(removeEl === true){
30059 this.el.update("");
30062 Roo.DialogManager.unregister(this);
30066 startMove : function(){
30067 if(this.proxyDrag){
30070 if(this.constraintoviewport !== false){
30071 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30076 endMove : function(){
30077 if(!this.proxyDrag){
30078 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30080 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30083 this.refreshSize();
30084 this.adjustAssets();
30086 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30090 * Brings this dialog to the front of any other visible dialogs
30091 * @return {Roo.BasicDialog} this
30093 toFront : function(){
30094 Roo.DialogManager.bringToFront(this);
30099 * Sends this dialog to the back (under) of any other visible dialogs
30100 * @return {Roo.BasicDialog} this
30102 toBack : function(){
30103 Roo.DialogManager.sendToBack(this);
30108 * Centers this dialog in the viewport
30109 * @return {Roo.BasicDialog} this
30111 center : function(){
30112 var xy = this.el.getCenterXY(true);
30113 this.moveTo(xy[0], xy[1]);
30118 * Moves the dialog's top-left corner to the specified point
30119 * @param {Number} x
30120 * @param {Number} y
30121 * @return {Roo.BasicDialog} this
30123 moveTo : function(x, y){
30125 if(this.isVisible()){
30126 this.el.setXY(this.xy);
30127 this.adjustAssets();
30133 * Aligns the dialog to the specified element
30134 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30135 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30136 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30137 * @return {Roo.BasicDialog} this
30139 alignTo : function(element, position, offsets){
30140 this.xy = this.el.getAlignToXY(element, position, offsets);
30141 if(this.isVisible()){
30142 this.el.setXY(this.xy);
30143 this.adjustAssets();
30149 * Anchors an element to another element and realigns it when the window is resized.
30150 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30151 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30152 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30153 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30154 * is a number, it is used as the buffer delay (defaults to 50ms).
30155 * @return {Roo.BasicDialog} this
30157 anchorTo : function(el, alignment, offsets, monitorScroll){
30158 var action = function(){
30159 this.alignTo(el, alignment, offsets);
30161 Roo.EventManager.onWindowResize(action, this);
30162 var tm = typeof monitorScroll;
30163 if(tm != 'undefined'){
30164 Roo.EventManager.on(window, 'scroll', action, this,
30165 {buffer: tm == 'number' ? monitorScroll : 50});
30172 * Returns true if the dialog is visible
30173 * @return {Boolean}
30175 isVisible : function(){
30176 return this.el.isVisible();
30180 animHide : function(callback){
30181 var b = Roo.get(this.animateTarget).getBox();
30183 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30185 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30186 this.hideEl.createDelegate(this, [callback]));
30190 * Hides the dialog.
30191 * @param {Function} callback (optional) Function to call when the dialog is hidden
30192 * @return {Roo.BasicDialog} this
30194 hide : function(callback){
30195 if (this.fireEvent("beforehide", this) === false){
30199 this.shadow.hide();
30204 // sometimes animateTarget seems to get set.. causing problems...
30205 // this just double checks..
30206 if(this.animateTarget && Roo.get(this.animateTarget)) {
30207 this.animHide(callback);
30210 this.hideEl(callback);
30216 hideEl : function(callback){
30220 Roo.get(document.body).removeClass("x-body-masked");
30222 this.fireEvent("hide", this);
30223 if(typeof callback == "function"){
30229 hideAction : function(){
30230 this.setLeft("-10000px");
30231 this.setTop("-10000px");
30232 this.setStyle("visibility", "hidden");
30236 refreshSize : function(){
30237 this.size = this.el.getSize();
30238 this.xy = this.el.getXY();
30239 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30243 // z-index is managed by the DialogManager and may be overwritten at any time
30244 setZIndex : function(index){
30246 this.mask.setStyle("z-index", index);
30249 this.shim.setStyle("z-index", ++index);
30252 this.shadow.setZIndex(++index);
30254 this.el.setStyle("z-index", ++index);
30256 this.proxy.setStyle("z-index", ++index);
30259 this.resizer.proxy.setStyle("z-index", ++index);
30262 this.lastZIndex = index;
30266 * Returns the element for this dialog
30267 * @return {Roo.Element} The underlying dialog Element
30269 getEl : function(){
30275 * @class Roo.DialogManager
30276 * Provides global access to BasicDialogs that have been created and
30277 * support for z-indexing (layering) multiple open dialogs.
30279 Roo.DialogManager = function(){
30281 var accessList = [];
30285 var sortDialogs = function(d1, d2){
30286 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30290 var orderDialogs = function(){
30291 accessList.sort(sortDialogs);
30292 var seed = Roo.DialogManager.zseed;
30293 for(var i = 0, len = accessList.length; i < len; i++){
30294 var dlg = accessList[i];
30296 dlg.setZIndex(seed + (i*10));
30303 * The starting z-index for BasicDialogs (defaults to 9000)
30304 * @type Number The z-index value
30309 register : function(dlg){
30310 list[dlg.id] = dlg;
30311 accessList.push(dlg);
30315 unregister : function(dlg){
30316 delete list[dlg.id];
30319 if(!accessList.indexOf){
30320 for( i = 0, len = accessList.length; i < len; i++){
30321 if(accessList[i] == dlg){
30322 accessList.splice(i, 1);
30327 i = accessList.indexOf(dlg);
30329 accessList.splice(i, 1);
30335 * Gets a registered dialog by id
30336 * @param {String/Object} id The id of the dialog or a dialog
30337 * @return {Roo.BasicDialog} this
30339 get : function(id){
30340 return typeof id == "object" ? id : list[id];
30344 * Brings the specified dialog to the front
30345 * @param {String/Object} dlg The id of the dialog or a dialog
30346 * @return {Roo.BasicDialog} this
30348 bringToFront : function(dlg){
30349 dlg = this.get(dlg);
30352 dlg._lastAccess = new Date().getTime();
30359 * Sends the specified dialog to the back
30360 * @param {String/Object} dlg The id of the dialog or a dialog
30361 * @return {Roo.BasicDialog} this
30363 sendToBack : function(dlg){
30364 dlg = this.get(dlg);
30365 dlg._lastAccess = -(new Date().getTime());
30371 * Hides all dialogs
30373 hideAll : function(){
30374 for(var id in list){
30375 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30384 * @class Roo.LayoutDialog
30385 * @extends Roo.BasicDialog
30386 * Dialog which provides adjustments for working with a layout in a Dialog.
30387 * Add your necessary layout config options to the dialog's config.<br>
30388 * Example usage (including a nested layout):
30391 dialog = new Roo.LayoutDialog("download-dlg", {
30400 // layout config merges with the dialog config
30402 tabPosition: "top",
30403 alwaysShowTabs: true
30406 dialog.addKeyListener(27, dialog.hide, dialog);
30407 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30408 dialog.addButton("Build It!", this.getDownload, this);
30410 // we can even add nested layouts
30411 var innerLayout = new Roo.BorderLayout("dl-inner", {
30421 innerLayout.beginUpdate();
30422 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30423 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30424 innerLayout.endUpdate(true);
30426 var layout = dialog.getLayout();
30427 layout.beginUpdate();
30428 layout.add("center", new Roo.ContentPanel("standard-panel",
30429 {title: "Download the Source", fitToFrame:true}));
30430 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30431 {title: "Build your own roo.js"}));
30432 layout.getRegion("center").showPanel(sp);
30433 layout.endUpdate();
30437 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30438 * @param {Object} config configuration options
30440 Roo.LayoutDialog = function(el, cfg){
30443 if (typeof(cfg) == 'undefined') {
30444 config = Roo.apply({}, el);
30445 // not sure why we use documentElement here.. - it should always be body.
30446 // IE7 borks horribly if we use documentElement.
30447 // webkit also does not like documentElement - it creates a body element...
30448 el = Roo.get( document.body || document.documentElement ).createChild();
30449 //config.autoCreate = true;
30453 config.autoTabs = false;
30454 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30455 this.body.setStyle({overflow:"hidden", position:"relative"});
30456 this.layout = new Roo.BorderLayout(this.body.dom, config);
30457 this.layout.monitorWindowResize = false;
30458 this.el.addClass("x-dlg-auto-layout");
30459 // fix case when center region overwrites center function
30460 this.center = Roo.BasicDialog.prototype.center;
30461 this.on("show", this.layout.layout, this.layout, true);
30462 if (config.items) {
30463 var xitems = config.items;
30464 delete config.items;
30465 Roo.each(xitems, this.addxtype, this);
30470 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30472 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30475 endUpdate : function(){
30476 this.layout.endUpdate();
30480 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30483 beginUpdate : function(){
30484 this.layout.beginUpdate();
30488 * Get the BorderLayout for this dialog
30489 * @return {Roo.BorderLayout}
30491 getLayout : function(){
30492 return this.layout;
30495 showEl : function(){
30496 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30498 this.layout.layout();
30503 // Use the syncHeightBeforeShow config option to control this automatically
30504 syncBodyHeight : function(){
30505 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30506 if(this.layout){this.layout.layout();}
30510 * Add an xtype element (actually adds to the layout.)
30511 * @return {Object} xdata xtype object data.
30514 addxtype : function(c) {
30515 return this.layout.addxtype(c);
30519 * Ext JS Library 1.1.1
30520 * Copyright(c) 2006-2007, Ext JS, LLC.
30522 * Originally Released Under LGPL - original licence link has changed is not relivant.
30525 * <script type="text/javascript">
30529 * @class Roo.MessageBox
30530 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30534 Roo.Msg.alert('Status', 'Changes saved successfully.');
30536 // Prompt for user data:
30537 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30539 // process text value...
30543 // Show a dialog using config options:
30545 title:'Save Changes?',
30546 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30547 buttons: Roo.Msg.YESNOCANCEL,
30554 Roo.MessageBox = function(){
30555 var dlg, opt, mask, waitTimer;
30556 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30557 var buttons, activeTextEl, bwidth;
30560 var handleButton = function(button){
30562 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30566 var handleHide = function(){
30567 if(opt && opt.cls){
30568 dlg.el.removeClass(opt.cls);
30571 Roo.TaskMgr.stop(waitTimer);
30577 var updateButtons = function(b){
30580 buttons["ok"].hide();
30581 buttons["cancel"].hide();
30582 buttons["yes"].hide();
30583 buttons["no"].hide();
30584 dlg.footer.dom.style.display = 'none';
30587 dlg.footer.dom.style.display = '';
30588 for(var k in buttons){
30589 if(typeof buttons[k] != "function"){
30592 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30593 width += buttons[k].el.getWidth()+15;
30603 var handleEsc = function(d, k, e){
30604 if(opt && opt.closable !== false){
30614 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30615 * @return {Roo.BasicDialog} The BasicDialog element
30617 getDialog : function(){
30619 dlg = new Roo.BasicDialog("x-msg-box", {
30624 constraintoviewport:false,
30626 collapsible : false,
30629 width:400, height:100,
30630 buttonAlign:"center",
30631 closeClick : function(){
30632 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30633 handleButton("no");
30635 handleButton("cancel");
30639 dlg.on("hide", handleHide);
30641 dlg.addKeyListener(27, handleEsc);
30643 var bt = this.buttonText;
30644 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30645 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30646 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30647 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30648 bodyEl = dlg.body.createChild({
30650 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>'
30652 msgEl = bodyEl.dom.firstChild;
30653 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30654 textboxEl.enableDisplayMode();
30655 textboxEl.addKeyListener([10,13], function(){
30656 if(dlg.isVisible() && opt && opt.buttons){
30657 if(opt.buttons.ok){
30658 handleButton("ok");
30659 }else if(opt.buttons.yes){
30660 handleButton("yes");
30664 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30665 textareaEl.enableDisplayMode();
30666 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30667 progressEl.enableDisplayMode();
30668 var pf = progressEl.dom.firstChild;
30670 pp = Roo.get(pf.firstChild);
30671 pp.setHeight(pf.offsetHeight);
30679 * Updates the message box body text
30680 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30681 * the XHTML-compliant non-breaking space character '&#160;')
30682 * @return {Roo.MessageBox} This message box
30684 updateText : function(text){
30685 if(!dlg.isVisible() && !opt.width){
30686 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30688 msgEl.innerHTML = text || ' ';
30690 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30691 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30693 Math.min(opt.width || cw , this.maxWidth),
30694 Math.max(opt.minWidth || this.minWidth, bwidth)
30697 activeTextEl.setWidth(w);
30699 if(dlg.isVisible()){
30700 dlg.fixedcenter = false;
30702 // to big, make it scroll. = But as usual stupid IE does not support
30705 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30706 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30707 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30709 bodyEl.dom.style.height = '';
30710 bodyEl.dom.style.overflowY = '';
30713 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30715 bodyEl.dom.style.overflowX = '';
30718 dlg.setContentSize(w, bodyEl.getHeight());
30719 if(dlg.isVisible()){
30720 dlg.fixedcenter = true;
30726 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30727 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30728 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30729 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30730 * @return {Roo.MessageBox} This message box
30732 updateProgress : function(value, text){
30734 this.updateText(text);
30736 if (pp) { // weird bug on my firefox - for some reason this is not defined
30737 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30743 * Returns true if the message box is currently displayed
30744 * @return {Boolean} True if the message box is visible, else false
30746 isVisible : function(){
30747 return dlg && dlg.isVisible();
30751 * Hides the message box if it is displayed
30754 if(this.isVisible()){
30760 * Displays a new message box, or reinitializes an existing message box, based on the config options
30761 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30762 * The following config object properties are supported:
30764 Property Type Description
30765 ---------- --------------- ------------------------------------------------------------------------------------
30766 animEl String/Element An id or Element from which the message box should animate as it opens and
30767 closes (defaults to undefined)
30768 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30769 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30770 closable Boolean False to hide the top-right close button (defaults to true). Note that
30771 progress and wait dialogs will ignore this property and always hide the
30772 close button as they can only be closed programmatically.
30773 cls String A custom CSS class to apply to the message box element
30774 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30775 displayed (defaults to 75)
30776 fn Function A callback function to execute after closing the dialog. The arguments to the
30777 function will be btn (the name of the button that was clicked, if applicable,
30778 e.g. "ok"), and text (the value of the active text field, if applicable).
30779 Progress and wait dialogs will ignore this option since they do not respond to
30780 user actions and can only be closed programmatically, so any required function
30781 should be called by the same code after it closes the dialog.
30782 icon String A CSS class that provides a background image to be used as an icon for
30783 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30784 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30785 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30786 modal Boolean False to allow user interaction with the page while the message box is
30787 displayed (defaults to true)
30788 msg String A string that will replace the existing message box body text (defaults
30789 to the XHTML-compliant non-breaking space character ' ')
30790 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30791 progress Boolean True to display a progress bar (defaults to false)
30792 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30793 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30794 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30795 title String The title text
30796 value String The string value to set into the active textbox element if displayed
30797 wait Boolean True to display a progress bar (defaults to false)
30798 width Number The width of the dialog in pixels
30805 msg: 'Please enter your address:',
30807 buttons: Roo.MessageBox.OKCANCEL,
30810 animEl: 'addAddressBtn'
30813 * @param {Object} config Configuration options
30814 * @return {Roo.MessageBox} This message box
30816 show : function(options)
30819 // this causes nightmares if you show one dialog after another
30820 // especially on callbacks..
30822 if(this.isVisible()){
30825 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30826 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30827 Roo.log("New Dialog Message:" + options.msg )
30828 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30829 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30832 var d = this.getDialog();
30834 d.setTitle(opt.title || " ");
30835 d.close.setDisplayed(opt.closable !== false);
30836 activeTextEl = textboxEl;
30837 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30842 textareaEl.setHeight(typeof opt.multiline == "number" ?
30843 opt.multiline : this.defaultTextHeight);
30844 activeTextEl = textareaEl;
30853 progressEl.setDisplayed(opt.progress === true);
30854 this.updateProgress(0);
30855 activeTextEl.dom.value = opt.value || "";
30857 dlg.setDefaultButton(activeTextEl);
30859 var bs = opt.buttons;
30862 db = buttons["ok"];
30863 }else if(bs && bs.yes){
30864 db = buttons["yes"];
30866 dlg.setDefaultButton(db);
30868 bwidth = updateButtons(opt.buttons);
30869 this.updateText(opt.msg);
30871 d.el.addClass(opt.cls);
30873 d.proxyDrag = opt.proxyDrag === true;
30874 d.modal = opt.modal !== false;
30875 d.mask = opt.modal !== false ? mask : false;
30876 if(!d.isVisible()){
30877 // force it to the end of the z-index stack so it gets a cursor in FF
30878 document.body.appendChild(dlg.el.dom);
30879 d.animateTarget = null;
30880 d.show(options.animEl);
30886 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30887 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30888 * and closing the message box when the process is complete.
30889 * @param {String} title The title bar text
30890 * @param {String} msg The message box body text
30891 * @return {Roo.MessageBox} This message box
30893 progress : function(title, msg){
30900 minWidth: this.minProgressWidth,
30907 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30908 * If a callback function is passed it will be called after the user clicks the button, and the
30909 * id of the button that was clicked will be passed as the only parameter to the callback
30910 * (could also be the top-right close button).
30911 * @param {String} title The title bar text
30912 * @param {String} msg The message box body text
30913 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30914 * @param {Object} scope (optional) The scope of the callback function
30915 * @return {Roo.MessageBox} This message box
30917 alert : function(title, msg, fn, scope){
30930 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30931 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30932 * You are responsible for closing the message box when the process is complete.
30933 * @param {String} msg The message box body text
30934 * @param {String} title (optional) The title bar text
30935 * @return {Roo.MessageBox} This message box
30937 wait : function(msg, title){
30948 waitTimer = Roo.TaskMgr.start({
30950 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30958 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30959 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30960 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30961 * @param {String} title The title bar text
30962 * @param {String} msg The message box body text
30963 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30964 * @param {Object} scope (optional) The scope of the callback function
30965 * @return {Roo.MessageBox} This message box
30967 confirm : function(title, msg, fn, scope){
30971 buttons: this.YESNO,
30980 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30981 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30982 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30983 * (could also be the top-right close button) and the text that was entered will be passed as the two
30984 * parameters to the callback.
30985 * @param {String} title The title bar text
30986 * @param {String} msg The message box body text
30987 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30988 * @param {Object} scope (optional) The scope of the callback function
30989 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30990 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30991 * @return {Roo.MessageBox} This message box
30993 prompt : function(title, msg, fn, scope, multiline){
30997 buttons: this.OKCANCEL,
31002 multiline: multiline,
31009 * Button config that displays a single OK button
31014 * Button config that displays Yes and No buttons
31017 YESNO : {yes:true, no:true},
31019 * Button config that displays OK and Cancel buttons
31022 OKCANCEL : {ok:true, cancel:true},
31024 * Button config that displays Yes, No and Cancel buttons
31027 YESNOCANCEL : {yes:true, no:true, cancel:true},
31030 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31033 defaultTextHeight : 75,
31035 * The maximum width in pixels of the message box (defaults to 600)
31040 * The minimum width in pixels of the message box (defaults to 100)
31045 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31046 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31049 minProgressWidth : 250,
31051 * An object containing the default button text strings that can be overriden for localized language support.
31052 * Supported properties are: ok, cancel, yes and no.
31053 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31066 * Shorthand for {@link Roo.MessageBox}
31068 Roo.Msg = Roo.MessageBox;/*
31070 * Ext JS Library 1.1.1
31071 * Copyright(c) 2006-2007, Ext JS, LLC.
31073 * Originally Released Under LGPL - original licence link has changed is not relivant.
31076 * <script type="text/javascript">
31079 * @class Roo.QuickTips
31080 * Provides attractive and customizable tooltips for any element.
31083 Roo.QuickTips = function(){
31084 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31085 var ce, bd, xy, dd;
31086 var visible = false, disabled = true, inited = false;
31087 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31089 var onOver = function(e){
31093 var t = e.getTarget();
31094 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31097 if(ce && t == ce.el){
31098 clearTimeout(hideProc);
31101 if(t && tagEls[t.id]){
31102 tagEls[t.id].el = t;
31103 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31106 var ttp, et = Roo.fly(t);
31107 var ns = cfg.namespace;
31108 if(tm.interceptTitles && t.title){
31111 t.removeAttribute("title");
31112 e.preventDefault();
31114 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31117 showProc = show.defer(tm.showDelay, tm, [{
31120 width: et.getAttributeNS(ns, cfg.width),
31121 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31122 title: et.getAttributeNS(ns, cfg.title),
31123 cls: et.getAttributeNS(ns, cfg.cls)
31128 var onOut = function(e){
31129 clearTimeout(showProc);
31130 var t = e.getTarget();
31131 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31132 hideProc = setTimeout(hide, tm.hideDelay);
31136 var onMove = function(e){
31142 if(tm.trackMouse && ce){
31147 var onDown = function(e){
31148 clearTimeout(showProc);
31149 clearTimeout(hideProc);
31151 if(tm.hideOnClick){
31154 tm.enable.defer(100, tm);
31159 var getPad = function(){
31160 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31163 var show = function(o){
31167 clearTimeout(dismissProc);
31169 if(removeCls){ // in case manually hidden
31170 el.removeClass(removeCls);
31174 el.addClass(ce.cls);
31175 removeCls = ce.cls;
31178 tipTitle.update(ce.title);
31181 tipTitle.update('');
31184 el.dom.style.width = tm.maxWidth+'px';
31185 //tipBody.dom.style.width = '';
31186 tipBodyText.update(o.text);
31187 var p = getPad(), w = ce.width;
31189 var td = tipBodyText.dom;
31190 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31191 if(aw > tm.maxWidth){
31193 }else if(aw < tm.minWidth){
31199 //tipBody.setWidth(w);
31200 el.setWidth(parseInt(w, 10) + p);
31201 if(ce.autoHide === false){
31202 close.setDisplayed(true);
31207 close.setDisplayed(false);
31213 el.avoidY = xy[1]-18;
31218 el.setStyle("visibility", "visible");
31219 el.fadeIn({callback: afterShow});
31225 var afterShow = function(){
31229 if(tm.autoDismiss && ce.autoHide !== false){
31230 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31235 var hide = function(noanim){
31236 clearTimeout(dismissProc);
31237 clearTimeout(hideProc);
31239 if(el.isVisible()){
31241 if(noanim !== true && tm.animate){
31242 el.fadeOut({callback: afterHide});
31249 var afterHide = function(){
31252 el.removeClass(removeCls);
31259 * @cfg {Number} minWidth
31260 * The minimum width of the quick tip (defaults to 40)
31264 * @cfg {Number} maxWidth
31265 * The maximum width of the quick tip (defaults to 300)
31269 * @cfg {Boolean} interceptTitles
31270 * True to automatically use the element's DOM title value if available (defaults to false)
31272 interceptTitles : false,
31274 * @cfg {Boolean} trackMouse
31275 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31277 trackMouse : false,
31279 * @cfg {Boolean} hideOnClick
31280 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31282 hideOnClick : true,
31284 * @cfg {Number} showDelay
31285 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31289 * @cfg {Number} hideDelay
31290 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31294 * @cfg {Boolean} autoHide
31295 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31296 * Used in conjunction with hideDelay.
31301 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31302 * (defaults to true). Used in conjunction with autoDismissDelay.
31304 autoDismiss : true,
31307 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31309 autoDismissDelay : 5000,
31311 * @cfg {Boolean} animate
31312 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31317 * @cfg {String} title
31318 * Title text to display (defaults to ''). This can be any valid HTML markup.
31322 * @cfg {String} text
31323 * Body text to display (defaults to ''). This can be any valid HTML markup.
31327 * @cfg {String} cls
31328 * A CSS class to apply to the base quick tip element (defaults to '').
31332 * @cfg {Number} width
31333 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31334 * minWidth or maxWidth.
31339 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31340 * or display QuickTips in a page.
31343 tm = Roo.QuickTips;
31344 cfg = tm.tagConfig;
31346 if(!Roo.isReady){ // allow calling of init() before onReady
31347 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31350 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31351 el.fxDefaults = {stopFx: true};
31352 // maximum custom styling
31353 //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>');
31354 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>');
31355 tipTitle = el.child('h3');
31356 tipTitle.enableDisplayMode("block");
31357 tipBody = el.child('div.x-tip-bd');
31358 tipBodyText = el.child('div.x-tip-bd-inner');
31359 //bdLeft = el.child('div.x-tip-bd-left');
31360 //bdRight = el.child('div.x-tip-bd-right');
31361 close = el.child('div.x-tip-close');
31362 close.enableDisplayMode("block");
31363 close.on("click", hide);
31364 var d = Roo.get(document);
31365 d.on("mousedown", onDown);
31366 d.on("mouseover", onOver);
31367 d.on("mouseout", onOut);
31368 d.on("mousemove", onMove);
31369 esc = d.addKeyListener(27, hide);
31372 dd = el.initDD("default", null, {
31373 onDrag : function(){
31377 dd.setHandleElId(tipTitle.id);
31386 * Configures a new quick tip instance and assigns it to a target element. The following config options
31389 Property Type Description
31390 ---------- --------------------- ------------------------------------------------------------------------
31391 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31393 * @param {Object} config The config object
31395 register : function(config){
31396 var cs = config instanceof Array ? config : arguments;
31397 for(var i = 0, len = cs.length; i < len; i++) {
31399 var target = c.target;
31401 if(target instanceof Array){
31402 for(var j = 0, jlen = target.length; j < jlen; j++){
31403 tagEls[target[j]] = c;
31406 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31413 * Removes this quick tip from its element and destroys it.
31414 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31416 unregister : function(el){
31417 delete tagEls[Roo.id(el)];
31421 * Enable this quick tip.
31423 enable : function(){
31424 if(inited && disabled){
31426 if(locks.length < 1){
31433 * Disable this quick tip.
31435 disable : function(){
31437 clearTimeout(showProc);
31438 clearTimeout(hideProc);
31439 clearTimeout(dismissProc);
31447 * Returns true if the quick tip is enabled, else false.
31449 isEnabled : function(){
31456 attribute : "qtip",
31466 // backwards compat
31467 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31469 * Ext JS Library 1.1.1
31470 * Copyright(c) 2006-2007, Ext JS, LLC.
31472 * Originally Released Under LGPL - original licence link has changed is not relivant.
31475 * <script type="text/javascript">
31480 * @class Roo.tree.TreePanel
31481 * @extends Roo.data.Tree
31483 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31484 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31485 * @cfg {Boolean} enableDD true to enable drag and drop
31486 * @cfg {Boolean} enableDrag true to enable just drag
31487 * @cfg {Boolean} enableDrop true to enable just drop
31488 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31489 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31490 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31491 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31492 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31493 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31494 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31495 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31496 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31497 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31498 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31499 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31500 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31501 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31502 * @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>
31503 * @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>
31506 * @param {String/HTMLElement/Element} el The container element
31507 * @param {Object} config
31509 Roo.tree.TreePanel = function(el, config){
31511 var loader = false;
31513 root = config.root;
31514 delete config.root;
31516 if (config.loader) {
31517 loader = config.loader;
31518 delete config.loader;
31521 Roo.apply(this, config);
31522 Roo.tree.TreePanel.superclass.constructor.call(this);
31523 this.el = Roo.get(el);
31524 this.el.addClass('x-tree');
31525 //console.log(root);
31527 this.setRootNode( Roo.factory(root, Roo.tree));
31530 this.loader = Roo.factory(loader, Roo.tree);
31533 * Read-only. The id of the container element becomes this TreePanel's id.
31535 this.id = this.el.id;
31538 * @event beforeload
31539 * Fires before a node is loaded, return false to cancel
31540 * @param {Node} node The node being loaded
31542 "beforeload" : true,
31545 * Fires when a node is loaded
31546 * @param {Node} node The node that was loaded
31550 * @event textchange
31551 * Fires when the text for a node is changed
31552 * @param {Node} node The node
31553 * @param {String} text The new text
31554 * @param {String} oldText The old text
31556 "textchange" : true,
31558 * @event beforeexpand
31559 * Fires before a node is expanded, return false to cancel.
31560 * @param {Node} node The node
31561 * @param {Boolean} deep
31562 * @param {Boolean} anim
31564 "beforeexpand" : true,
31566 * @event beforecollapse
31567 * Fires before a node is collapsed, return false to cancel.
31568 * @param {Node} node The node
31569 * @param {Boolean} deep
31570 * @param {Boolean} anim
31572 "beforecollapse" : true,
31575 * Fires when a node is expanded
31576 * @param {Node} node The node
31580 * @event disabledchange
31581 * Fires when the disabled status of a node changes
31582 * @param {Node} node The node
31583 * @param {Boolean} disabled
31585 "disabledchange" : true,
31588 * Fires when a node is collapsed
31589 * @param {Node} node The node
31593 * @event beforeclick
31594 * Fires before click processing on a node. Return false to cancel the default action.
31595 * @param {Node} node The node
31596 * @param {Roo.EventObject} e The event object
31598 "beforeclick":true,
31600 * @event checkchange
31601 * Fires when a node with a checkbox's checked property changes
31602 * @param {Node} this This node
31603 * @param {Boolean} checked
31605 "checkchange":true,
31608 * Fires when a node is clicked
31609 * @param {Node} node The node
31610 * @param {Roo.EventObject} e The event object
31615 * Fires when a node is double clicked
31616 * @param {Node} node The node
31617 * @param {Roo.EventObject} e The event object
31621 * @event contextmenu
31622 * Fires when a node is right clicked
31623 * @param {Node} node The node
31624 * @param {Roo.EventObject} e The event object
31626 "contextmenu":true,
31628 * @event beforechildrenrendered
31629 * Fires right before the child nodes for a node are rendered
31630 * @param {Node} node The node
31632 "beforechildrenrendered":true,
31635 * Fires when a node starts being dragged
31636 * @param {Roo.tree.TreePanel} this
31637 * @param {Roo.tree.TreeNode} node
31638 * @param {event} e The raw browser event
31640 "startdrag" : true,
31643 * Fires when a drag operation is complete
31644 * @param {Roo.tree.TreePanel} this
31645 * @param {Roo.tree.TreeNode} node
31646 * @param {event} e The raw browser event
31651 * Fires when a dragged node is dropped on a valid DD target
31652 * @param {Roo.tree.TreePanel} this
31653 * @param {Roo.tree.TreeNode} node
31654 * @param {DD} dd The dd it was dropped on
31655 * @param {event} e The raw browser event
31659 * @event beforenodedrop
31660 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31661 * passed to handlers has the following properties:<br />
31662 * <ul style="padding:5px;padding-left:16px;">
31663 * <li>tree - The TreePanel</li>
31664 * <li>target - The node being targeted for the drop</li>
31665 * <li>data - The drag data from the drag source</li>
31666 * <li>point - The point of the drop - append, above or below</li>
31667 * <li>source - The drag source</li>
31668 * <li>rawEvent - Raw mouse event</li>
31669 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31670 * to be inserted by setting them on this object.</li>
31671 * <li>cancel - Set this to true to cancel the drop.</li>
31673 * @param {Object} dropEvent
31675 "beforenodedrop" : true,
31678 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31679 * passed to handlers has the following properties:<br />
31680 * <ul style="padding:5px;padding-left:16px;">
31681 * <li>tree - The TreePanel</li>
31682 * <li>target - The node being targeted for the drop</li>
31683 * <li>data - The drag data from the drag source</li>
31684 * <li>point - The point of the drop - append, above or below</li>
31685 * <li>source - The drag source</li>
31686 * <li>rawEvent - Raw mouse event</li>
31687 * <li>dropNode - Dropped node(s).</li>
31689 * @param {Object} dropEvent
31693 * @event nodedragover
31694 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31695 * passed to handlers has the following properties:<br />
31696 * <ul style="padding:5px;padding-left:16px;">
31697 * <li>tree - The TreePanel</li>
31698 * <li>target - The node being targeted for the drop</li>
31699 * <li>data - The drag data from the drag source</li>
31700 * <li>point - The point of the drop - append, above or below</li>
31701 * <li>source - The drag source</li>
31702 * <li>rawEvent - Raw mouse event</li>
31703 * <li>dropNode - Drop node(s) provided by the source.</li>
31704 * <li>cancel - Set this to true to signal drop not allowed.</li>
31706 * @param {Object} dragOverEvent
31708 "nodedragover" : true
31711 if(this.singleExpand){
31712 this.on("beforeexpand", this.restrictExpand, this);
31715 this.editor.tree = this;
31716 this.editor = Roo.factory(this.editor, Roo.tree);
31719 if (this.selModel) {
31720 this.selModel = Roo.factory(this.selModel, Roo.tree);
31724 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31725 rootVisible : true,
31726 animate: Roo.enableFx,
31729 hlDrop : Roo.enableFx,
31733 rendererTip: false,
31735 restrictExpand : function(node){
31736 var p = node.parentNode;
31738 if(p.expandedChild && p.expandedChild.parentNode == p){
31739 p.expandedChild.collapse();
31741 p.expandedChild = node;
31745 // private override
31746 setRootNode : function(node){
31747 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31748 if(!this.rootVisible){
31749 node.ui = new Roo.tree.RootTreeNodeUI(node);
31755 * Returns the container element for this TreePanel
31757 getEl : function(){
31762 * Returns the default TreeLoader for this TreePanel
31764 getLoader : function(){
31765 return this.loader;
31771 expandAll : function(){
31772 this.root.expand(true);
31776 * Collapse all nodes
31778 collapseAll : function(){
31779 this.root.collapse(true);
31783 * Returns the selection model used by this TreePanel
31785 getSelectionModel : function(){
31786 if(!this.selModel){
31787 this.selModel = new Roo.tree.DefaultSelectionModel();
31789 return this.selModel;
31793 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31794 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31795 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31798 getChecked : function(a, startNode){
31799 startNode = startNode || this.root;
31801 var f = function(){
31802 if(this.attributes.checked){
31803 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31806 startNode.cascade(f);
31811 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31812 * @param {String} path
31813 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31814 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31815 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31817 expandPath : function(path, attr, callback){
31818 attr = attr || "id";
31819 var keys = path.split(this.pathSeparator);
31820 var curNode = this.root;
31821 if(curNode.attributes[attr] != keys[1]){ // invalid root
31823 callback(false, null);
31828 var f = function(){
31829 if(++index == keys.length){
31831 callback(true, curNode);
31835 var c = curNode.findChild(attr, keys[index]);
31838 callback(false, curNode);
31843 c.expand(false, false, f);
31845 curNode.expand(false, false, f);
31849 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31850 * @param {String} path
31851 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31852 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31853 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31855 selectPath : function(path, attr, callback){
31856 attr = attr || "id";
31857 var keys = path.split(this.pathSeparator);
31858 var v = keys.pop();
31859 if(keys.length > 0){
31860 var f = function(success, node){
31861 if(success && node){
31862 var n = node.findChild(attr, v);
31868 }else if(callback){
31869 callback(false, n);
31873 callback(false, n);
31877 this.expandPath(keys.join(this.pathSeparator), attr, f);
31879 this.root.select();
31881 callback(true, this.root);
31886 getTreeEl : function(){
31891 * Trigger rendering of this TreePanel
31893 render : function(){
31894 if (this.innerCt) {
31895 return this; // stop it rendering more than once!!
31898 this.innerCt = this.el.createChild({tag:"ul",
31899 cls:"x-tree-root-ct " +
31900 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31902 if(this.containerScroll){
31903 Roo.dd.ScrollManager.register(this.el);
31905 if((this.enableDD || this.enableDrop) && !this.dropZone){
31907 * The dropZone used by this tree if drop is enabled
31908 * @type Roo.tree.TreeDropZone
31910 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31911 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31914 if((this.enableDD || this.enableDrag) && !this.dragZone){
31916 * The dragZone used by this tree if drag is enabled
31917 * @type Roo.tree.TreeDragZone
31919 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31920 ddGroup: this.ddGroup || "TreeDD",
31921 scroll: this.ddScroll
31924 this.getSelectionModel().init(this);
31926 Roo.log("ROOT not set in tree");
31929 this.root.render();
31930 if(!this.rootVisible){
31931 this.root.renderChildren();
31937 * Ext JS Library 1.1.1
31938 * Copyright(c) 2006-2007, Ext JS, LLC.
31940 * Originally Released Under LGPL - original licence link has changed is not relivant.
31943 * <script type="text/javascript">
31948 * @class Roo.tree.DefaultSelectionModel
31949 * @extends Roo.util.Observable
31950 * The default single selection for a TreePanel.
31951 * @param {Object} cfg Configuration
31953 Roo.tree.DefaultSelectionModel = function(cfg){
31954 this.selNode = null;
31960 * @event selectionchange
31961 * Fires when the selected node changes
31962 * @param {DefaultSelectionModel} this
31963 * @param {TreeNode} node the new selection
31965 "selectionchange" : true,
31968 * @event beforeselect
31969 * Fires before the selected node changes, return false to cancel the change
31970 * @param {DefaultSelectionModel} this
31971 * @param {TreeNode} node the new selection
31972 * @param {TreeNode} node the old selection
31974 "beforeselect" : true
31977 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31980 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31981 init : function(tree){
31983 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31984 tree.on("click", this.onNodeClick, this);
31987 onNodeClick : function(node, e){
31988 if (e.ctrlKey && this.selNode == node) {
31989 this.unselect(node);
31997 * @param {TreeNode} node The node to select
31998 * @return {TreeNode} The selected node
32000 select : function(node){
32001 var last = this.selNode;
32002 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32004 last.ui.onSelectedChange(false);
32006 this.selNode = node;
32007 node.ui.onSelectedChange(true);
32008 this.fireEvent("selectionchange", this, node, last);
32015 * @param {TreeNode} node The node to unselect
32017 unselect : function(node){
32018 if(this.selNode == node){
32019 this.clearSelections();
32024 * Clear all selections
32026 clearSelections : function(){
32027 var n = this.selNode;
32029 n.ui.onSelectedChange(false);
32030 this.selNode = null;
32031 this.fireEvent("selectionchange", this, null);
32037 * Get the selected node
32038 * @return {TreeNode} The selected node
32040 getSelectedNode : function(){
32041 return this.selNode;
32045 * Returns true if the node is selected
32046 * @param {TreeNode} node The node to check
32047 * @return {Boolean}
32049 isSelected : function(node){
32050 return this.selNode == node;
32054 * Selects the node above the selected node in the tree, intelligently walking the nodes
32055 * @return TreeNode The new selection
32057 selectPrevious : function(){
32058 var s = this.selNode || this.lastSelNode;
32062 var ps = s.previousSibling;
32064 if(!ps.isExpanded() || ps.childNodes.length < 1){
32065 return this.select(ps);
32067 var lc = ps.lastChild;
32068 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32071 return this.select(lc);
32073 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32074 return this.select(s.parentNode);
32080 * Selects the node above the selected node in the tree, intelligently walking the nodes
32081 * @return TreeNode The new selection
32083 selectNext : function(){
32084 var s = this.selNode || this.lastSelNode;
32088 if(s.firstChild && s.isExpanded()){
32089 return this.select(s.firstChild);
32090 }else if(s.nextSibling){
32091 return this.select(s.nextSibling);
32092 }else if(s.parentNode){
32094 s.parentNode.bubble(function(){
32095 if(this.nextSibling){
32096 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32105 onKeyDown : function(e){
32106 var s = this.selNode || this.lastSelNode;
32107 // undesirable, but required
32112 var k = e.getKey();
32120 this.selectPrevious();
32123 e.preventDefault();
32124 if(s.hasChildNodes()){
32125 if(!s.isExpanded()){
32127 }else if(s.firstChild){
32128 this.select(s.firstChild, e);
32133 e.preventDefault();
32134 if(s.hasChildNodes() && s.isExpanded()){
32136 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32137 this.select(s.parentNode, e);
32145 * @class Roo.tree.MultiSelectionModel
32146 * @extends Roo.util.Observable
32147 * Multi selection for a TreePanel.
32148 * @param {Object} cfg Configuration
32150 Roo.tree.MultiSelectionModel = function(){
32151 this.selNodes = [];
32155 * @event selectionchange
32156 * Fires when the selected nodes change
32157 * @param {MultiSelectionModel} this
32158 * @param {Array} nodes Array of the selected nodes
32160 "selectionchange" : true
32162 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32166 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32167 init : function(tree){
32169 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32170 tree.on("click", this.onNodeClick, this);
32173 onNodeClick : function(node, e){
32174 this.select(node, e, e.ctrlKey);
32179 * @param {TreeNode} node The node to select
32180 * @param {EventObject} e (optional) An event associated with the selection
32181 * @param {Boolean} keepExisting True to retain existing selections
32182 * @return {TreeNode} The selected node
32184 select : function(node, e, keepExisting){
32185 if(keepExisting !== true){
32186 this.clearSelections(true);
32188 if(this.isSelected(node)){
32189 this.lastSelNode = node;
32192 this.selNodes.push(node);
32193 this.selMap[node.id] = node;
32194 this.lastSelNode = node;
32195 node.ui.onSelectedChange(true);
32196 this.fireEvent("selectionchange", this, this.selNodes);
32202 * @param {TreeNode} node The node to unselect
32204 unselect : function(node){
32205 if(this.selMap[node.id]){
32206 node.ui.onSelectedChange(false);
32207 var sn = this.selNodes;
32210 index = sn.indexOf(node);
32212 for(var i = 0, len = sn.length; i < len; i++){
32220 this.selNodes.splice(index, 1);
32222 delete this.selMap[node.id];
32223 this.fireEvent("selectionchange", this, this.selNodes);
32228 * Clear all selections
32230 clearSelections : function(suppressEvent){
32231 var sn = this.selNodes;
32233 for(var i = 0, len = sn.length; i < len; i++){
32234 sn[i].ui.onSelectedChange(false);
32236 this.selNodes = [];
32238 if(suppressEvent !== true){
32239 this.fireEvent("selectionchange", this, this.selNodes);
32245 * Returns true if the node is selected
32246 * @param {TreeNode} node The node to check
32247 * @return {Boolean}
32249 isSelected : function(node){
32250 return this.selMap[node.id] ? true : false;
32254 * Returns an array of the selected nodes
32257 getSelectedNodes : function(){
32258 return this.selNodes;
32261 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32263 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32265 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32268 * Ext JS Library 1.1.1
32269 * Copyright(c) 2006-2007, Ext JS, LLC.
32271 * Originally Released Under LGPL - original licence link has changed is not relivant.
32274 * <script type="text/javascript">
32278 * @class Roo.tree.TreeNode
32279 * @extends Roo.data.Node
32280 * @cfg {String} text The text for this node
32281 * @cfg {Boolean} expanded true to start the node expanded
32282 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32283 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32284 * @cfg {Boolean} disabled true to start the node disabled
32285 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32286 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32287 * @cfg {String} cls A css class to be added to the node
32288 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32289 * @cfg {String} href URL of the link used for the node (defaults to #)
32290 * @cfg {String} hrefTarget target frame for the link
32291 * @cfg {String} qtip An Ext QuickTip for the node
32292 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32293 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32294 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32295 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32296 * (defaults to undefined with no checkbox rendered)
32298 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32300 Roo.tree.TreeNode = function(attributes){
32301 attributes = attributes || {};
32302 if(typeof attributes == "string"){
32303 attributes = {text: attributes};
32305 this.childrenRendered = false;
32306 this.rendered = false;
32307 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32308 this.expanded = attributes.expanded === true;
32309 this.isTarget = attributes.isTarget !== false;
32310 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32311 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32314 * Read-only. The text for this node. To change it use setText().
32317 this.text = attributes.text;
32319 * True if this node is disabled.
32322 this.disabled = attributes.disabled === true;
32326 * @event textchange
32327 * Fires when the text for this node is changed
32328 * @param {Node} this This node
32329 * @param {String} text The new text
32330 * @param {String} oldText The old text
32332 "textchange" : true,
32334 * @event beforeexpand
32335 * Fires before this node is expanded, return false to cancel.
32336 * @param {Node} this This node
32337 * @param {Boolean} deep
32338 * @param {Boolean} anim
32340 "beforeexpand" : true,
32342 * @event beforecollapse
32343 * Fires before this node is collapsed, return false to cancel.
32344 * @param {Node} this This node
32345 * @param {Boolean} deep
32346 * @param {Boolean} anim
32348 "beforecollapse" : true,
32351 * Fires when this node is expanded
32352 * @param {Node} this This node
32356 * @event disabledchange
32357 * Fires when the disabled status of this node changes
32358 * @param {Node} this This node
32359 * @param {Boolean} disabled
32361 "disabledchange" : true,
32364 * Fires when this node is collapsed
32365 * @param {Node} this This node
32369 * @event beforeclick
32370 * Fires before click processing. Return false to cancel the default action.
32371 * @param {Node} this This node
32372 * @param {Roo.EventObject} e The event object
32374 "beforeclick":true,
32376 * @event checkchange
32377 * Fires when a node with a checkbox's checked property changes
32378 * @param {Node} this This node
32379 * @param {Boolean} checked
32381 "checkchange":true,
32384 * Fires when this node is clicked
32385 * @param {Node} this This node
32386 * @param {Roo.EventObject} e The event object
32391 * Fires when this node is double clicked
32392 * @param {Node} this This node
32393 * @param {Roo.EventObject} e The event object
32397 * @event contextmenu
32398 * Fires when this node is right clicked
32399 * @param {Node} this This node
32400 * @param {Roo.EventObject} e The event object
32402 "contextmenu":true,
32404 * @event beforechildrenrendered
32405 * Fires right before the child nodes for this node are rendered
32406 * @param {Node} this This node
32408 "beforechildrenrendered":true
32411 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32414 * Read-only. The UI for this node
32417 this.ui = new uiClass(this);
32419 // finally support items[]
32420 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32425 Roo.each(this.attributes.items, function(c) {
32426 this.appendChild(Roo.factory(c,Roo.Tree));
32428 delete this.attributes.items;
32433 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32434 preventHScroll: true,
32436 * Returns true if this node is expanded
32437 * @return {Boolean}
32439 isExpanded : function(){
32440 return this.expanded;
32444 * Returns the UI object for this node
32445 * @return {TreeNodeUI}
32447 getUI : function(){
32451 // private override
32452 setFirstChild : function(node){
32453 var of = this.firstChild;
32454 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32455 if(this.childrenRendered && of && node != of){
32456 of.renderIndent(true, true);
32459 this.renderIndent(true, true);
32463 // private override
32464 setLastChild : function(node){
32465 var ol = this.lastChild;
32466 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32467 if(this.childrenRendered && ol && node != ol){
32468 ol.renderIndent(true, true);
32471 this.renderIndent(true, true);
32475 // these methods are overridden to provide lazy rendering support
32476 // private override
32477 appendChild : function()
32479 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32480 if(node && this.childrenRendered){
32483 this.ui.updateExpandIcon();
32487 // private override
32488 removeChild : function(node){
32489 this.ownerTree.getSelectionModel().unselect(node);
32490 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32491 // if it's been rendered remove dom node
32492 if(this.childrenRendered){
32495 if(this.childNodes.length < 1){
32496 this.collapse(false, false);
32498 this.ui.updateExpandIcon();
32500 if(!this.firstChild) {
32501 this.childrenRendered = false;
32506 // private override
32507 insertBefore : function(node, refNode){
32508 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32509 if(newNode && refNode && this.childrenRendered){
32512 this.ui.updateExpandIcon();
32517 * Sets the text for this node
32518 * @param {String} text
32520 setText : function(text){
32521 var oldText = this.text;
32523 this.attributes.text = text;
32524 if(this.rendered){ // event without subscribing
32525 this.ui.onTextChange(this, text, oldText);
32527 this.fireEvent("textchange", this, text, oldText);
32531 * Triggers selection of this node
32533 select : function(){
32534 this.getOwnerTree().getSelectionModel().select(this);
32538 * Triggers deselection of this node
32540 unselect : function(){
32541 this.getOwnerTree().getSelectionModel().unselect(this);
32545 * Returns true if this node is selected
32546 * @return {Boolean}
32548 isSelected : function(){
32549 return this.getOwnerTree().getSelectionModel().isSelected(this);
32553 * Expand this node.
32554 * @param {Boolean} deep (optional) True to expand all children as well
32555 * @param {Boolean} anim (optional) false to cancel the default animation
32556 * @param {Function} callback (optional) A callback to be called when
32557 * expanding this node completes (does not wait for deep expand to complete).
32558 * Called with 1 parameter, this node.
32560 expand : function(deep, anim, callback){
32561 if(!this.expanded){
32562 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32565 if(!this.childrenRendered){
32566 this.renderChildren();
32568 this.expanded = true;
32569 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32570 this.ui.animExpand(function(){
32571 this.fireEvent("expand", this);
32572 if(typeof callback == "function"){
32576 this.expandChildNodes(true);
32578 }.createDelegate(this));
32582 this.fireEvent("expand", this);
32583 if(typeof callback == "function"){
32588 if(typeof callback == "function"){
32593 this.expandChildNodes(true);
32597 isHiddenRoot : function(){
32598 return this.isRoot && !this.getOwnerTree().rootVisible;
32602 * Collapse this node.
32603 * @param {Boolean} deep (optional) True to collapse all children as well
32604 * @param {Boolean} anim (optional) false to cancel the default animation
32606 collapse : function(deep, anim){
32607 if(this.expanded && !this.isHiddenRoot()){
32608 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32611 this.expanded = false;
32612 if((this.getOwnerTree().animate && anim !== false) || anim){
32613 this.ui.animCollapse(function(){
32614 this.fireEvent("collapse", this);
32616 this.collapseChildNodes(true);
32618 }.createDelegate(this));
32621 this.ui.collapse();
32622 this.fireEvent("collapse", this);
32626 var cs = this.childNodes;
32627 for(var i = 0, len = cs.length; i < len; i++) {
32628 cs[i].collapse(true, false);
32634 delayedExpand : function(delay){
32635 if(!this.expandProcId){
32636 this.expandProcId = this.expand.defer(delay, this);
32641 cancelExpand : function(){
32642 if(this.expandProcId){
32643 clearTimeout(this.expandProcId);
32645 this.expandProcId = false;
32649 * Toggles expanded/collapsed state of the node
32651 toggle : function(){
32660 * Ensures all parent nodes are expanded
32662 ensureVisible : function(callback){
32663 var tree = this.getOwnerTree();
32664 tree.expandPath(this.parentNode.getPath(), false, function(){
32665 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32666 Roo.callback(callback);
32667 }.createDelegate(this));
32671 * Expand all child nodes
32672 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32674 expandChildNodes : function(deep){
32675 var cs = this.childNodes;
32676 for(var i = 0, len = cs.length; i < len; i++) {
32677 cs[i].expand(deep);
32682 * Collapse all child nodes
32683 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32685 collapseChildNodes : function(deep){
32686 var cs = this.childNodes;
32687 for(var i = 0, len = cs.length; i < len; i++) {
32688 cs[i].collapse(deep);
32693 * Disables this node
32695 disable : function(){
32696 this.disabled = true;
32698 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32699 this.ui.onDisableChange(this, true);
32701 this.fireEvent("disabledchange", this, true);
32705 * Enables this node
32707 enable : function(){
32708 this.disabled = false;
32709 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32710 this.ui.onDisableChange(this, false);
32712 this.fireEvent("disabledchange", this, false);
32716 renderChildren : function(suppressEvent){
32717 if(suppressEvent !== false){
32718 this.fireEvent("beforechildrenrendered", this);
32720 var cs = this.childNodes;
32721 for(var i = 0, len = cs.length; i < len; i++){
32722 cs[i].render(true);
32724 this.childrenRendered = true;
32728 sort : function(fn, scope){
32729 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32730 if(this.childrenRendered){
32731 var cs = this.childNodes;
32732 for(var i = 0, len = cs.length; i < len; i++){
32733 cs[i].render(true);
32739 render : function(bulkRender){
32740 this.ui.render(bulkRender);
32741 if(!this.rendered){
32742 this.rendered = true;
32744 this.expanded = false;
32745 this.expand(false, false);
32751 renderIndent : function(deep, refresh){
32753 this.ui.childIndent = null;
32755 this.ui.renderIndent();
32756 if(deep === true && this.childrenRendered){
32757 var cs = this.childNodes;
32758 for(var i = 0, len = cs.length; i < len; i++){
32759 cs[i].renderIndent(true, refresh);
32765 * Ext JS Library 1.1.1
32766 * Copyright(c) 2006-2007, Ext JS, LLC.
32768 * Originally Released Under LGPL - original licence link has changed is not relivant.
32771 * <script type="text/javascript">
32775 * @class Roo.tree.AsyncTreeNode
32776 * @extends Roo.tree.TreeNode
32777 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32779 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32781 Roo.tree.AsyncTreeNode = function(config){
32782 this.loaded = false;
32783 this.loading = false;
32784 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32786 * @event beforeload
32787 * Fires before this node is loaded, return false to cancel
32788 * @param {Node} this This node
32790 this.addEvents({'beforeload':true, 'load': true});
32793 * Fires when this node is loaded
32794 * @param {Node} this This node
32797 * The loader used by this node (defaults to using the tree's defined loader)
32802 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32803 expand : function(deep, anim, callback){
32804 if(this.loading){ // if an async load is already running, waiting til it's done
32806 var f = function(){
32807 if(!this.loading){ // done loading
32808 clearInterval(timer);
32809 this.expand(deep, anim, callback);
32811 }.createDelegate(this);
32812 timer = setInterval(f, 200);
32816 if(this.fireEvent("beforeload", this) === false){
32819 this.loading = true;
32820 this.ui.beforeLoad(this);
32821 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32823 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32827 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32831 * Returns true if this node is currently loading
32832 * @return {Boolean}
32834 isLoading : function(){
32835 return this.loading;
32838 loadComplete : function(deep, anim, callback){
32839 this.loading = false;
32840 this.loaded = true;
32841 this.ui.afterLoad(this);
32842 this.fireEvent("load", this);
32843 this.expand(deep, anim, callback);
32847 * Returns true if this node has been loaded
32848 * @return {Boolean}
32850 isLoaded : function(){
32851 return this.loaded;
32854 hasChildNodes : function(){
32855 if(!this.isLeaf() && !this.loaded){
32858 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32863 * Trigger a reload for this node
32864 * @param {Function} callback
32866 reload : function(callback){
32867 this.collapse(false, false);
32868 while(this.firstChild){
32869 this.removeChild(this.firstChild);
32871 this.childrenRendered = false;
32872 this.loaded = false;
32873 if(this.isHiddenRoot()){
32874 this.expanded = false;
32876 this.expand(false, false, callback);
32880 * Ext JS Library 1.1.1
32881 * Copyright(c) 2006-2007, Ext JS, LLC.
32883 * Originally Released Under LGPL - original licence link has changed is not relivant.
32886 * <script type="text/javascript">
32890 * @class Roo.tree.TreeNodeUI
32892 * @param {Object} node The node to render
32893 * The TreeNode UI implementation is separate from the
32894 * tree implementation. Unless you are customizing the tree UI,
32895 * you should never have to use this directly.
32897 Roo.tree.TreeNodeUI = function(node){
32899 this.rendered = false;
32900 this.animating = false;
32901 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32904 Roo.tree.TreeNodeUI.prototype = {
32905 removeChild : function(node){
32907 this.ctNode.removeChild(node.ui.getEl());
32911 beforeLoad : function(){
32912 this.addClass("x-tree-node-loading");
32915 afterLoad : function(){
32916 this.removeClass("x-tree-node-loading");
32919 onTextChange : function(node, text, oldText){
32921 this.textNode.innerHTML = text;
32925 onDisableChange : function(node, state){
32926 this.disabled = state;
32928 this.addClass("x-tree-node-disabled");
32930 this.removeClass("x-tree-node-disabled");
32934 onSelectedChange : function(state){
32937 this.addClass("x-tree-selected");
32940 this.removeClass("x-tree-selected");
32944 onMove : function(tree, node, oldParent, newParent, index, refNode){
32945 this.childIndent = null;
32947 var targetNode = newParent.ui.getContainer();
32948 if(!targetNode){//target not rendered
32949 this.holder = document.createElement("div");
32950 this.holder.appendChild(this.wrap);
32953 var insertBefore = refNode ? refNode.ui.getEl() : null;
32955 targetNode.insertBefore(this.wrap, insertBefore);
32957 targetNode.appendChild(this.wrap);
32959 this.node.renderIndent(true);
32963 addClass : function(cls){
32965 Roo.fly(this.elNode).addClass(cls);
32969 removeClass : function(cls){
32971 Roo.fly(this.elNode).removeClass(cls);
32975 remove : function(){
32977 this.holder = document.createElement("div");
32978 this.holder.appendChild(this.wrap);
32982 fireEvent : function(){
32983 return this.node.fireEvent.apply(this.node, arguments);
32986 initEvents : function(){
32987 this.node.on("move", this.onMove, this);
32988 var E = Roo.EventManager;
32989 var a = this.anchor;
32991 var el = Roo.fly(a, '_treeui');
32993 if(Roo.isOpera){ // opera render bug ignores the CSS
32994 el.setStyle("text-decoration", "none");
32997 el.on("click", this.onClick, this);
32998 el.on("dblclick", this.onDblClick, this);
33001 Roo.EventManager.on(this.checkbox,
33002 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33005 el.on("contextmenu", this.onContextMenu, this);
33007 var icon = Roo.fly(this.iconNode);
33008 icon.on("click", this.onClick, this);
33009 icon.on("dblclick", this.onDblClick, this);
33010 icon.on("contextmenu", this.onContextMenu, this);
33011 E.on(this.ecNode, "click", this.ecClick, this, true);
33013 if(this.node.disabled){
33014 this.addClass("x-tree-node-disabled");
33016 if(this.node.hidden){
33017 this.addClass("x-tree-node-disabled");
33019 var ot = this.node.getOwnerTree();
33020 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33021 if(dd && (!this.node.isRoot || ot.rootVisible)){
33022 Roo.dd.Registry.register(this.elNode, {
33024 handles: this.getDDHandles(),
33030 getDDHandles : function(){
33031 return [this.iconNode, this.textNode];
33036 this.wrap.style.display = "none";
33042 this.wrap.style.display = "";
33046 onContextMenu : function(e){
33047 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33048 e.preventDefault();
33050 this.fireEvent("contextmenu", this.node, e);
33054 onClick : function(e){
33059 if(this.fireEvent("beforeclick", this.node, e) !== false){
33060 if(!this.disabled && this.node.attributes.href){
33061 this.fireEvent("click", this.node, e);
33064 e.preventDefault();
33069 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33070 this.node.toggle();
33073 this.fireEvent("click", this.node, e);
33079 onDblClick : function(e){
33080 e.preventDefault();
33085 this.toggleCheck();
33087 if(!this.animating && this.node.hasChildNodes()){
33088 this.node.toggle();
33090 this.fireEvent("dblclick", this.node, e);
33093 onCheckChange : function(){
33094 var checked = this.checkbox.checked;
33095 this.node.attributes.checked = checked;
33096 this.fireEvent('checkchange', this.node, checked);
33099 ecClick : function(e){
33100 if(!this.animating && this.node.hasChildNodes()){
33101 this.node.toggle();
33105 startDrop : function(){
33106 this.dropping = true;
33109 // delayed drop so the click event doesn't get fired on a drop
33110 endDrop : function(){
33111 setTimeout(function(){
33112 this.dropping = false;
33113 }.createDelegate(this), 50);
33116 expand : function(){
33117 this.updateExpandIcon();
33118 this.ctNode.style.display = "";
33121 focus : function(){
33122 if(!this.node.preventHScroll){
33123 try{this.anchor.focus();
33125 }else if(!Roo.isIE){
33127 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33128 var l = noscroll.scrollLeft;
33129 this.anchor.focus();
33130 noscroll.scrollLeft = l;
33135 toggleCheck : function(value){
33136 var cb = this.checkbox;
33138 cb.checked = (value === undefined ? !cb.checked : value);
33144 this.anchor.blur();
33148 animExpand : function(callback){
33149 var ct = Roo.get(this.ctNode);
33151 if(!this.node.hasChildNodes()){
33152 this.updateExpandIcon();
33153 this.ctNode.style.display = "";
33154 Roo.callback(callback);
33157 this.animating = true;
33158 this.updateExpandIcon();
33161 callback : function(){
33162 this.animating = false;
33163 Roo.callback(callback);
33166 duration: this.node.ownerTree.duration || .25
33170 highlight : function(){
33171 var tree = this.node.getOwnerTree();
33172 Roo.fly(this.wrap).highlight(
33173 tree.hlColor || "C3DAF9",
33174 {endColor: tree.hlBaseColor}
33178 collapse : function(){
33179 this.updateExpandIcon();
33180 this.ctNode.style.display = "none";
33183 animCollapse : function(callback){
33184 var ct = Roo.get(this.ctNode);
33185 ct.enableDisplayMode('block');
33188 this.animating = true;
33189 this.updateExpandIcon();
33192 callback : function(){
33193 this.animating = false;
33194 Roo.callback(callback);
33197 duration: this.node.ownerTree.duration || .25
33201 getContainer : function(){
33202 return this.ctNode;
33205 getEl : function(){
33209 appendDDGhost : function(ghostNode){
33210 ghostNode.appendChild(this.elNode.cloneNode(true));
33213 getDDRepairXY : function(){
33214 return Roo.lib.Dom.getXY(this.iconNode);
33217 onRender : function(){
33221 render : function(bulkRender){
33222 var n = this.node, a = n.attributes;
33223 var targetNode = n.parentNode ?
33224 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33226 if(!this.rendered){
33227 this.rendered = true;
33229 this.renderElements(n, a, targetNode, bulkRender);
33232 if(this.textNode.setAttributeNS){
33233 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33235 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33238 this.textNode.setAttribute("ext:qtip", a.qtip);
33240 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33243 }else if(a.qtipCfg){
33244 a.qtipCfg.target = Roo.id(this.textNode);
33245 Roo.QuickTips.register(a.qtipCfg);
33248 if(!this.node.expanded){
33249 this.updateExpandIcon();
33252 if(bulkRender === true) {
33253 targetNode.appendChild(this.wrap);
33258 renderElements : function(n, a, targetNode, bulkRender)
33260 // add some indent caching, this helps performance when rendering a large tree
33261 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33262 var t = n.getOwnerTree();
33263 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33264 if (typeof(n.attributes.html) != 'undefined') {
33265 txt = n.attributes.html;
33267 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33268 var cb = typeof a.checked == 'boolean';
33269 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33270 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33271 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33272 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33273 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33274 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33275 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33276 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33277 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33278 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33281 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33282 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33283 n.nextSibling.ui.getEl(), buf.join(""));
33285 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33288 this.elNode = this.wrap.childNodes[0];
33289 this.ctNode = this.wrap.childNodes[1];
33290 var cs = this.elNode.childNodes;
33291 this.indentNode = cs[0];
33292 this.ecNode = cs[1];
33293 this.iconNode = cs[2];
33296 this.checkbox = cs[3];
33299 this.anchor = cs[index];
33300 this.textNode = cs[index].firstChild;
33303 getAnchor : function(){
33304 return this.anchor;
33307 getTextEl : function(){
33308 return this.textNode;
33311 getIconEl : function(){
33312 return this.iconNode;
33315 isChecked : function(){
33316 return this.checkbox ? this.checkbox.checked : false;
33319 updateExpandIcon : function(){
33321 var n = this.node, c1, c2;
33322 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33323 var hasChild = n.hasChildNodes();
33327 c1 = "x-tree-node-collapsed";
33328 c2 = "x-tree-node-expanded";
33331 c1 = "x-tree-node-expanded";
33332 c2 = "x-tree-node-collapsed";
33335 this.removeClass("x-tree-node-leaf");
33336 this.wasLeaf = false;
33338 if(this.c1 != c1 || this.c2 != c2){
33339 Roo.fly(this.elNode).replaceClass(c1, c2);
33340 this.c1 = c1; this.c2 = c2;
33343 // this changes non-leafs into leafs if they have no children.
33344 // it's not very rational behaviour..
33346 if(!this.wasLeaf && this.node.leaf){
33347 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33350 this.wasLeaf = true;
33353 var ecc = "x-tree-ec-icon "+cls;
33354 if(this.ecc != ecc){
33355 this.ecNode.className = ecc;
33361 getChildIndent : function(){
33362 if(!this.childIndent){
33366 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33368 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33370 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33375 this.childIndent = buf.join("");
33377 return this.childIndent;
33380 renderIndent : function(){
33383 var p = this.node.parentNode;
33385 indent = p.ui.getChildIndent();
33387 if(this.indentMarkup != indent){ // don't rerender if not required
33388 this.indentNode.innerHTML = indent;
33389 this.indentMarkup = indent;
33391 this.updateExpandIcon();
33396 Roo.tree.RootTreeNodeUI = function(){
33397 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33399 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33400 render : function(){
33401 if(!this.rendered){
33402 var targetNode = this.node.ownerTree.innerCt.dom;
33403 this.node.expanded = true;
33404 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33405 this.wrap = this.ctNode = targetNode.firstChild;
33408 collapse : function(){
33410 expand : function(){
33414 * Ext JS Library 1.1.1
33415 * Copyright(c) 2006-2007, Ext JS, LLC.
33417 * Originally Released Under LGPL - original licence link has changed is not relivant.
33420 * <script type="text/javascript">
33423 * @class Roo.tree.TreeLoader
33424 * @extends Roo.util.Observable
33425 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33426 * nodes from a specified URL. The response must be a javascript Array definition
33427 * who's elements are node definition objects. eg:
33432 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33433 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33440 * The old style respose with just an array is still supported, but not recommended.
33443 * A server request is sent, and child nodes are loaded only when a node is expanded.
33444 * The loading node's id is passed to the server under the parameter name "node" to
33445 * enable the server to produce the correct child nodes.
33447 * To pass extra parameters, an event handler may be attached to the "beforeload"
33448 * event, and the parameters specified in the TreeLoader's baseParams property:
33450 myTreeLoader.on("beforeload", function(treeLoader, node) {
33451 this.baseParams.category = node.attributes.category;
33454 * This would pass an HTTP parameter called "category" to the server containing
33455 * the value of the Node's "category" attribute.
33457 * Creates a new Treeloader.
33458 * @param {Object} config A config object containing config properties.
33460 Roo.tree.TreeLoader = function(config){
33461 this.baseParams = {};
33462 this.requestMethod = "POST";
33463 Roo.apply(this, config);
33468 * @event beforeload
33469 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33470 * @param {Object} This TreeLoader object.
33471 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33472 * @param {Object} callback The callback function specified in the {@link #load} call.
33477 * Fires when the node has been successfuly loaded.
33478 * @param {Object} This TreeLoader object.
33479 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33480 * @param {Object} response The response object containing the data from the server.
33484 * @event loadexception
33485 * Fires if the network request failed.
33486 * @param {Object} This TreeLoader object.
33487 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33488 * @param {Object} response The response object containing the data from the server.
33490 loadexception : true,
33493 * Fires before a node is created, enabling you to return custom Node types
33494 * @param {Object} This TreeLoader object.
33495 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33500 Roo.tree.TreeLoader.superclass.constructor.call(this);
33503 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33505 * @cfg {String} dataUrl The URL from which to request a Json string which
33506 * specifies an array of node definition object representing the child nodes
33510 * @cfg {String} requestMethod either GET or POST
33511 * defaults to POST (due to BC)
33515 * @cfg {Object} baseParams (optional) An object containing properties which
33516 * specify HTTP parameters to be passed to each request for child nodes.
33519 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33520 * created by this loader. If the attributes sent by the server have an attribute in this object,
33521 * they take priority.
33524 * @cfg {Object} uiProviders (optional) An object containing properties which
33526 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33527 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33528 * <i>uiProvider</i> attribute of a returned child node is a string rather
33529 * than a reference to a TreeNodeUI implementation, this that string value
33530 * is used as a property name in the uiProviders object. You can define the provider named
33531 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33536 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33537 * child nodes before loading.
33539 clearOnLoad : true,
33542 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33543 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33544 * Grid query { data : [ .....] }
33549 * @cfg {String} queryParam (optional)
33550 * Name of the query as it will be passed on the querystring (defaults to 'node')
33551 * eg. the request will be ?node=[id]
33558 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33559 * This is called automatically when a node is expanded, but may be used to reload
33560 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33561 * @param {Roo.tree.TreeNode} node
33562 * @param {Function} callback
33564 load : function(node, callback){
33565 if(this.clearOnLoad){
33566 while(node.firstChild){
33567 node.removeChild(node.firstChild);
33570 if(node.attributes.children){ // preloaded json children
33571 var cs = node.attributes.children;
33572 for(var i = 0, len = cs.length; i < len; i++){
33573 node.appendChild(this.createNode(cs[i]));
33575 if(typeof callback == "function"){
33578 }else if(this.dataUrl){
33579 this.requestData(node, callback);
33583 getParams: function(node){
33584 var buf = [], bp = this.baseParams;
33585 for(var key in bp){
33586 if(typeof bp[key] != "function"){
33587 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33590 var n = this.queryParam === false ? 'node' : this.queryParam;
33591 buf.push(n + "=", encodeURIComponent(node.id));
33592 return buf.join("");
33595 requestData : function(node, callback){
33596 if(this.fireEvent("beforeload", this, node, callback) !== false){
33597 this.transId = Roo.Ajax.request({
33598 method:this.requestMethod,
33599 url: this.dataUrl||this.url,
33600 success: this.handleResponse,
33601 failure: this.handleFailure,
33603 argument: {callback: callback, node: node},
33604 params: this.getParams(node)
33607 // if the load is cancelled, make sure we notify
33608 // the node that we are done
33609 if(typeof callback == "function"){
33615 isLoading : function(){
33616 return this.transId ? true : false;
33619 abort : function(){
33620 if(this.isLoading()){
33621 Roo.Ajax.abort(this.transId);
33626 createNode : function(attr)
33628 // apply baseAttrs, nice idea Corey!
33629 if(this.baseAttrs){
33630 Roo.applyIf(attr, this.baseAttrs);
33632 if(this.applyLoader !== false){
33633 attr.loader = this;
33635 // uiProvider = depreciated..
33637 if(typeof(attr.uiProvider) == 'string'){
33638 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33639 /** eval:var:attr */ eval(attr.uiProvider);
33641 if(typeof(this.uiProviders['default']) != 'undefined') {
33642 attr.uiProvider = this.uiProviders['default'];
33645 this.fireEvent('create', this, attr);
33647 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33649 new Roo.tree.TreeNode(attr) :
33650 new Roo.tree.AsyncTreeNode(attr));
33653 processResponse : function(response, node, callback)
33655 var json = response.responseText;
33658 var o = Roo.decode(json);
33660 if (this.root === false && typeof(o.success) != undefined) {
33661 this.root = 'data'; // the default behaviour for list like data..
33664 if (this.root !== false && !o.success) {
33665 // it's a failure condition.
33666 var a = response.argument;
33667 this.fireEvent("loadexception", this, a.node, response);
33668 Roo.log("Load failed - should have a handler really");
33674 if (this.root !== false) {
33678 for(var i = 0, len = o.length; i < len; i++){
33679 var n = this.createNode(o[i]);
33681 node.appendChild(n);
33684 if(typeof callback == "function"){
33685 callback(this, node);
33688 this.handleFailure(response);
33692 handleResponse : function(response){
33693 this.transId = false;
33694 var a = response.argument;
33695 this.processResponse(response, a.node, a.callback);
33696 this.fireEvent("load", this, a.node, response);
33699 handleFailure : function(response)
33701 // should handle failure better..
33702 this.transId = false;
33703 var a = response.argument;
33704 this.fireEvent("loadexception", this, a.node, response);
33705 if(typeof a.callback == "function"){
33706 a.callback(this, a.node);
33711 * Ext JS Library 1.1.1
33712 * Copyright(c) 2006-2007, Ext JS, LLC.
33714 * Originally Released Under LGPL - original licence link has changed is not relivant.
33717 * <script type="text/javascript">
33721 * @class Roo.tree.TreeFilter
33722 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33723 * @param {TreePanel} tree
33724 * @param {Object} config (optional)
33726 Roo.tree.TreeFilter = function(tree, config){
33728 this.filtered = {};
33729 Roo.apply(this, config);
33732 Roo.tree.TreeFilter.prototype = {
33739 * Filter the data by a specific attribute.
33740 * @param {String/RegExp} value Either string that the attribute value
33741 * should start with or a RegExp to test against the attribute
33742 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33743 * @param {TreeNode} startNode (optional) The node to start the filter at.
33745 filter : function(value, attr, startNode){
33746 attr = attr || "text";
33748 if(typeof value == "string"){
33749 var vlen = value.length;
33750 // auto clear empty filter
33751 if(vlen == 0 && this.clearBlank){
33755 value = value.toLowerCase();
33757 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33759 }else if(value.exec){ // regex?
33761 return value.test(n.attributes[attr]);
33764 throw 'Illegal filter type, must be string or regex';
33766 this.filterBy(f, null, startNode);
33770 * Filter by a function. The passed function will be called with each
33771 * node in the tree (or from the startNode). If the function returns true, the node is kept
33772 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33773 * @param {Function} fn The filter function
33774 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33776 filterBy : function(fn, scope, startNode){
33777 startNode = startNode || this.tree.root;
33778 if(this.autoClear){
33781 var af = this.filtered, rv = this.reverse;
33782 var f = function(n){
33783 if(n == startNode){
33789 var m = fn.call(scope || n, n);
33797 startNode.cascade(f);
33800 if(typeof id != "function"){
33802 if(n && n.parentNode){
33803 n.parentNode.removeChild(n);
33811 * Clears the current filter. Note: with the "remove" option
33812 * set a filter cannot be cleared.
33814 clear : function(){
33816 var af = this.filtered;
33818 if(typeof id != "function"){
33825 this.filtered = {};
33830 * Ext JS Library 1.1.1
33831 * Copyright(c) 2006-2007, Ext JS, LLC.
33833 * Originally Released Under LGPL - original licence link has changed is not relivant.
33836 * <script type="text/javascript">
33841 * @class Roo.tree.TreeSorter
33842 * Provides sorting of nodes in a TreePanel
33844 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33845 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33846 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33847 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33848 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33849 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33851 * @param {TreePanel} tree
33852 * @param {Object} config
33854 Roo.tree.TreeSorter = function(tree, config){
33855 Roo.apply(this, config);
33856 tree.on("beforechildrenrendered", this.doSort, this);
33857 tree.on("append", this.updateSort, this);
33858 tree.on("insert", this.updateSort, this);
33860 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33861 var p = this.property || "text";
33862 var sortType = this.sortType;
33863 var fs = this.folderSort;
33864 var cs = this.caseSensitive === true;
33865 var leafAttr = this.leafAttr || 'leaf';
33867 this.sortFn = function(n1, n2){
33869 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33872 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33876 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33877 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33879 return dsc ? +1 : -1;
33881 return dsc ? -1 : +1;
33888 Roo.tree.TreeSorter.prototype = {
33889 doSort : function(node){
33890 node.sort(this.sortFn);
33893 compareNodes : function(n1, n2){
33894 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33897 updateSort : function(tree, node){
33898 if(node.childrenRendered){
33899 this.doSort.defer(1, this, [node]);
33904 * Ext JS Library 1.1.1
33905 * Copyright(c) 2006-2007, Ext JS, LLC.
33907 * Originally Released Under LGPL - original licence link has changed is not relivant.
33910 * <script type="text/javascript">
33913 if(Roo.dd.DropZone){
33915 Roo.tree.TreeDropZone = function(tree, config){
33916 this.allowParentInsert = false;
33917 this.allowContainerDrop = false;
33918 this.appendOnly = false;
33919 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33921 this.lastInsertClass = "x-tree-no-status";
33922 this.dragOverData = {};
33925 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33926 ddGroup : "TreeDD",
33929 expandDelay : 1000,
33931 expandNode : function(node){
33932 if(node.hasChildNodes() && !node.isExpanded()){
33933 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33937 queueExpand : function(node){
33938 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33941 cancelExpand : function(){
33942 if(this.expandProcId){
33943 clearTimeout(this.expandProcId);
33944 this.expandProcId = false;
33948 isValidDropPoint : function(n, pt, dd, e, data){
33949 if(!n || !data){ return false; }
33950 var targetNode = n.node;
33951 var dropNode = data.node;
33952 // default drop rules
33953 if(!(targetNode && targetNode.isTarget && pt)){
33956 if(pt == "append" && targetNode.allowChildren === false){
33959 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33962 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33965 // reuse the object
33966 var overEvent = this.dragOverData;
33967 overEvent.tree = this.tree;
33968 overEvent.target = targetNode;
33969 overEvent.data = data;
33970 overEvent.point = pt;
33971 overEvent.source = dd;
33972 overEvent.rawEvent = e;
33973 overEvent.dropNode = dropNode;
33974 overEvent.cancel = false;
33975 var result = this.tree.fireEvent("nodedragover", overEvent);
33976 return overEvent.cancel === false && result !== false;
33979 getDropPoint : function(e, n, dd)
33983 return tn.allowChildren !== false ? "append" : false; // always append for root
33985 var dragEl = n.ddel;
33986 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33987 var y = Roo.lib.Event.getPageY(e);
33988 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33990 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33991 var noAppend = tn.allowChildren === false;
33992 if(this.appendOnly || tn.parentNode.allowChildren === false){
33993 return noAppend ? false : "append";
33995 var noBelow = false;
33996 if(!this.allowParentInsert){
33997 noBelow = tn.hasChildNodes() && tn.isExpanded();
33999 var q = (b - t) / (noAppend ? 2 : 3);
34000 if(y >= t && y < (t + q)){
34002 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34009 onNodeEnter : function(n, dd, e, data)
34011 this.cancelExpand();
34014 onNodeOver : function(n, dd, e, data)
34017 var pt = this.getDropPoint(e, n, dd);
34020 // auto node expand check
34021 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34022 this.queueExpand(node);
34023 }else if(pt != "append"){
34024 this.cancelExpand();
34027 // set the insert point style on the target node
34028 var returnCls = this.dropNotAllowed;
34029 if(this.isValidDropPoint(n, pt, dd, e, data)){
34034 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34035 cls = "x-tree-drag-insert-above";
34036 }else if(pt == "below"){
34037 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34038 cls = "x-tree-drag-insert-below";
34040 returnCls = "x-tree-drop-ok-append";
34041 cls = "x-tree-drag-append";
34043 if(this.lastInsertClass != cls){
34044 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34045 this.lastInsertClass = cls;
34052 onNodeOut : function(n, dd, e, data){
34054 this.cancelExpand();
34055 this.removeDropIndicators(n);
34058 onNodeDrop : function(n, dd, e, data){
34059 var point = this.getDropPoint(e, n, dd);
34060 var targetNode = n.node;
34061 targetNode.ui.startDrop();
34062 if(!this.isValidDropPoint(n, point, dd, e, data)){
34063 targetNode.ui.endDrop();
34066 // first try to find the drop node
34067 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34070 target: targetNode,
34075 dropNode: dropNode,
34078 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34079 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34080 targetNode.ui.endDrop();
34083 // allow target changing
34084 targetNode = dropEvent.target;
34085 if(point == "append" && !targetNode.isExpanded()){
34086 targetNode.expand(false, null, function(){
34087 this.completeDrop(dropEvent);
34088 }.createDelegate(this));
34090 this.completeDrop(dropEvent);
34095 completeDrop : function(de){
34096 var ns = de.dropNode, p = de.point, t = de.target;
34097 if(!(ns instanceof Array)){
34101 for(var i = 0, len = ns.length; i < len; i++){
34104 t.parentNode.insertBefore(n, t);
34105 }else if(p == "below"){
34106 t.parentNode.insertBefore(n, t.nextSibling);
34112 if(this.tree.hlDrop){
34116 this.tree.fireEvent("nodedrop", de);
34119 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34120 if(this.tree.hlDrop){
34121 dropNode.ui.focus();
34122 dropNode.ui.highlight();
34124 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34127 getTree : function(){
34131 removeDropIndicators : function(n){
34134 Roo.fly(el).removeClass([
34135 "x-tree-drag-insert-above",
34136 "x-tree-drag-insert-below",
34137 "x-tree-drag-append"]);
34138 this.lastInsertClass = "_noclass";
34142 beforeDragDrop : function(target, e, id){
34143 this.cancelExpand();
34147 afterRepair : function(data){
34148 if(data && Roo.enableFx){
34149 data.node.ui.highlight();
34159 * Ext JS Library 1.1.1
34160 * Copyright(c) 2006-2007, Ext JS, LLC.
34162 * Originally Released Under LGPL - original licence link has changed is not relivant.
34165 * <script type="text/javascript">
34169 if(Roo.dd.DragZone){
34170 Roo.tree.TreeDragZone = function(tree, config){
34171 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34175 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34176 ddGroup : "TreeDD",
34178 onBeforeDrag : function(data, e){
34180 return n && n.draggable && !n.disabled;
34184 onInitDrag : function(e){
34185 var data = this.dragData;
34186 this.tree.getSelectionModel().select(data.node);
34187 this.proxy.update("");
34188 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34189 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34192 getRepairXY : function(e, data){
34193 return data.node.ui.getDDRepairXY();
34196 onEndDrag : function(data, e){
34197 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34202 onValidDrop : function(dd, e, id){
34203 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34207 beforeInvalidDrop : function(e, id){
34208 // this scrolls the original position back into view
34209 var sm = this.tree.getSelectionModel();
34210 sm.clearSelections();
34211 sm.select(this.dragData.node);
34216 * Ext JS Library 1.1.1
34217 * Copyright(c) 2006-2007, Ext JS, LLC.
34219 * Originally Released Under LGPL - original licence link has changed is not relivant.
34222 * <script type="text/javascript">
34225 * @class Roo.tree.TreeEditor
34226 * @extends Roo.Editor
34227 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34228 * as the editor field.
34230 * @param {Object} config (used to be the tree panel.)
34231 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34233 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34234 * @cfg {Roo.form.TextField|Object} field The field configuration
34238 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34241 if (oldconfig) { // old style..
34242 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34245 tree = config.tree;
34246 config.field = config.field || {};
34247 config.field.xtype = 'TextField';
34248 field = Roo.factory(config.field, Roo.form);
34250 config = config || {};
34255 * @event beforenodeedit
34256 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34257 * false from the handler of this event.
34258 * @param {Editor} this
34259 * @param {Roo.tree.Node} node
34261 "beforenodeedit" : true
34265 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34269 tree.on('beforeclick', this.beforeNodeClick, this);
34270 tree.getTreeEl().on('mousedown', this.hide, this);
34271 this.on('complete', this.updateNode, this);
34272 this.on('beforestartedit', this.fitToTree, this);
34273 this.on('startedit', this.bindScroll, this, {delay:10});
34274 this.on('specialkey', this.onSpecialKey, this);
34277 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34279 * @cfg {String} alignment
34280 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34286 * @cfg {Boolean} hideEl
34287 * True to hide the bound element while the editor is displayed (defaults to false)
34291 * @cfg {String} cls
34292 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34294 cls: "x-small-editor x-tree-editor",
34296 * @cfg {Boolean} shim
34297 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34303 * @cfg {Number} maxWidth
34304 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34305 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34306 * scroll and client offsets into account prior to each edit.
34313 fitToTree : function(ed, el){
34314 var td = this.tree.getTreeEl().dom, nd = el.dom;
34315 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34316 td.scrollLeft = nd.offsetLeft;
34320 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34321 this.setSize(w, '');
34323 return this.fireEvent('beforenodeedit', this, this.editNode);
34328 triggerEdit : function(node){
34329 this.completeEdit();
34330 this.editNode = node;
34331 this.startEdit(node.ui.textNode, node.text);
34335 bindScroll : function(){
34336 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34340 beforeNodeClick : function(node, e){
34341 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34342 this.lastClick = new Date();
34343 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34345 this.triggerEdit(node);
34352 updateNode : function(ed, value){
34353 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34354 this.editNode.setText(value);
34358 onHide : function(){
34359 Roo.tree.TreeEditor.superclass.onHide.call(this);
34361 this.editNode.ui.focus();
34366 onSpecialKey : function(field, e){
34367 var k = e.getKey();
34371 }else if(k == e.ENTER && !e.hasModifier()){
34373 this.completeEdit();
34376 });//<Script type="text/javascript">
34379 * Ext JS Library 1.1.1
34380 * Copyright(c) 2006-2007, Ext JS, LLC.
34382 * Originally Released Under LGPL - original licence link has changed is not relivant.
34385 * <script type="text/javascript">
34389 * Not documented??? - probably should be...
34392 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34393 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34395 renderElements : function(n, a, targetNode, bulkRender){
34396 //consel.log("renderElements?");
34397 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34399 var t = n.getOwnerTree();
34400 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34402 var cols = t.columns;
34403 var bw = t.borderWidth;
34405 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34406 var cb = typeof a.checked == "boolean";
34407 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34408 var colcls = 'x-t-' + tid + '-c0';
34410 '<li class="x-tree-node">',
34413 '<div class="x-tree-node-el ', a.cls,'">',
34415 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34418 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34419 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34420 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34421 (a.icon ? ' x-tree-node-inline-icon' : ''),
34422 (a.iconCls ? ' '+a.iconCls : ''),
34423 '" unselectable="on" />',
34424 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34425 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34427 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34428 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34429 '<span unselectable="on" qtip="' + tx + '">',
34433 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34434 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34436 for(var i = 1, len = cols.length; i < len; i++){
34438 colcls = 'x-t-' + tid + '-c' +i;
34439 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34440 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34441 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34447 '<div class="x-clear"></div></div>',
34448 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34451 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34452 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34453 n.nextSibling.ui.getEl(), buf.join(""));
34455 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34457 var el = this.wrap.firstChild;
34459 this.elNode = el.firstChild;
34460 this.ranchor = el.childNodes[1];
34461 this.ctNode = this.wrap.childNodes[1];
34462 var cs = el.firstChild.childNodes;
34463 this.indentNode = cs[0];
34464 this.ecNode = cs[1];
34465 this.iconNode = cs[2];
34468 this.checkbox = cs[3];
34471 this.anchor = cs[index];
34473 this.textNode = cs[index].firstChild;
34475 //el.on("click", this.onClick, this);
34476 //el.on("dblclick", this.onDblClick, this);
34479 // console.log(this);
34481 initEvents : function(){
34482 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34485 var a = this.ranchor;
34487 var el = Roo.get(a);
34489 if(Roo.isOpera){ // opera render bug ignores the CSS
34490 el.setStyle("text-decoration", "none");
34493 el.on("click", this.onClick, this);
34494 el.on("dblclick", this.onDblClick, this);
34495 el.on("contextmenu", this.onContextMenu, this);
34499 /*onSelectedChange : function(state){
34502 this.addClass("x-tree-selected");
34505 this.removeClass("x-tree-selected");
34508 addClass : function(cls){
34510 Roo.fly(this.elRow).addClass(cls);
34516 removeClass : function(cls){
34518 Roo.fly(this.elRow).removeClass(cls);
34524 });//<Script type="text/javascript">
34528 * Ext JS Library 1.1.1
34529 * Copyright(c) 2006-2007, Ext JS, LLC.
34531 * Originally Released Under LGPL - original licence link has changed is not relivant.
34534 * <script type="text/javascript">
34539 * @class Roo.tree.ColumnTree
34540 * @extends Roo.data.TreePanel
34541 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34542 * @cfg {int} borderWidth compined right/left border allowance
34544 * @param {String/HTMLElement/Element} el The container element
34545 * @param {Object} config
34547 Roo.tree.ColumnTree = function(el, config)
34549 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34553 * Fire this event on a container when it resizes
34554 * @param {int} w Width
34555 * @param {int} h Height
34559 this.on('resize', this.onResize, this);
34562 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34566 borderWidth: Roo.isBorderBox ? 0 : 2,
34569 render : function(){
34570 // add the header.....
34572 Roo.tree.ColumnTree.superclass.render.apply(this);
34574 this.el.addClass('x-column-tree');
34576 this.headers = this.el.createChild(
34577 {cls:'x-tree-headers'},this.innerCt.dom);
34579 var cols = this.columns, c;
34580 var totalWidth = 0;
34582 var len = cols.length;
34583 for(var i = 0; i < len; i++){
34585 totalWidth += c.width;
34586 this.headEls.push(this.headers.createChild({
34587 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34589 cls:'x-tree-hd-text',
34592 style:'width:'+(c.width-this.borderWidth)+'px;'
34595 this.headers.createChild({cls:'x-clear'});
34596 // prevent floats from wrapping when clipped
34597 this.headers.setWidth(totalWidth);
34598 //this.innerCt.setWidth(totalWidth);
34599 this.innerCt.setStyle({ overflow: 'auto' });
34600 this.onResize(this.width, this.height);
34604 onResize : function(w,h)
34609 this.innerCt.setWidth(this.width);
34610 this.innerCt.setHeight(this.height-20);
34613 var cols = this.columns, c;
34614 var totalWidth = 0;
34616 var len = cols.length;
34617 for(var i = 0; i < len; i++){
34619 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34620 // it's the expander..
34621 expEl = this.headEls[i];
34624 totalWidth += c.width;
34628 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34630 this.headers.setWidth(w-20);
34639 * Ext JS Library 1.1.1
34640 * Copyright(c) 2006-2007, Ext JS, LLC.
34642 * Originally Released Under LGPL - original licence link has changed is not relivant.
34645 * <script type="text/javascript">
34649 * @class Roo.menu.Menu
34650 * @extends Roo.util.Observable
34651 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34652 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34654 * Creates a new Menu
34655 * @param {Object} config Configuration options
34657 Roo.menu.Menu = function(config){
34658 Roo.apply(this, config);
34659 this.id = this.id || Roo.id();
34662 * @event beforeshow
34663 * Fires before this menu is displayed
34664 * @param {Roo.menu.Menu} this
34668 * @event beforehide
34669 * Fires before this menu is hidden
34670 * @param {Roo.menu.Menu} this
34675 * Fires after this menu is displayed
34676 * @param {Roo.menu.Menu} this
34681 * Fires after this menu is hidden
34682 * @param {Roo.menu.Menu} this
34687 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34688 * @param {Roo.menu.Menu} this
34689 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34690 * @param {Roo.EventObject} e
34695 * Fires when the mouse is hovering over this menu
34696 * @param {Roo.menu.Menu} this
34697 * @param {Roo.EventObject} e
34698 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34703 * Fires when the mouse exits this menu
34704 * @param {Roo.menu.Menu} this
34705 * @param {Roo.EventObject} e
34706 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34711 * Fires when a menu item contained in this menu is clicked
34712 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34713 * @param {Roo.EventObject} e
34717 if (this.registerMenu) {
34718 Roo.menu.MenuMgr.register(this);
34721 var mis = this.items;
34722 this.items = new Roo.util.MixedCollection();
34724 this.add.apply(this, mis);
34728 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34730 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34734 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34735 * for bottom-right shadow (defaults to "sides")
34739 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34740 * this menu (defaults to "tl-tr?")
34742 subMenuAlign : "tl-tr?",
34744 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34745 * relative to its element of origin (defaults to "tl-bl?")
34747 defaultAlign : "tl-bl?",
34749 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34751 allowOtherMenus : false,
34753 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34755 registerMenu : true,
34760 render : function(){
34764 var el = this.el = new Roo.Layer({
34766 shadow:this.shadow,
34768 parentEl: this.parentEl || document.body,
34772 this.keyNav = new Roo.menu.MenuNav(this);
34775 el.addClass("x-menu-plain");
34778 el.addClass(this.cls);
34780 // generic focus element
34781 this.focusEl = el.createChild({
34782 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34784 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34785 ul.on("click", this.onClick, this);
34786 ul.on("mouseover", this.onMouseOver, this);
34787 ul.on("mouseout", this.onMouseOut, this);
34788 this.items.each(function(item){
34789 var li = document.createElement("li");
34790 li.className = "x-menu-list-item";
34791 ul.dom.appendChild(li);
34792 item.render(li, this);
34799 autoWidth : function(){
34800 var el = this.el, ul = this.ul;
34804 var w = this.width;
34807 }else if(Roo.isIE){
34808 el.setWidth(this.minWidth);
34809 var t = el.dom.offsetWidth; // force recalc
34810 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34815 delayAutoWidth : function(){
34818 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34820 this.awTask.delay(20);
34825 findTargetItem : function(e){
34826 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34827 if(t && t.menuItemId){
34828 return this.items.get(t.menuItemId);
34833 onClick : function(e){
34835 if(t = this.findTargetItem(e)){
34837 this.fireEvent("click", this, t, e);
34842 setActiveItem : function(item, autoExpand){
34843 if(item != this.activeItem){
34844 if(this.activeItem){
34845 this.activeItem.deactivate();
34847 this.activeItem = item;
34848 item.activate(autoExpand);
34849 }else if(autoExpand){
34855 tryActivate : function(start, step){
34856 var items = this.items;
34857 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34858 var item = items.get(i);
34859 if(!item.disabled && item.canActivate){
34860 this.setActiveItem(item, false);
34868 onMouseOver : function(e){
34870 if(t = this.findTargetItem(e)){
34871 if(t.canActivate && !t.disabled){
34872 this.setActiveItem(t, true);
34875 this.fireEvent("mouseover", this, e, t);
34879 onMouseOut : function(e){
34881 if(t = this.findTargetItem(e)){
34882 if(t == this.activeItem && t.shouldDeactivate(e)){
34883 this.activeItem.deactivate();
34884 delete this.activeItem;
34887 this.fireEvent("mouseout", this, e, t);
34891 * Read-only. Returns true if the menu is currently displayed, else false.
34894 isVisible : function(){
34895 return this.el && !this.hidden;
34899 * Displays this menu relative to another element
34900 * @param {String/HTMLElement/Roo.Element} element The element to align to
34901 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34902 * the element (defaults to this.defaultAlign)
34903 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34905 show : function(el, pos, parentMenu){
34906 this.parentMenu = parentMenu;
34910 this.fireEvent("beforeshow", this);
34911 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34915 * Displays this menu at a specific xy position
34916 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34917 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34919 showAt : function(xy, parentMenu, /* private: */_e){
34920 this.parentMenu = parentMenu;
34925 this.fireEvent("beforeshow", this);
34926 xy = this.el.adjustForConstraints(xy);
34930 this.hidden = false;
34932 this.fireEvent("show", this);
34935 focus : function(){
34937 this.doFocus.defer(50, this);
34941 doFocus : function(){
34943 this.focusEl.focus();
34948 * Hides this menu and optionally all parent menus
34949 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34951 hide : function(deep){
34952 if(this.el && this.isVisible()){
34953 this.fireEvent("beforehide", this);
34954 if(this.activeItem){
34955 this.activeItem.deactivate();
34956 this.activeItem = null;
34959 this.hidden = true;
34960 this.fireEvent("hide", this);
34962 if(deep === true && this.parentMenu){
34963 this.parentMenu.hide(true);
34968 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34969 * Any of the following are valid:
34971 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34972 * <li>An HTMLElement object which will be converted to a menu item</li>
34973 * <li>A menu item config object that will be created as a new menu item</li>
34974 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34975 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34980 var menu = new Roo.menu.Menu();
34982 // Create a menu item to add by reference
34983 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34985 // Add a bunch of items at once using different methods.
34986 // Only the last item added will be returned.
34987 var item = menu.add(
34988 menuItem, // add existing item by ref
34989 'Dynamic Item', // new TextItem
34990 '-', // new separator
34991 { text: 'Config Item' } // new item by config
34994 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34995 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34998 var a = arguments, l = a.length, item;
34999 for(var i = 0; i < l; i++){
35001 if ((typeof(el) == "object") && el.xtype && el.xns) {
35002 el = Roo.factory(el, Roo.menu);
35005 if(el.render){ // some kind of Item
35006 item = this.addItem(el);
35007 }else if(typeof el == "string"){ // string
35008 if(el == "separator" || el == "-"){
35009 item = this.addSeparator();
35011 item = this.addText(el);
35013 }else if(el.tagName || el.el){ // element
35014 item = this.addElement(el);
35015 }else if(typeof el == "object"){ // must be menu item config?
35016 item = this.addMenuItem(el);
35023 * Returns this menu's underlying {@link Roo.Element} object
35024 * @return {Roo.Element} The element
35026 getEl : function(){
35034 * Adds a separator bar to the menu
35035 * @return {Roo.menu.Item} The menu item that was added
35037 addSeparator : function(){
35038 return this.addItem(new Roo.menu.Separator());
35042 * Adds an {@link Roo.Element} object to the menu
35043 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35044 * @return {Roo.menu.Item} The menu item that was added
35046 addElement : function(el){
35047 return this.addItem(new Roo.menu.BaseItem(el));
35051 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35052 * @param {Roo.menu.Item} item The menu item to add
35053 * @return {Roo.menu.Item} The menu item that was added
35055 addItem : function(item){
35056 this.items.add(item);
35058 var li = document.createElement("li");
35059 li.className = "x-menu-list-item";
35060 this.ul.dom.appendChild(li);
35061 item.render(li, this);
35062 this.delayAutoWidth();
35068 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35069 * @param {Object} config A MenuItem config object
35070 * @return {Roo.menu.Item} The menu item that was added
35072 addMenuItem : function(config){
35073 if(!(config instanceof Roo.menu.Item)){
35074 if(typeof config.checked == "boolean"){ // must be check menu item config?
35075 config = new Roo.menu.CheckItem(config);
35077 config = new Roo.menu.Item(config);
35080 return this.addItem(config);
35084 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35085 * @param {String} text The text to display in the menu item
35086 * @return {Roo.menu.Item} The menu item that was added
35088 addText : function(text){
35089 return this.addItem(new Roo.menu.TextItem({ text : text }));
35093 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35094 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35095 * @param {Roo.menu.Item} item The menu item to add
35096 * @return {Roo.menu.Item} The menu item that was added
35098 insert : function(index, item){
35099 this.items.insert(index, item);
35101 var li = document.createElement("li");
35102 li.className = "x-menu-list-item";
35103 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35104 item.render(li, this);
35105 this.delayAutoWidth();
35111 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35112 * @param {Roo.menu.Item} item The menu item to remove
35114 remove : function(item){
35115 this.items.removeKey(item.id);
35120 * Removes and destroys all items in the menu
35122 removeAll : function(){
35124 while(f = this.items.first()){
35130 // MenuNav is a private utility class used internally by the Menu
35131 Roo.menu.MenuNav = function(menu){
35132 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35133 this.scope = this.menu = menu;
35136 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35137 doRelay : function(e, h){
35138 var k = e.getKey();
35139 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35140 this.menu.tryActivate(0, 1);
35143 return h.call(this.scope || this, e, this.menu);
35146 up : function(e, m){
35147 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35148 m.tryActivate(m.items.length-1, -1);
35152 down : function(e, m){
35153 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35154 m.tryActivate(0, 1);
35158 right : function(e, m){
35160 m.activeItem.expandMenu(true);
35164 left : function(e, m){
35166 if(m.parentMenu && m.parentMenu.activeItem){
35167 m.parentMenu.activeItem.activate();
35171 enter : function(e, m){
35173 e.stopPropagation();
35174 m.activeItem.onClick(e);
35175 m.fireEvent("click", this, m.activeItem);
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">
35191 * @class Roo.menu.MenuMgr
35192 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35195 Roo.menu.MenuMgr = function(){
35196 var menus, active, groups = {}, attached = false, lastShow = new Date();
35198 // private - called when first menu is created
35201 active = new Roo.util.MixedCollection();
35202 Roo.get(document).addKeyListener(27, function(){
35203 if(active.length > 0){
35210 function hideAll(){
35211 if(active && active.length > 0){
35212 var c = active.clone();
35213 c.each(function(m){
35220 function onHide(m){
35222 if(active.length < 1){
35223 Roo.get(document).un("mousedown", onMouseDown);
35229 function onShow(m){
35230 var last = active.last();
35231 lastShow = new Date();
35234 Roo.get(document).on("mousedown", onMouseDown);
35238 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35239 m.parentMenu.activeChild = m;
35240 }else if(last && last.isVisible()){
35241 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35246 function onBeforeHide(m){
35248 m.activeChild.hide();
35250 if(m.autoHideTimer){
35251 clearTimeout(m.autoHideTimer);
35252 delete m.autoHideTimer;
35257 function onBeforeShow(m){
35258 var pm = m.parentMenu;
35259 if(!pm && !m.allowOtherMenus){
35261 }else if(pm && pm.activeChild && active != m){
35262 pm.activeChild.hide();
35267 function onMouseDown(e){
35268 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35274 function onBeforeCheck(mi, state){
35276 var g = groups[mi.group];
35277 for(var i = 0, l = g.length; i < l; i++){
35279 g[i].setChecked(false);
35288 * Hides all menus that are currently visible
35290 hideAll : function(){
35295 register : function(menu){
35299 menus[menu.id] = menu;
35300 menu.on("beforehide", onBeforeHide);
35301 menu.on("hide", onHide);
35302 menu.on("beforeshow", onBeforeShow);
35303 menu.on("show", onShow);
35304 var g = menu.group;
35305 if(g && menu.events["checkchange"]){
35309 groups[g].push(menu);
35310 menu.on("checkchange", onCheck);
35315 * Returns a {@link Roo.menu.Menu} object
35316 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35317 * be used to generate and return a new Menu instance.
35319 get : function(menu){
35320 if(typeof menu == "string"){ // menu id
35321 return menus[menu];
35322 }else if(menu.events){ // menu instance
35324 }else if(typeof menu.length == 'number'){ // array of menu items?
35325 return new Roo.menu.Menu({items:menu});
35326 }else{ // otherwise, must be a config
35327 return new Roo.menu.Menu(menu);
35332 unregister : function(menu){
35333 delete menus[menu.id];
35334 menu.un("beforehide", onBeforeHide);
35335 menu.un("hide", onHide);
35336 menu.un("beforeshow", onBeforeShow);
35337 menu.un("show", onShow);
35338 var g = menu.group;
35339 if(g && menu.events["checkchange"]){
35340 groups[g].remove(menu);
35341 menu.un("checkchange", onCheck);
35346 registerCheckable : function(menuItem){
35347 var g = menuItem.group;
35352 groups[g].push(menuItem);
35353 menuItem.on("beforecheckchange", onBeforeCheck);
35358 unregisterCheckable : function(menuItem){
35359 var g = menuItem.group;
35361 groups[g].remove(menuItem);
35362 menuItem.un("beforecheckchange", onBeforeCheck);
35368 * Ext JS Library 1.1.1
35369 * Copyright(c) 2006-2007, Ext JS, LLC.
35371 * Originally Released Under LGPL - original licence link has changed is not relivant.
35374 * <script type="text/javascript">
35379 * @class Roo.menu.BaseItem
35380 * @extends Roo.Component
35381 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35382 * management and base configuration options shared by all menu components.
35384 * Creates a new BaseItem
35385 * @param {Object} config Configuration options
35387 Roo.menu.BaseItem = function(config){
35388 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35393 * Fires when this item is clicked
35394 * @param {Roo.menu.BaseItem} this
35395 * @param {Roo.EventObject} e
35400 * Fires when this item is activated
35401 * @param {Roo.menu.BaseItem} this
35405 * @event deactivate
35406 * Fires when this item is deactivated
35407 * @param {Roo.menu.BaseItem} this
35413 this.on("click", this.handler, this.scope, true);
35417 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35419 * @cfg {Function} handler
35420 * A function that will handle the click event of this menu item (defaults to undefined)
35423 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35425 canActivate : false,
35427 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35429 activeClass : "x-menu-item-active",
35431 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35433 hideOnClick : true,
35435 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35440 ctype: "Roo.menu.BaseItem",
35443 actionMode : "container",
35446 render : function(container, parentMenu){
35447 this.parentMenu = parentMenu;
35448 Roo.menu.BaseItem.superclass.render.call(this, container);
35449 this.container.menuItemId = this.id;
35453 onRender : function(container, position){
35454 this.el = Roo.get(this.el);
35455 container.dom.appendChild(this.el.dom);
35459 onClick : function(e){
35460 if(!this.disabled && this.fireEvent("click", this, e) !== false
35461 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35462 this.handleClick(e);
35469 activate : function(){
35473 var li = this.container;
35474 li.addClass(this.activeClass);
35475 this.region = li.getRegion().adjust(2, 2, -2, -2);
35476 this.fireEvent("activate", this);
35481 deactivate : function(){
35482 this.container.removeClass(this.activeClass);
35483 this.fireEvent("deactivate", this);
35487 shouldDeactivate : function(e){
35488 return !this.region || !this.region.contains(e.getPoint());
35492 handleClick : function(e){
35493 if(this.hideOnClick){
35494 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35499 expandMenu : function(autoActivate){
35504 hideMenu : function(){
35509 * Ext JS Library 1.1.1
35510 * Copyright(c) 2006-2007, Ext JS, LLC.
35512 * Originally Released Under LGPL - original licence link has changed is not relivant.
35515 * <script type="text/javascript">
35519 * @class Roo.menu.Adapter
35520 * @extends Roo.menu.BaseItem
35521 * 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.
35522 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35524 * Creates a new Adapter
35525 * @param {Object} config Configuration options
35527 Roo.menu.Adapter = function(component, config){
35528 Roo.menu.Adapter.superclass.constructor.call(this, config);
35529 this.component = component;
35531 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35533 canActivate : true,
35536 onRender : function(container, position){
35537 this.component.render(container);
35538 this.el = this.component.getEl();
35542 activate : function(){
35546 this.component.focus();
35547 this.fireEvent("activate", this);
35552 deactivate : function(){
35553 this.fireEvent("deactivate", this);
35557 disable : function(){
35558 this.component.disable();
35559 Roo.menu.Adapter.superclass.disable.call(this);
35563 enable : function(){
35564 this.component.enable();
35565 Roo.menu.Adapter.superclass.enable.call(this);
35569 * Ext JS Library 1.1.1
35570 * Copyright(c) 2006-2007, Ext JS, LLC.
35572 * Originally Released Under LGPL - original licence link has changed is not relivant.
35575 * <script type="text/javascript">
35579 * @class Roo.menu.TextItem
35580 * @extends Roo.menu.BaseItem
35581 * Adds a static text string to a menu, usually used as either a heading or group separator.
35582 * Note: old style constructor with text is still supported.
35585 * Creates a new TextItem
35586 * @param {Object} cfg Configuration
35588 Roo.menu.TextItem = function(cfg){
35589 if (typeof(cfg) == 'string') {
35592 Roo.apply(this,cfg);
35595 Roo.menu.TextItem.superclass.constructor.call(this);
35598 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35600 * @cfg {Boolean} text Text to show on item.
35605 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35607 hideOnClick : false,
35609 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35611 itemCls : "x-menu-text",
35614 onRender : function(){
35615 var s = document.createElement("span");
35616 s.className = this.itemCls;
35617 s.innerHTML = this.text;
35619 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35623 * Ext JS Library 1.1.1
35624 * Copyright(c) 2006-2007, Ext JS, LLC.
35626 * Originally Released Under LGPL - original licence link has changed is not relivant.
35629 * <script type="text/javascript">
35633 * @class Roo.menu.Separator
35634 * @extends Roo.menu.BaseItem
35635 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35636 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35638 * @param {Object} config Configuration options
35640 Roo.menu.Separator = function(config){
35641 Roo.menu.Separator.superclass.constructor.call(this, config);
35644 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35646 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35648 itemCls : "x-menu-sep",
35650 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35652 hideOnClick : false,
35655 onRender : function(li){
35656 var s = document.createElement("span");
35657 s.className = this.itemCls;
35658 s.innerHTML = " ";
35660 li.addClass("x-menu-sep-li");
35661 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35665 * Ext JS Library 1.1.1
35666 * Copyright(c) 2006-2007, Ext JS, LLC.
35668 * Originally Released Under LGPL - original licence link has changed is not relivant.
35671 * <script type="text/javascript">
35674 * @class Roo.menu.Item
35675 * @extends Roo.menu.BaseItem
35676 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35677 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35678 * activation and click handling.
35680 * Creates a new Item
35681 * @param {Object} config Configuration options
35683 Roo.menu.Item = function(config){
35684 Roo.menu.Item.superclass.constructor.call(this, config);
35686 this.menu = Roo.menu.MenuMgr.get(this.menu);
35689 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35692 * @cfg {String} text
35693 * The text to show on the menu item.
35697 * @cfg {String} HTML to render in menu
35698 * The text to show on the menu item (HTML version).
35702 * @cfg {String} icon
35703 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35707 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35709 itemCls : "x-menu-item",
35711 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35713 canActivate : true,
35715 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35718 // doc'd in BaseItem
35722 ctype: "Roo.menu.Item",
35725 onRender : function(container, position){
35726 var el = document.createElement("a");
35727 el.hideFocus = true;
35728 el.unselectable = "on";
35729 el.href = this.href || "#";
35730 if(this.hrefTarget){
35731 el.target = this.hrefTarget;
35733 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35735 var html = this.html.length ? this.html : String.format('{0}',this.text);
35737 el.innerHTML = String.format(
35738 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35739 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35741 Roo.menu.Item.superclass.onRender.call(this, container, position);
35745 * Sets the text to display in this menu item
35746 * @param {String} text The text to display
35747 * @param {Boolean} isHTML true to indicate text is pure html.
35749 setText : function(text, isHTML){
35757 var html = this.html.length ? this.html : String.format('{0}',this.text);
35759 this.el.update(String.format(
35760 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35761 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35762 this.parentMenu.autoWidth();
35767 handleClick : function(e){
35768 if(!this.href){ // if no link defined, stop the event automatically
35771 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35775 activate : function(autoExpand){
35776 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35786 shouldDeactivate : function(e){
35787 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35788 if(this.menu && this.menu.isVisible()){
35789 return !this.menu.getEl().getRegion().contains(e.getPoint());
35797 deactivate : function(){
35798 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35803 expandMenu : function(autoActivate){
35804 if(!this.disabled && this.menu){
35805 clearTimeout(this.hideTimer);
35806 delete this.hideTimer;
35807 if(!this.menu.isVisible() && !this.showTimer){
35808 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35809 }else if (this.menu.isVisible() && autoActivate){
35810 this.menu.tryActivate(0, 1);
35816 deferExpand : function(autoActivate){
35817 delete this.showTimer;
35818 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35820 this.menu.tryActivate(0, 1);
35825 hideMenu : function(){
35826 clearTimeout(this.showTimer);
35827 delete this.showTimer;
35828 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35829 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35834 deferHide : function(){
35835 delete this.hideTimer;
35840 * Ext JS Library 1.1.1
35841 * Copyright(c) 2006-2007, Ext JS, LLC.
35843 * Originally Released Under LGPL - original licence link has changed is not relivant.
35846 * <script type="text/javascript">
35850 * @class Roo.menu.CheckItem
35851 * @extends Roo.menu.Item
35852 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35854 * Creates a new CheckItem
35855 * @param {Object} config Configuration options
35857 Roo.menu.CheckItem = function(config){
35858 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35861 * @event beforecheckchange
35862 * Fires before the checked value is set, providing an opportunity to cancel if needed
35863 * @param {Roo.menu.CheckItem} this
35864 * @param {Boolean} checked The new checked value that will be set
35866 "beforecheckchange" : true,
35868 * @event checkchange
35869 * Fires after the checked value has been set
35870 * @param {Roo.menu.CheckItem} this
35871 * @param {Boolean} checked The checked value that was set
35873 "checkchange" : true
35875 if(this.checkHandler){
35876 this.on('checkchange', this.checkHandler, this.scope);
35879 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35881 * @cfg {String} group
35882 * All check items with the same group name will automatically be grouped into a single-select
35883 * radio button group (defaults to '')
35886 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35888 itemCls : "x-menu-item x-menu-check-item",
35890 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35892 groupClass : "x-menu-group-item",
35895 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35896 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35897 * initialized with checked = true will be rendered as checked.
35902 ctype: "Roo.menu.CheckItem",
35905 onRender : function(c){
35906 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35908 this.el.addClass(this.groupClass);
35910 Roo.menu.MenuMgr.registerCheckable(this);
35912 this.checked = false;
35913 this.setChecked(true, true);
35918 destroy : function(){
35920 Roo.menu.MenuMgr.unregisterCheckable(this);
35922 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35926 * Set the checked state of this item
35927 * @param {Boolean} checked The new checked value
35928 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35930 setChecked : function(state, suppressEvent){
35931 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35932 if(this.container){
35933 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35935 this.checked = state;
35936 if(suppressEvent !== true){
35937 this.fireEvent("checkchange", this, state);
35943 handleClick : function(e){
35944 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35945 this.setChecked(!this.checked);
35947 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35951 * Ext JS Library 1.1.1
35952 * Copyright(c) 2006-2007, Ext JS, LLC.
35954 * Originally Released Under LGPL - original licence link has changed is not relivant.
35957 * <script type="text/javascript">
35961 * @class Roo.menu.DateItem
35962 * @extends Roo.menu.Adapter
35963 * A menu item that wraps the {@link Roo.DatPicker} component.
35965 * Creates a new DateItem
35966 * @param {Object} config Configuration options
35968 Roo.menu.DateItem = function(config){
35969 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35970 /** The Roo.DatePicker object @type Roo.DatePicker */
35971 this.picker = this.component;
35972 this.addEvents({select: true});
35974 this.picker.on("render", function(picker){
35975 picker.getEl().swallowEvent("click");
35976 picker.container.addClass("x-menu-date-item");
35979 this.picker.on("select", this.onSelect, this);
35982 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35984 onSelect : function(picker, date){
35985 this.fireEvent("select", this, date, picker);
35986 Roo.menu.DateItem.superclass.handleClick.call(this);
35990 * Ext JS Library 1.1.1
35991 * Copyright(c) 2006-2007, Ext JS, LLC.
35993 * Originally Released Under LGPL - original licence link has changed is not relivant.
35996 * <script type="text/javascript">
36000 * @class Roo.menu.ColorItem
36001 * @extends Roo.menu.Adapter
36002 * A menu item that wraps the {@link Roo.ColorPalette} component.
36004 * Creates a new ColorItem
36005 * @param {Object} config Configuration options
36007 Roo.menu.ColorItem = function(config){
36008 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36009 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36010 this.palette = this.component;
36011 this.relayEvents(this.palette, ["select"]);
36012 if(this.selectHandler){
36013 this.on('select', this.selectHandler, this.scope);
36016 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36018 * Ext JS Library 1.1.1
36019 * Copyright(c) 2006-2007, Ext JS, LLC.
36021 * Originally Released Under LGPL - original licence link has changed is not relivant.
36024 * <script type="text/javascript">
36029 * @class Roo.menu.DateMenu
36030 * @extends Roo.menu.Menu
36031 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36033 * Creates a new DateMenu
36034 * @param {Object} config Configuration options
36036 Roo.menu.DateMenu = function(config){
36037 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36039 var di = new Roo.menu.DateItem(config);
36042 * The {@link Roo.DatePicker} instance for this DateMenu
36045 this.picker = di.picker;
36048 * @param {DatePicker} picker
36049 * @param {Date} date
36051 this.relayEvents(di, ["select"]);
36053 this.on('beforeshow', function(){
36055 this.picker.hideMonthPicker(true);
36059 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36063 * Ext JS Library 1.1.1
36064 * Copyright(c) 2006-2007, Ext JS, LLC.
36066 * Originally Released Under LGPL - original licence link has changed is not relivant.
36069 * <script type="text/javascript">
36074 * @class Roo.menu.ColorMenu
36075 * @extends Roo.menu.Menu
36076 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36078 * Creates a new ColorMenu
36079 * @param {Object} config Configuration options
36081 Roo.menu.ColorMenu = function(config){
36082 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36084 var ci = new Roo.menu.ColorItem(config);
36087 * The {@link Roo.ColorPalette} instance for this ColorMenu
36088 * @type ColorPalette
36090 this.palette = ci.palette;
36093 * @param {ColorPalette} palette
36094 * @param {String} color
36096 this.relayEvents(ci, ["select"]);
36098 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36100 * Ext JS Library 1.1.1
36101 * Copyright(c) 2006-2007, Ext JS, LLC.
36103 * Originally Released Under LGPL - original licence link has changed is not relivant.
36106 * <script type="text/javascript">
36110 * @class Roo.form.Field
36111 * @extends Roo.BoxComponent
36112 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36114 * Creates a new Field
36115 * @param {Object} config Configuration options
36117 Roo.form.Field = function(config){
36118 Roo.form.Field.superclass.constructor.call(this, config);
36121 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36123 * @cfg {String} fieldLabel Label to use when rendering a form.
36126 * @cfg {String} qtip Mouse over tip
36130 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36132 invalidClass : "x-form-invalid",
36134 * @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")
36136 invalidText : "The value in this field is invalid",
36138 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36140 focusClass : "x-form-focus",
36142 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36143 automatic validation (defaults to "keyup").
36145 validationEvent : "keyup",
36147 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36149 validateOnBlur : true,
36151 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36153 validationDelay : 250,
36155 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36156 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36158 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36160 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36162 fieldClass : "x-form-field",
36164 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36167 ----------- ----------------------------------------------------------------------
36168 qtip Display a quick tip when the user hovers over the field
36169 title Display a default browser title attribute popup
36170 under Add a block div beneath the field containing the error text
36171 side Add an error icon to the right of the field with a popup on hover
36172 [element id] Add the error text directly to the innerHTML of the specified element
36175 msgTarget : 'qtip',
36177 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36182 * @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.
36187 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36192 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36194 inputType : undefined,
36197 * @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).
36199 tabIndex : undefined,
36202 isFormField : true,
36207 * @property {Roo.Element} fieldEl
36208 * Element Containing the rendered Field (with label etc.)
36211 * @cfg {Mixed} value A value to initialize this field with.
36216 * @cfg {String} name The field's HTML name attribute.
36219 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36223 initComponent : function(){
36224 Roo.form.Field.superclass.initComponent.call(this);
36228 * Fires when this field receives input focus.
36229 * @param {Roo.form.Field} this
36234 * Fires when this field loses input focus.
36235 * @param {Roo.form.Field} this
36239 * @event specialkey
36240 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36241 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36242 * @param {Roo.form.Field} this
36243 * @param {Roo.EventObject} e The event object
36248 * Fires just before the field blurs if the field value has changed.
36249 * @param {Roo.form.Field} this
36250 * @param {Mixed} newValue The new value
36251 * @param {Mixed} oldValue The original value
36256 * Fires after the field has been marked as invalid.
36257 * @param {Roo.form.Field} this
36258 * @param {String} msg The validation message
36263 * Fires after the field has been validated with no errors.
36264 * @param {Roo.form.Field} this
36269 * Fires after the key up
36270 * @param {Roo.form.Field} this
36271 * @param {Roo.EventObject} e The event Object
36278 * Returns the name attribute of the field if available
36279 * @return {String} name The field name
36281 getName: function(){
36282 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36286 onRender : function(ct, position){
36287 Roo.form.Field.superclass.onRender.call(this, ct, position);
36289 var cfg = this.getAutoCreate();
36291 cfg.name = this.name || this.id;
36293 if(this.inputType){
36294 cfg.type = this.inputType;
36296 this.el = ct.createChild(cfg, position);
36298 var type = this.el.dom.type;
36300 if(type == 'password'){
36303 this.el.addClass('x-form-'+type);
36306 this.el.dom.readOnly = true;
36308 if(this.tabIndex !== undefined){
36309 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36312 this.el.addClass([this.fieldClass, this.cls]);
36317 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36318 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36319 * @return {Roo.form.Field} this
36321 applyTo : function(target){
36322 this.allowDomMove = false;
36323 this.el = Roo.get(target);
36324 this.render(this.el.dom.parentNode);
36329 initValue : function(){
36330 if(this.value !== undefined){
36331 this.setValue(this.value);
36332 }else if(this.el.dom.value.length > 0){
36333 this.setValue(this.el.dom.value);
36338 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36340 isDirty : function() {
36341 if(this.disabled) {
36344 return String(this.getValue()) !== String(this.originalValue);
36348 afterRender : function(){
36349 Roo.form.Field.superclass.afterRender.call(this);
36354 fireKey : function(e){
36355 //Roo.log('field ' + e.getKey());
36356 if(e.isNavKeyPress()){
36357 this.fireEvent("specialkey", this, e);
36362 * Resets the current field value to the originally loaded value and clears any validation messages
36364 reset : function(){
36365 this.setValue(this.originalValue);
36366 this.clearInvalid();
36370 initEvents : function(){
36371 // safari killled keypress - so keydown is now used..
36372 this.el.on("keydown" , this.fireKey, this);
36373 this.el.on("focus", this.onFocus, this);
36374 this.el.on("blur", this.onBlur, this);
36375 this.el.relayEvent('keyup', this);
36377 // reference to original value for reset
36378 this.originalValue = this.getValue();
36382 onFocus : function(){
36383 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36384 this.el.addClass(this.focusClass);
36386 if(!this.hasFocus){
36387 this.hasFocus = true;
36388 this.startValue = this.getValue();
36389 this.fireEvent("focus", this);
36393 beforeBlur : Roo.emptyFn,
36396 onBlur : function(){
36398 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36399 this.el.removeClass(this.focusClass);
36401 this.hasFocus = false;
36402 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36405 var v = this.getValue();
36406 if(String(v) !== String(this.startValue)){
36407 this.fireEvent('change', this, v, this.startValue);
36409 this.fireEvent("blur", this);
36413 * Returns whether or not the field value is currently valid
36414 * @param {Boolean} preventMark True to disable marking the field invalid
36415 * @return {Boolean} True if the value is valid, else false
36417 isValid : function(preventMark){
36421 var restore = this.preventMark;
36422 this.preventMark = preventMark === true;
36423 var v = this.validateValue(this.processValue(this.getRawValue()));
36424 this.preventMark = restore;
36429 * Validates the field value
36430 * @return {Boolean} True if the value is valid, else false
36432 validate : function(){
36433 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36434 this.clearInvalid();
36440 processValue : function(value){
36445 // Subclasses should provide the validation implementation by overriding this
36446 validateValue : function(value){
36451 * Mark this field as invalid
36452 * @param {String} msg The validation message
36454 markInvalid : function(msg){
36455 if(!this.rendered || this.preventMark){ // not rendered
36458 this.el.addClass(this.invalidClass);
36459 msg = msg || this.invalidText;
36460 switch(this.msgTarget){
36462 this.el.dom.qtip = msg;
36463 this.el.dom.qclass = 'x-form-invalid-tip';
36464 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36465 Roo.QuickTips.enable();
36469 this.el.dom.title = msg;
36473 var elp = this.el.findParent('.x-form-element', 5, true);
36474 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36475 this.errorEl.setWidth(elp.getWidth(true)-20);
36477 this.errorEl.update(msg);
36478 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36481 if(!this.errorIcon){
36482 var elp = this.el.findParent('.x-form-element', 5, true);
36483 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36485 this.alignErrorIcon();
36486 this.errorIcon.dom.qtip = msg;
36487 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36488 this.errorIcon.show();
36489 this.on('resize', this.alignErrorIcon, this);
36492 var t = Roo.getDom(this.msgTarget);
36494 t.style.display = this.msgDisplay;
36497 this.fireEvent('invalid', this, msg);
36501 alignErrorIcon : function(){
36502 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36506 * Clear any invalid styles/messages for this field
36508 clearInvalid : function(){
36509 if(!this.rendered || this.preventMark){ // not rendered
36512 this.el.removeClass(this.invalidClass);
36513 switch(this.msgTarget){
36515 this.el.dom.qtip = '';
36518 this.el.dom.title = '';
36522 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36526 if(this.errorIcon){
36527 this.errorIcon.dom.qtip = '';
36528 this.errorIcon.hide();
36529 this.un('resize', this.alignErrorIcon, this);
36533 var t = Roo.getDom(this.msgTarget);
36535 t.style.display = 'none';
36538 this.fireEvent('valid', this);
36542 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36543 * @return {Mixed} value The field value
36545 getRawValue : function(){
36546 var v = this.el.getValue();
36547 if(v === this.emptyText){
36554 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36555 * @return {Mixed} value The field value
36557 getValue : function(){
36558 var v = this.el.getValue();
36559 if(v === this.emptyText || v === undefined){
36566 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36567 * @param {Mixed} value The value to set
36569 setRawValue : function(v){
36570 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36574 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36575 * @param {Mixed} value The value to set
36577 setValue : function(v){
36580 this.el.dom.value = (v === null || v === undefined ? '' : v);
36585 adjustSize : function(w, h){
36586 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36587 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36591 adjustWidth : function(tag, w){
36592 tag = tag.toLowerCase();
36593 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36594 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36595 if(tag == 'input'){
36598 if(tag = 'textarea'){
36601 }else if(Roo.isOpera){
36602 if(tag == 'input'){
36605 if(tag = 'textarea'){
36615 // anything other than normal should be considered experimental
36616 Roo.form.Field.msgFx = {
36618 show: function(msgEl, f){
36619 msgEl.setDisplayed('block');
36622 hide : function(msgEl, f){
36623 msgEl.setDisplayed(false).update('');
36628 show: function(msgEl, f){
36629 msgEl.slideIn('t', {stopFx:true});
36632 hide : function(msgEl, f){
36633 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36638 show: function(msgEl, f){
36639 msgEl.fixDisplay();
36640 msgEl.alignTo(f.el, 'tl-tr');
36641 msgEl.slideIn('l', {stopFx:true});
36644 hide : function(msgEl, f){
36645 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36650 * Ext JS Library 1.1.1
36651 * Copyright(c) 2006-2007, Ext JS, LLC.
36653 * Originally Released Under LGPL - original licence link has changed is not relivant.
36656 * <script type="text/javascript">
36661 * @class Roo.form.TextField
36662 * @extends Roo.form.Field
36663 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36664 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36666 * Creates a new TextField
36667 * @param {Object} config Configuration options
36669 Roo.form.TextField = function(config){
36670 Roo.form.TextField.superclass.constructor.call(this, config);
36674 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36675 * according to the default logic, but this event provides a hook for the developer to apply additional
36676 * logic at runtime to resize the field if needed.
36677 * @param {Roo.form.Field} this This text field
36678 * @param {Number} width The new field width
36684 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36686 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36690 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36694 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36698 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36702 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36706 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36708 disableKeyFilter : false,
36710 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36714 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36718 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36720 maxLength : Number.MAX_VALUE,
36722 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36724 minLengthText : "The minimum length for this field is {0}",
36726 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36728 maxLengthText : "The maximum length for this field is {0}",
36730 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36732 selectOnFocus : false,
36734 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36736 blankText : "This field is required",
36738 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36739 * If available, this function will be called only after the basic validators all return true, and will be passed the
36740 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36744 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36745 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36746 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36750 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36754 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36758 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36759 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36761 emptyClass : 'x-form-empty-field',
36764 initEvents : function(){
36765 Roo.form.TextField.superclass.initEvents.call(this);
36766 if(this.validationEvent == 'keyup'){
36767 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36768 this.el.on('keyup', this.filterValidation, this);
36770 else if(this.validationEvent !== false){
36771 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36773 if(this.selectOnFocus || this.emptyText){
36774 this.on("focus", this.preFocus, this);
36775 if(this.emptyText){
36776 this.on('blur', this.postBlur, this);
36777 this.applyEmptyText();
36780 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36781 this.el.on("keypress", this.filterKeys, this);
36784 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36785 this.el.on("click", this.autoSize, this);
36789 processValue : function(value){
36790 if(this.stripCharsRe){
36791 var newValue = value.replace(this.stripCharsRe, '');
36792 if(newValue !== value){
36793 this.setRawValue(newValue);
36800 filterValidation : function(e){
36801 if(!e.isNavKeyPress()){
36802 this.validationTask.delay(this.validationDelay);
36807 onKeyUp : function(e){
36808 if(!e.isNavKeyPress()){
36814 * Resets the current field value to the originally-loaded value and clears any validation messages.
36815 * Also adds emptyText and emptyClass if the original value was blank.
36817 reset : function(){
36818 Roo.form.TextField.superclass.reset.call(this);
36819 this.applyEmptyText();
36822 applyEmptyText : function(){
36823 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36824 this.setRawValue(this.emptyText);
36825 this.el.addClass(this.emptyClass);
36830 preFocus : function(){
36831 if(this.emptyText){
36832 if(this.el.dom.value == this.emptyText){
36833 this.setRawValue('');
36835 this.el.removeClass(this.emptyClass);
36837 if(this.selectOnFocus){
36838 this.el.dom.select();
36843 postBlur : function(){
36844 this.applyEmptyText();
36848 filterKeys : function(e){
36849 var k = e.getKey();
36850 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36853 var c = e.getCharCode(), cc = String.fromCharCode(c);
36854 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36857 if(!this.maskRe.test(cc)){
36862 setValue : function(v){
36863 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36864 this.el.removeClass(this.emptyClass);
36866 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36867 this.applyEmptyText();
36872 * Validates a value according to the field's validation rules and marks the field as invalid
36873 * if the validation fails
36874 * @param {Mixed} value The value to validate
36875 * @return {Boolean} True if the value is valid, else false
36877 validateValue : function(value){
36878 if(value.length < 1 || value === this.emptyText){ // if it's blank
36879 if(this.allowBlank){
36880 this.clearInvalid();
36883 this.markInvalid(this.blankText);
36887 if(value.length < this.minLength){
36888 this.markInvalid(String.format(this.minLengthText, this.minLength));
36891 if(value.length > this.maxLength){
36892 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36896 var vt = Roo.form.VTypes;
36897 if(!vt[this.vtype](value, this)){
36898 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36902 if(typeof this.validator == "function"){
36903 var msg = this.validator(value);
36905 this.markInvalid(msg);
36909 if(this.regex && !this.regex.test(value)){
36910 this.markInvalid(this.regexText);
36917 * Selects text in this field
36918 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36919 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36921 selectText : function(start, end){
36922 var v = this.getRawValue();
36924 start = start === undefined ? 0 : start;
36925 end = end === undefined ? v.length : end;
36926 var d = this.el.dom;
36927 if(d.setSelectionRange){
36928 d.setSelectionRange(start, end);
36929 }else if(d.createTextRange){
36930 var range = d.createTextRange();
36931 range.moveStart("character", start);
36932 range.moveEnd("character", v.length-end);
36939 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36940 * This only takes effect if grow = true, and fires the autosize event.
36942 autoSize : function(){
36943 if(!this.grow || !this.rendered){
36947 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36950 var v = el.dom.value;
36951 var d = document.createElement('div');
36952 d.appendChild(document.createTextNode(v));
36956 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36957 this.el.setWidth(w);
36958 this.fireEvent("autosize", this, w);
36962 * Ext JS Library 1.1.1
36963 * Copyright(c) 2006-2007, Ext JS, LLC.
36965 * Originally Released Under LGPL - original licence link has changed is not relivant.
36968 * <script type="text/javascript">
36972 * @class Roo.form.Hidden
36973 * @extends Roo.form.TextField
36974 * Simple Hidden element used on forms
36976 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36979 * Creates a new Hidden form element.
36980 * @param {Object} config Configuration options
36985 // easy hidden field...
36986 Roo.form.Hidden = function(config){
36987 Roo.form.Hidden.superclass.constructor.call(this, config);
36990 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36992 inputType: 'hidden',
36995 labelSeparator: '',
36997 itemCls : 'x-form-item-display-none'
37005 * Ext JS Library 1.1.1
37006 * Copyright(c) 2006-2007, Ext JS, LLC.
37008 * Originally Released Under LGPL - original licence link has changed is not relivant.
37011 * <script type="text/javascript">
37015 * @class Roo.form.TriggerField
37016 * @extends Roo.form.TextField
37017 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37018 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37019 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37020 * for which you can provide a custom implementation. For example:
37022 var trigger = new Roo.form.TriggerField();
37023 trigger.onTriggerClick = myTriggerFn;
37024 trigger.applyTo('my-field');
37027 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37028 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37029 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37030 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37032 * Create a new TriggerField.
37033 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37034 * to the base TextField)
37036 Roo.form.TriggerField = function(config){
37037 this.mimicing = false;
37038 Roo.form.TriggerField.superclass.constructor.call(this, config);
37041 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37043 * @cfg {String} triggerClass A CSS class to apply to the trigger
37046 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37047 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37049 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37051 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37055 /** @cfg {Boolean} grow @hide */
37056 /** @cfg {Number} growMin @hide */
37057 /** @cfg {Number} growMax @hide */
37063 autoSize: Roo.emptyFn,
37067 deferHeight : true,
37070 actionMode : 'wrap',
37072 onResize : function(w, h){
37073 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37074 if(typeof w == 'number'){
37075 var x = w - this.trigger.getWidth();
37076 this.el.setWidth(this.adjustWidth('input', x));
37077 this.trigger.setStyle('left', x+'px');
37082 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37085 getResizeEl : function(){
37090 getPositionEl : function(){
37095 alignErrorIcon : function(){
37096 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37100 onRender : function(ct, position){
37101 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37102 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37103 this.trigger = this.wrap.createChild(this.triggerConfig ||
37104 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37105 if(this.hideTrigger){
37106 this.trigger.setDisplayed(false);
37108 this.initTrigger();
37110 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37115 initTrigger : function(){
37116 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37117 this.trigger.addClassOnOver('x-form-trigger-over');
37118 this.trigger.addClassOnClick('x-form-trigger-click');
37122 onDestroy : function(){
37124 this.trigger.removeAllListeners();
37125 this.trigger.remove();
37128 this.wrap.remove();
37130 Roo.form.TriggerField.superclass.onDestroy.call(this);
37134 onFocus : function(){
37135 Roo.form.TriggerField.superclass.onFocus.call(this);
37136 if(!this.mimicing){
37137 this.wrap.addClass('x-trigger-wrap-focus');
37138 this.mimicing = true;
37139 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37140 if(this.monitorTab){
37141 this.el.on("keydown", this.checkTab, this);
37147 checkTab : function(e){
37148 if(e.getKey() == e.TAB){
37149 this.triggerBlur();
37154 onBlur : function(){
37159 mimicBlur : function(e, t){
37160 if(!this.wrap.contains(t) && this.validateBlur()){
37161 this.triggerBlur();
37166 triggerBlur : function(){
37167 this.mimicing = false;
37168 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37169 if(this.monitorTab){
37170 this.el.un("keydown", this.checkTab, this);
37172 this.wrap.removeClass('x-trigger-wrap-focus');
37173 Roo.form.TriggerField.superclass.onBlur.call(this);
37177 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37178 validateBlur : function(e, t){
37183 onDisable : function(){
37184 Roo.form.TriggerField.superclass.onDisable.call(this);
37186 this.wrap.addClass('x-item-disabled');
37191 onEnable : function(){
37192 Roo.form.TriggerField.superclass.onEnable.call(this);
37194 this.wrap.removeClass('x-item-disabled');
37199 onShow : function(){
37200 var ae = this.getActionEl();
37203 ae.dom.style.display = '';
37204 ae.dom.style.visibility = 'visible';
37210 onHide : function(){
37211 var ae = this.getActionEl();
37212 ae.dom.style.display = 'none';
37216 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37217 * by an implementing function.
37219 * @param {EventObject} e
37221 onTriggerClick : Roo.emptyFn
37224 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37225 // to be extended by an implementing class. For an example of implementing this class, see the custom
37226 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37227 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37228 initComponent : function(){
37229 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37231 this.triggerConfig = {
37232 tag:'span', cls:'x-form-twin-triggers', cn:[
37233 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37234 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37238 getTrigger : function(index){
37239 return this.triggers[index];
37242 initTrigger : function(){
37243 var ts = this.trigger.select('.x-form-trigger', true);
37244 this.wrap.setStyle('overflow', 'hidden');
37245 var triggerField = this;
37246 ts.each(function(t, all, index){
37247 t.hide = function(){
37248 var w = triggerField.wrap.getWidth();
37249 this.dom.style.display = 'none';
37250 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37252 t.show = function(){
37253 var w = triggerField.wrap.getWidth();
37254 this.dom.style.display = '';
37255 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37257 var triggerIndex = 'Trigger'+(index+1);
37259 if(this['hide'+triggerIndex]){
37260 t.dom.style.display = 'none';
37262 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37263 t.addClassOnOver('x-form-trigger-over');
37264 t.addClassOnClick('x-form-trigger-click');
37266 this.triggers = ts.elements;
37269 onTrigger1Click : Roo.emptyFn,
37270 onTrigger2Click : Roo.emptyFn
37273 * Ext JS Library 1.1.1
37274 * Copyright(c) 2006-2007, Ext JS, LLC.
37276 * Originally Released Under LGPL - original licence link has changed is not relivant.
37279 * <script type="text/javascript">
37283 * @class Roo.form.TextArea
37284 * @extends Roo.form.TextField
37285 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37286 * support for auto-sizing.
37288 * Creates a new TextArea
37289 * @param {Object} config Configuration options
37291 Roo.form.TextArea = function(config){
37292 Roo.form.TextArea.superclass.constructor.call(this, config);
37293 // these are provided exchanges for backwards compat
37294 // minHeight/maxHeight were replaced by growMin/growMax to be
37295 // compatible with TextField growing config values
37296 if(this.minHeight !== undefined){
37297 this.growMin = this.minHeight;
37299 if(this.maxHeight !== undefined){
37300 this.growMax = this.maxHeight;
37304 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37306 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37310 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37314 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37315 * in the field (equivalent to setting overflow: hidden, defaults to false)
37317 preventScrollbars: false,
37319 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37320 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37324 onRender : function(ct, position){
37326 this.defaultAutoCreate = {
37328 style:"width:300px;height:60px;",
37329 autocomplete: "off"
37332 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37334 this.textSizeEl = Roo.DomHelper.append(document.body, {
37335 tag: "pre", cls: "x-form-grow-sizer"
37337 if(this.preventScrollbars){
37338 this.el.setStyle("overflow", "hidden");
37340 this.el.setHeight(this.growMin);
37344 onDestroy : function(){
37345 if(this.textSizeEl){
37346 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37348 Roo.form.TextArea.superclass.onDestroy.call(this);
37352 onKeyUp : function(e){
37353 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37359 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37360 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37362 autoSize : function(){
37363 if(!this.grow || !this.textSizeEl){
37367 var v = el.dom.value;
37368 var ts = this.textSizeEl;
37371 ts.appendChild(document.createTextNode(v));
37374 Roo.fly(ts).setWidth(this.el.getWidth());
37376 v = "  ";
37379 v = v.replace(/\n/g, '<p> </p>');
37381 v += " \n ";
37384 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37385 if(h != this.lastHeight){
37386 this.lastHeight = h;
37387 this.el.setHeight(h);
37388 this.fireEvent("autosize", this, h);
37393 * Ext JS Library 1.1.1
37394 * Copyright(c) 2006-2007, Ext JS, LLC.
37396 * Originally Released Under LGPL - original licence link has changed is not relivant.
37399 * <script type="text/javascript">
37404 * @class Roo.form.NumberField
37405 * @extends Roo.form.TextField
37406 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37408 * Creates a new NumberField
37409 * @param {Object} config Configuration options
37411 Roo.form.NumberField = function(config){
37412 Roo.form.NumberField.superclass.constructor.call(this, config);
37415 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37417 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37419 fieldClass: "x-form-field x-form-num-field",
37421 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37423 allowDecimals : true,
37425 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37427 decimalSeparator : ".",
37429 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37431 decimalPrecision : 2,
37433 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37435 allowNegative : true,
37437 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37439 minValue : Number.NEGATIVE_INFINITY,
37441 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37443 maxValue : Number.MAX_VALUE,
37445 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37447 minText : "The minimum value for this field is {0}",
37449 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37451 maxText : "The maximum value for this field is {0}",
37453 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37454 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37456 nanText : "{0} is not a valid number",
37459 initEvents : function(){
37460 Roo.form.NumberField.superclass.initEvents.call(this);
37461 var allowed = "0123456789";
37462 if(this.allowDecimals){
37463 allowed += this.decimalSeparator;
37465 if(this.allowNegative){
37468 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37469 var keyPress = function(e){
37470 var k = e.getKey();
37471 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37474 var c = e.getCharCode();
37475 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37479 this.el.on("keypress", keyPress, this);
37483 validateValue : function(value){
37484 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37487 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37490 var num = this.parseValue(value);
37492 this.markInvalid(String.format(this.nanText, value));
37495 if(num < this.minValue){
37496 this.markInvalid(String.format(this.minText, this.minValue));
37499 if(num > this.maxValue){
37500 this.markInvalid(String.format(this.maxText, this.maxValue));
37506 getValue : function(){
37507 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37511 parseValue : function(value){
37512 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37513 return isNaN(value) ? '' : value;
37517 fixPrecision : function(value){
37518 var nan = isNaN(value);
37519 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37520 return nan ? '' : value;
37522 return parseFloat(value).toFixed(this.decimalPrecision);
37525 setValue : function(v){
37526 v = this.fixPrecision(v);
37527 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37531 decimalPrecisionFcn : function(v){
37532 return Math.floor(v);
37535 beforeBlur : function(){
37536 var v = this.parseValue(this.getRawValue());
37543 * Ext JS Library 1.1.1
37544 * Copyright(c) 2006-2007, Ext JS, LLC.
37546 * Originally Released Under LGPL - original licence link has changed is not relivant.
37549 * <script type="text/javascript">
37553 * @class Roo.form.DateField
37554 * @extends Roo.form.TriggerField
37555 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37557 * Create a new DateField
37558 * @param {Object} config
37560 Roo.form.DateField = function(config){
37561 Roo.form.DateField.superclass.constructor.call(this, config);
37567 * Fires when a date is selected
37568 * @param {Roo.form.DateField} combo This combo box
37569 * @param {Date} date The date selected
37576 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37577 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37578 this.ddMatch = null;
37579 if(this.disabledDates){
37580 var dd = this.disabledDates;
37582 for(var i = 0; i < dd.length; i++){
37584 if(i != dd.length-1) re += "|";
37586 this.ddMatch = new RegExp(re + ")");
37590 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37592 * @cfg {String} format
37593 * The default date format string which can be overriden for localization support. The format must be
37594 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37598 * @cfg {String} altFormats
37599 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37600 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37602 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37604 * @cfg {Array} disabledDays
37605 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37607 disabledDays : null,
37609 * @cfg {String} disabledDaysText
37610 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37612 disabledDaysText : "Disabled",
37614 * @cfg {Array} disabledDates
37615 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37616 * expression so they are very powerful. Some examples:
37618 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37619 * <li>["03/08", "09/16"] would disable those days for every year</li>
37620 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37621 * <li>["03/../2006"] would disable every day in March 2006</li>
37622 * <li>["^03"] would disable every day in every March</li>
37624 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37625 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37627 disabledDates : null,
37629 * @cfg {String} disabledDatesText
37630 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37632 disabledDatesText : "Disabled",
37634 * @cfg {Date/String} minValue
37635 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37636 * valid format (defaults to null).
37640 * @cfg {Date/String} maxValue
37641 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37642 * valid format (defaults to null).
37646 * @cfg {String} minText
37647 * The error text to display when the date in the cell is before minValue (defaults to
37648 * 'The date in this field must be after {minValue}').
37650 minText : "The date in this field must be equal to or after {0}",
37652 * @cfg {String} maxText
37653 * The error text to display when the date in the cell is after maxValue (defaults to
37654 * 'The date in this field must be before {maxValue}').
37656 maxText : "The date in this field must be equal to or before {0}",
37658 * @cfg {String} invalidText
37659 * The error text to display when the date in the field is invalid (defaults to
37660 * '{value} is not a valid date - it must be in the format {format}').
37662 invalidText : "{0} is not a valid date - it must be in the format {1}",
37664 * @cfg {String} triggerClass
37665 * An additional CSS class used to style the trigger button. The trigger will always get the
37666 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37667 * which displays a calendar icon).
37669 triggerClass : 'x-form-date-trigger',
37673 * @cfg {Boolean} useIso
37674 * if enabled, then the date field will use a hidden field to store the
37675 * real value as iso formated date. default (false)
37679 * @cfg {String/Object} autoCreate
37680 * A DomHelper element spec, or true for a default element spec (defaults to
37681 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37684 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37687 hiddenField: false,
37689 onRender : function(ct, position)
37691 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37693 this.el.dom.removeAttribute('name');
37694 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37696 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37697 // prevent input submission
37698 this.hiddenName = this.name;
37705 validateValue : function(value)
37707 value = this.formatDate(value);
37708 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37711 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37714 var svalue = value;
37715 value = this.parseDate(value);
37717 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37720 var time = value.getTime();
37721 if(this.minValue && time < this.minValue.getTime()){
37722 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37725 if(this.maxValue && time > this.maxValue.getTime()){
37726 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37729 if(this.disabledDays){
37730 var day = value.getDay();
37731 for(var i = 0; i < this.disabledDays.length; i++) {
37732 if(day === this.disabledDays[i]){
37733 this.markInvalid(this.disabledDaysText);
37738 var fvalue = this.formatDate(value);
37739 if(this.ddMatch && this.ddMatch.test(fvalue)){
37740 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37747 // Provides logic to override the default TriggerField.validateBlur which just returns true
37748 validateBlur : function(){
37749 return !this.menu || !this.menu.isVisible();
37753 * Returns the current date value of the date field.
37754 * @return {Date} The date value
37756 getValue : function(){
37758 return this.hiddenField ?
37759 this.hiddenField.value :
37760 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37764 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37765 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37766 * (the default format used is "m/d/y").
37769 //All of these calls set the same date value (May 4, 2006)
37771 //Pass a date object:
37772 var dt = new Date('5/4/06');
37773 dateField.setValue(dt);
37775 //Pass a date string (default format):
37776 dateField.setValue('5/4/06');
37778 //Pass a date string (custom format):
37779 dateField.format = 'Y-m-d';
37780 dateField.setValue('2006-5-4');
37782 * @param {String/Date} date The date or valid date string
37784 setValue : function(date){
37785 if (this.hiddenField) {
37786 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37788 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37792 parseDate : function(value){
37793 if(!value || value instanceof Date){
37796 var v = Date.parseDate(value, this.format);
37797 if(!v && this.altFormats){
37798 if(!this.altFormatsArray){
37799 this.altFormatsArray = this.altFormats.split("|");
37801 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37802 v = Date.parseDate(value, this.altFormatsArray[i]);
37809 formatDate : function(date, fmt){
37810 return (!date || !(date instanceof Date)) ?
37811 date : date.dateFormat(fmt || this.format);
37816 select: function(m, d){
37818 this.fireEvent('select', this, d);
37820 show : function(){ // retain focus styling
37824 this.focus.defer(10, this);
37825 var ml = this.menuListeners;
37826 this.menu.un("select", ml.select, this);
37827 this.menu.un("show", ml.show, this);
37828 this.menu.un("hide", ml.hide, this);
37833 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37834 onTriggerClick : function(){
37838 if(this.menu == null){
37839 this.menu = new Roo.menu.DateMenu();
37841 Roo.apply(this.menu.picker, {
37842 showClear: this.allowBlank,
37843 minDate : this.minValue,
37844 maxDate : this.maxValue,
37845 disabledDatesRE : this.ddMatch,
37846 disabledDatesText : this.disabledDatesText,
37847 disabledDays : this.disabledDays,
37848 disabledDaysText : this.disabledDaysText,
37849 format : this.format,
37850 minText : String.format(this.minText, this.formatDate(this.minValue)),
37851 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37853 this.menu.on(Roo.apply({}, this.menuListeners, {
37856 this.menu.picker.setValue(this.getValue() || new Date());
37857 this.menu.show(this.el, "tl-bl?");
37860 beforeBlur : function(){
37861 var v = this.parseDate(this.getRawValue());
37867 /** @cfg {Boolean} grow @hide */
37868 /** @cfg {Number} growMin @hide */
37869 /** @cfg {Number} growMax @hide */
37876 * Ext JS Library 1.1.1
37877 * Copyright(c) 2006-2007, Ext JS, LLC.
37879 * Originally Released Under LGPL - original licence link has changed is not relivant.
37882 * <script type="text/javascript">
37887 * @class Roo.form.ComboBox
37888 * @extends Roo.form.TriggerField
37889 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37891 * Create a new ComboBox.
37892 * @param {Object} config Configuration options
37894 Roo.form.ComboBox = function(config){
37895 Roo.form.ComboBox.superclass.constructor.call(this, config);
37899 * Fires when the dropdown list is expanded
37900 * @param {Roo.form.ComboBox} combo This combo box
37905 * Fires when the dropdown list is collapsed
37906 * @param {Roo.form.ComboBox} combo This combo box
37910 * @event beforeselect
37911 * Fires before a list item is selected. Return false to cancel the selection.
37912 * @param {Roo.form.ComboBox} combo This combo box
37913 * @param {Roo.data.Record} record The data record returned from the underlying store
37914 * @param {Number} index The index of the selected item in the dropdown list
37916 'beforeselect' : true,
37919 * Fires when a list item is selected
37920 * @param {Roo.form.ComboBox} combo This combo box
37921 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37922 * @param {Number} index The index of the selected item in the dropdown list
37926 * @event beforequery
37927 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37928 * The event object passed has these properties:
37929 * @param {Roo.form.ComboBox} combo This combo box
37930 * @param {String} query The query
37931 * @param {Boolean} forceAll true to force "all" query
37932 * @param {Boolean} cancel true to cancel the query
37933 * @param {Object} e The query event object
37935 'beforequery': true,
37938 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37939 * @param {Roo.form.ComboBox} combo This combo box
37944 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37945 * @param {Roo.form.ComboBox} combo This combo box
37946 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37952 if(this.transform){
37953 this.allowDomMove = false;
37954 var s = Roo.getDom(this.transform);
37955 if(!this.hiddenName){
37956 this.hiddenName = s.name;
37959 this.mode = 'local';
37960 var d = [], opts = s.options;
37961 for(var i = 0, len = opts.length;i < len; i++){
37963 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37965 this.value = value;
37967 d.push([value, o.text]);
37969 this.store = new Roo.data.SimpleStore({
37971 fields: ['value', 'text'],
37974 this.valueField = 'value';
37975 this.displayField = 'text';
37977 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37978 if(!this.lazyRender){
37979 this.target = true;
37980 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37981 s.parentNode.removeChild(s); // remove it
37982 this.render(this.el.parentNode);
37984 s.parentNode.removeChild(s); // remove it
37989 this.store = Roo.factory(this.store, Roo.data);
37992 this.selectedIndex = -1;
37993 if(this.mode == 'local'){
37994 if(config.queryDelay === undefined){
37995 this.queryDelay = 10;
37997 if(config.minChars === undefined){
38003 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38005 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38008 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38009 * rendering into an Roo.Editor, defaults to false)
38012 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38013 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38016 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38019 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38020 * the dropdown list (defaults to undefined, with no header element)
38024 * @cfg {String/Roo.Template} tpl The template to use to render the output
38028 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38030 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38032 listWidth: undefined,
38034 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38035 * mode = 'remote' or 'text' if mode = 'local')
38037 displayField: undefined,
38039 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38040 * mode = 'remote' or 'value' if mode = 'local').
38041 * Note: use of a valueField requires the user make a selection
38042 * in order for a value to be mapped.
38044 valueField: undefined,
38048 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38049 * field's data value (defaults to the underlying DOM element's name)
38051 hiddenName: undefined,
38053 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38057 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38059 selectedClass: 'x-combo-selected',
38061 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38062 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38063 * which displays a downward arrow icon).
38065 triggerClass : 'x-form-arrow-trigger',
38067 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38071 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38072 * anchor positions (defaults to 'tl-bl')
38074 listAlign: 'tl-bl?',
38076 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38080 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38081 * query specified by the allQuery config option (defaults to 'query')
38083 triggerAction: 'query',
38085 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38086 * (defaults to 4, does not apply if editable = false)
38090 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38091 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38095 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38096 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38100 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38101 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38105 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38106 * when editable = true (defaults to false)
38108 selectOnFocus:false,
38110 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38112 queryParam: 'query',
38114 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38115 * when mode = 'remote' (defaults to 'Loading...')
38117 loadingText: 'Loading...',
38119 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38123 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38127 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38128 * traditional select (defaults to true)
38132 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38136 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38140 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38141 * listWidth has a higher value)
38145 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38146 * allow the user to set arbitrary text into the field (defaults to false)
38148 forceSelection:false,
38150 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38151 * if typeAhead = true (defaults to 250)
38153 typeAheadDelay : 250,
38155 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38156 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38158 valueNotFoundText : undefined,
38160 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38162 blockFocus : false,
38165 * @cfg {Boolean} disableClear Disable showing of clear button.
38167 disableClear : false,
38169 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38171 alwaysQuery : false,
38177 // element that contains real text value.. (when hidden is used..)
38180 onRender : function(ct, position){
38181 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38182 if(this.hiddenName){
38183 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38185 this.hiddenField.value =
38186 this.hiddenValue !== undefined ? this.hiddenValue :
38187 this.value !== undefined ? this.value : '';
38189 // prevent input submission
38190 this.el.dom.removeAttribute('name');
38195 this.el.dom.setAttribute('autocomplete', 'off');
38198 var cls = 'x-combo-list';
38200 this.list = new Roo.Layer({
38201 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38204 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38205 this.list.setWidth(lw);
38206 this.list.swallowEvent('mousewheel');
38207 this.assetHeight = 0;
38210 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38211 this.assetHeight += this.header.getHeight();
38214 this.innerList = this.list.createChild({cls:cls+'-inner'});
38215 this.innerList.on('mouseover', this.onViewOver, this);
38216 this.innerList.on('mousemove', this.onViewMove, this);
38217 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38219 if(this.allowBlank && !this.pageSize && !this.disableClear){
38220 this.footer = this.list.createChild({cls:cls+'-ft'});
38221 this.pageTb = new Roo.Toolbar(this.footer);
38225 this.footer = this.list.createChild({cls:cls+'-ft'});
38226 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38227 {pageSize: this.pageSize});
38231 if (this.pageTb && this.allowBlank && !this.disableClear) {
38233 this.pageTb.add(new Roo.Toolbar.Fill(), {
38234 cls: 'x-btn-icon x-btn-clear',
38236 handler: function()
38239 _this.clearValue();
38240 _this.onSelect(false, -1);
38245 this.assetHeight += this.footer.getHeight();
38250 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38253 this.view = new Roo.View(this.innerList, this.tpl, {
38254 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38257 this.view.on('click', this.onViewClick, this);
38259 this.store.on('beforeload', this.onBeforeLoad, this);
38260 this.store.on('load', this.onLoad, this);
38261 this.store.on('loadexception', this.onLoadException, this);
38263 if(this.resizable){
38264 this.resizer = new Roo.Resizable(this.list, {
38265 pinned:true, handles:'se'
38267 this.resizer.on('resize', function(r, w, h){
38268 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38269 this.listWidth = w;
38270 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38271 this.restrictHeight();
38273 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38275 if(!this.editable){
38276 this.editable = true;
38277 this.setEditable(false);
38281 if (typeof(this.events.add.listeners) != 'undefined') {
38283 this.addicon = this.wrap.createChild(
38284 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38286 this.addicon.on('click', function(e) {
38287 this.fireEvent('add', this);
38290 if (typeof(this.events.edit.listeners) != 'undefined') {
38292 this.editicon = this.wrap.createChild(
38293 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38294 if (this.addicon) {
38295 this.editicon.setStyle('margin-left', '40px');
38297 this.editicon.on('click', function(e) {
38299 // we fire even if inothing is selected..
38300 this.fireEvent('edit', this, this.lastData );
38310 initEvents : function(){
38311 Roo.form.ComboBox.superclass.initEvents.call(this);
38313 this.keyNav = new Roo.KeyNav(this.el, {
38314 "up" : function(e){
38315 this.inKeyMode = true;
38319 "down" : function(e){
38320 if(!this.isExpanded()){
38321 this.onTriggerClick();
38323 this.inKeyMode = true;
38328 "enter" : function(e){
38329 this.onViewClick();
38333 "esc" : function(e){
38337 "tab" : function(e){
38338 this.onViewClick(false);
38339 this.fireEvent("specialkey", this, e);
38345 doRelay : function(foo, bar, hname){
38346 if(hname == 'down' || this.scope.isExpanded()){
38347 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38354 this.queryDelay = Math.max(this.queryDelay || 10,
38355 this.mode == 'local' ? 10 : 250);
38356 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38357 if(this.typeAhead){
38358 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38360 if(this.editable !== false){
38361 this.el.on("keyup", this.onKeyUp, this);
38363 if(this.forceSelection){
38364 this.on('blur', this.doForce, this);
38368 onDestroy : function(){
38370 this.view.setStore(null);
38371 this.view.el.removeAllListeners();
38372 this.view.el.remove();
38373 this.view.purgeListeners();
38376 this.list.destroy();
38379 this.store.un('beforeload', this.onBeforeLoad, this);
38380 this.store.un('load', this.onLoad, this);
38381 this.store.un('loadexception', this.onLoadException, this);
38383 Roo.form.ComboBox.superclass.onDestroy.call(this);
38387 fireKey : function(e){
38388 if(e.isNavKeyPress() && !this.list.isVisible()){
38389 this.fireEvent("specialkey", this, e);
38394 onResize: function(w, h){
38395 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
38397 if(typeof w != 'number'){
38398 // we do not handle it!?!?
38401 var tw = this.trigger.getWidth();
38402 tw += this.addicon ? this.addicon.getWidth() : 0;
38403 tw += this.editicon ? this.editicon.getWidth() : 0;
38405 this.el.setWidth( this.adjustWidth('input', x));
38407 this.trigger.setStyle('left', x+'px');
38409 if(this.list && this.listWidth === undefined){
38410 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38411 this.list.setWidth(lw);
38412 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38420 * Allow or prevent the user from directly editing the field text. If false is passed,
38421 * the user will only be able to select from the items defined in the dropdown list. This method
38422 * is the runtime equivalent of setting the 'editable' config option at config time.
38423 * @param {Boolean} value True to allow the user to directly edit the field text
38425 setEditable : function(value){
38426 if(value == this.editable){
38429 this.editable = value;
38431 this.el.dom.setAttribute('readOnly', true);
38432 this.el.on('mousedown', this.onTriggerClick, this);
38433 this.el.addClass('x-combo-noedit');
38435 this.el.dom.setAttribute('readOnly', false);
38436 this.el.un('mousedown', this.onTriggerClick, this);
38437 this.el.removeClass('x-combo-noedit');
38442 onBeforeLoad : function(){
38443 if(!this.hasFocus){
38446 this.innerList.update(this.loadingText ?
38447 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
38448 this.restrictHeight();
38449 this.selectedIndex = -1;
38453 onLoad : function(){
38454 if(!this.hasFocus){
38457 if(this.store.getCount() > 0){
38459 this.restrictHeight();
38460 if(this.lastQuery == this.allQuery){
38462 this.el.dom.select();
38464 if(!this.selectByValue(this.value, true)){
38465 this.select(0, true);
38469 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38470 this.taTask.delay(this.typeAheadDelay);
38474 this.onEmptyResults();
38479 onLoadException : function()
38482 Roo.log(this.store.reader.jsonData);
38483 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
38484 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38490 onTypeAhead : function(){
38491 if(this.store.getCount() > 0){
38492 var r = this.store.getAt(0);
38493 var newValue = r.data[this.displayField];
38494 var len = newValue.length;
38495 var selStart = this.getRawValue().length;
38496 if(selStart != len){
38497 this.setRawValue(newValue);
38498 this.selectText(selStart, newValue.length);
38504 onSelect : function(record, index){
38505 if(this.fireEvent('beforeselect', this, record, index) !== false){
38506 this.setFromData(index > -1 ? record.data : false);
38508 this.fireEvent('select', this, record, index);
38513 * Returns the currently selected field value or empty string if no value is set.
38514 * @return {String} value The selected value
38516 getValue : function(){
38517 if(this.valueField){
38518 return typeof this.value != 'undefined' ? this.value : '';
38520 return Roo.form.ComboBox.superclass.getValue.call(this);
38525 * Clears any text/value currently set in the field
38527 clearValue : function(){
38528 if(this.hiddenField){
38529 this.hiddenField.value = '';
38532 this.setRawValue('');
38533 this.lastSelectionText = '';
38534 this.applyEmptyText();
38538 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38539 * will be displayed in the field. If the value does not match the data value of an existing item,
38540 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38541 * Otherwise the field will be blank (although the value will still be set).
38542 * @param {String} value The value to match
38544 setValue : function(v){
38546 if(this.valueField){
38547 var r = this.findRecord(this.valueField, v);
38549 text = r.data[this.displayField];
38550 }else if(this.valueNotFoundText !== undefined){
38551 text = this.valueNotFoundText;
38554 this.lastSelectionText = text;
38555 if(this.hiddenField){
38556 this.hiddenField.value = v;
38558 Roo.form.ComboBox.superclass.setValue.call(this, text);
38562 * @property {Object} the last set data for the element
38567 * Sets the value of the field based on a object which is related to the record format for the store.
38568 * @param {Object} value the value to set as. or false on reset?
38570 setFromData : function(o){
38571 var dv = ''; // display value
38572 var vv = ''; // value value..
38574 if (this.displayField) {
38575 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
38577 // this is an error condition!!!
38578 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
38581 if(this.valueField){
38582 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
38584 if(this.hiddenField){
38585 this.hiddenField.value = vv;
38587 this.lastSelectionText = dv;
38588 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38592 // no hidden field.. - we store the value in 'value', but still display
38593 // display field!!!!
38594 this.lastSelectionText = dv;
38595 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38601 reset : function(){
38602 // overridden so that last data is reset..
38603 this.setValue(this.originalValue);
38604 this.clearInvalid();
38605 this.lastData = false;
38608 findRecord : function(prop, value){
38610 if(this.store.getCount() > 0){
38611 this.store.each(function(r){
38612 if(r.data[prop] == value){
38622 getName: function()
38624 // returns hidden if it's set..
38625 if (!this.rendered) {return ''};
38626 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38630 onViewMove : function(e, t){
38631 this.inKeyMode = false;
38635 onViewOver : function(e, t){
38636 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38639 var item = this.view.findItemFromChild(t);
38641 var index = this.view.indexOf(item);
38642 this.select(index, false);
38647 onViewClick : function(doFocus)
38649 var index = this.view.getSelectedIndexes()[0];
38650 var r = this.store.getAt(index);
38652 this.onSelect(r, index);
38654 if(doFocus !== false && !this.blockFocus){
38660 restrictHeight : function(){
38661 this.innerList.dom.style.height = '';
38662 var inner = this.innerList.dom;
38663 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38664 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38665 this.list.beginUpdate();
38666 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38667 this.list.alignTo(this.el, this.listAlign);
38668 this.list.endUpdate();
38672 onEmptyResults : function(){
38677 * Returns true if the dropdown list is expanded, else false.
38679 isExpanded : function(){
38680 return this.list.isVisible();
38684 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38685 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38686 * @param {String} value The data value of the item to select
38687 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38688 * selected item if it is not currently in view (defaults to true)
38689 * @return {Boolean} True if the value matched an item in the list, else false
38691 selectByValue : function(v, scrollIntoView){
38692 if(v !== undefined && v !== null){
38693 var r = this.findRecord(this.valueField || this.displayField, v);
38695 this.select(this.store.indexOf(r), scrollIntoView);
38703 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38704 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38705 * @param {Number} index The zero-based index of the list item to select
38706 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38707 * selected item if it is not currently in view (defaults to true)
38709 select : function(index, scrollIntoView){
38710 this.selectedIndex = index;
38711 this.view.select(index);
38712 if(scrollIntoView !== false){
38713 var el = this.view.getNode(index);
38715 this.innerList.scrollChildIntoView(el, false);
38721 selectNext : function(){
38722 var ct = this.store.getCount();
38724 if(this.selectedIndex == -1){
38726 }else if(this.selectedIndex < ct-1){
38727 this.select(this.selectedIndex+1);
38733 selectPrev : function(){
38734 var ct = this.store.getCount();
38736 if(this.selectedIndex == -1){
38738 }else if(this.selectedIndex != 0){
38739 this.select(this.selectedIndex-1);
38745 onKeyUp : function(e){
38746 if(this.editable !== false && !e.isSpecialKey()){
38747 this.lastKey = e.getKey();
38748 this.dqTask.delay(this.queryDelay);
38753 validateBlur : function(){
38754 return !this.list || !this.list.isVisible();
38758 initQuery : function(){
38759 this.doQuery(this.getRawValue());
38763 doForce : function(){
38764 if(this.el.dom.value.length > 0){
38765 this.el.dom.value =
38766 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38767 this.applyEmptyText();
38772 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38773 * query allowing the query action to be canceled if needed.
38774 * @param {String} query The SQL query to execute
38775 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38776 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38777 * saved in the current store (defaults to false)
38779 doQuery : function(q, forceAll){
38780 if(q === undefined || q === null){
38785 forceAll: forceAll,
38789 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38793 forceAll = qe.forceAll;
38794 if(forceAll === true || (q.length >= this.minChars)){
38795 if(this.lastQuery != q || this.alwaysQuery){
38796 this.lastQuery = q;
38797 if(this.mode == 'local'){
38798 this.selectedIndex = -1;
38800 this.store.clearFilter();
38802 this.store.filter(this.displayField, q);
38806 this.store.baseParams[this.queryParam] = q;
38808 params: this.getParams(q)
38813 this.selectedIndex = -1;
38820 getParams : function(q){
38822 //p[this.queryParam] = q;
38825 p.limit = this.pageSize;
38831 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38833 collapse : function(){
38834 if(!this.isExpanded()){
38838 Roo.get(document).un('mousedown', this.collapseIf, this);
38839 Roo.get(document).un('mousewheel', this.collapseIf, this);
38840 if (!this.editable) {
38841 Roo.get(document).un('keydown', this.listKeyPress, this);
38843 this.fireEvent('collapse', this);
38847 collapseIf : function(e){
38848 if(!e.within(this.wrap) && !e.within(this.list)){
38854 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38856 expand : function(){
38857 if(this.isExpanded() || !this.hasFocus){
38860 this.list.alignTo(this.el, this.listAlign);
38862 Roo.get(document).on('mousedown', this.collapseIf, this);
38863 Roo.get(document).on('mousewheel', this.collapseIf, this);
38864 if (!this.editable) {
38865 Roo.get(document).on('keydown', this.listKeyPress, this);
38868 this.fireEvent('expand', this);
38872 // Implements the default empty TriggerField.onTriggerClick function
38873 onTriggerClick : function(){
38877 if(this.isExpanded()){
38879 if (!this.blockFocus) {
38884 this.hasFocus = true;
38885 if(this.triggerAction == 'all') {
38886 this.doQuery(this.allQuery, true);
38888 this.doQuery(this.getRawValue());
38890 if (!this.blockFocus) {
38895 listKeyPress : function(e)
38897 //Roo.log('listkeypress');
38898 // scroll to first matching element based on key pres..
38899 if (e.isSpecialKey()) {
38902 var k = String.fromCharCode(e.getKey()).toUpperCase();
38905 var csel = this.view.getSelectedNodes();
38906 var cselitem = false;
38908 var ix = this.view.indexOf(csel[0]);
38909 cselitem = this.store.getAt(ix);
38910 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38916 this.store.each(function(v) {
38918 // start at existing selection.
38919 if (cselitem.id == v.id) {
38925 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38926 match = this.store.indexOf(v);
38931 if (match === false) {
38932 return true; // no more action?
38935 this.view.select(match);
38936 var sn = Roo.get(this.view.getSelectedNodes()[0])
38937 sn.scrollIntoView(sn.dom.parentNode, false);
38941 * @cfg {Boolean} grow
38945 * @cfg {Number} growMin
38949 * @cfg {Number} growMax
38957 * Copyright(c) 2010-2012, Roo J Solutions Limited
38964 * @class Roo.form.ComboBoxArray
38965 * @extends Roo.form.TextField
38966 * A facebook style adder... for lists of email / people / countries etc...
38967 * pick multiple items from a combo box, and shows each one.
38969 * Fred [x] Brian [x] [Pick another |v]
38972 * For this to work: it needs various extra information
38973 * - normal combo problay has
38975 * + displayField, valueField
38977 * For our purpose...
38980 * If we change from 'extends' to wrapping...
38987 * Create a new ComboBoxArray.
38988 * @param {Object} config Configuration options
38992 Roo.form.ComboBoxArray = function(config)
38995 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
38997 this.items = new Roo.util.MixedCollection(false);
38999 // construct the child combo...
39009 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39012 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39017 // behavies liek a hiddne field
39018 inputType: 'hidden',
39020 * @cfg {Number} width The width of the box that displays the selected element
39027 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39031 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39033 hiddenName : false,
39036 // private the array of items that are displayed..
39038 // private - the hidden field el.
39040 // private - the filed el..
39043 //validateValue : function() { return true; }, // all values are ok!
39044 //onAddClick: function() { },
39046 onRender : function(ct, position)
39049 // create the standard hidden element
39050 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39053 // give fake names to child combo;
39054 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39055 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39057 this.combo = Roo.factory(this.combo, Roo.form);
39058 this.combo.onRender(ct, position);
39060 // assigned so form know we need to do this..
39061 this.store = this.combo.store;
39062 this.valueField = this.combo.valueField;
39063 this.displayField = this.combo.displayField ;
39066 this.combo.wrap.addClass('x-cbarray-grp');
39068 var cbwrap = this.combo.wrap.createChild(
39069 {tag: 'div', cls: 'x-cbarray-cb'},
39074 this.hiddenEl = this.combo.wrap.createChild({
39075 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39077 this.el = this.combo.wrap.createChild({
39078 tag: 'input', type:'hidden' , name: this.name, value : ''
39080 // this.el.dom.removeAttribute("name");
39083 this.outerWrap = this.combo.wrap;
39084 this.wrap = cbwrap;
39086 this.outerWrap.setWidth(this.width);
39087 this.outerWrap.dom.removeChild(this.el.dom);
39089 this.wrap.dom.appendChild(this.el.dom);
39090 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39091 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39093 this.combo.trigger.setStyle('position','relative');
39094 this.combo.trigger.setStyle('left', '0px');
39095 this.combo.trigger.setStyle('top', '2px');
39097 this.combo.el.setStyle('vertical-align', 'text-bottom');
39099 //this.trigger.setStyle('vertical-align', 'top');
39101 // this should use the code from combo really... on('add' ....)
39105 this.adder = this.outerWrap.createChild(
39106 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39108 this.adder.on('click', function(e) {
39109 _t.fireEvent('adderclick', this, e);
39113 //this.adder.on('click', this.onAddClick, _t);
39116 this.combo.on('select', function(cb, rec, ix) {
39117 this.addItem(rec.data);
39120 cb.el.dom.value = '';
39121 //cb.lastData = rec.data;
39130 getName: function()
39132 // returns hidden if it's set..
39133 if (!this.rendered) {return ''};
39134 return this.hiddenName ? this.hiddenName : this.name;
39139 onResize: function(w, h){
39142 // not sure if this is needed..
39143 //this.combo.onResize(w,h);
39145 if(typeof w != 'number'){
39146 // we do not handle it!?!?
39149 var tw = this.combo.trigger.getWidth();
39150 tw += this.addicon ? this.addicon.getWidth() : 0;
39151 tw += this.editicon ? this.editicon.getWidth() : 0;
39153 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39155 this.combo.trigger.setStyle('left', '0px');
39157 if(this.list && this.listWidth === undefined){
39158 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39159 this.list.setWidth(lw);
39160 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39167 addItem: function(rec)
39169 var valueField = this.combo.valueField;
39170 var displayField = this.combo.displayField;
39171 if (this.items.indexOfKey(rec[valueField]) > -1) {
39172 //console.log("GOT " + rec.data.id);
39176 var x = new Roo.form.ComboBoxArray.Item({
39177 //id : rec[this.idField],
39179 displayField : displayField ,
39180 tipField : displayField ,
39184 this.items.add(rec[valueField],x);
39185 // add it before the element..
39186 this.updateHiddenEl();
39187 x.render(this.outerWrap, this.wrap.dom);
39188 // add the image handler..
39191 updateHiddenEl : function()
39194 if (!this.hiddenEl) {
39198 var idField = this.combo.valueField;
39200 this.items.each(function(f) {
39201 ar.push(f.data[idField]);
39204 this.hiddenEl.dom.value = ar.join(',');
39210 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39211 this.items.each(function(f) {
39214 this.el.dom.value = '';
39215 if (this.hiddenEl) {
39216 this.hiddenEl.dom.value = '';
39220 getValue: function()
39222 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39224 setValue: function(v) // not a valid action - must use addItems..
39231 if (this.store.isLocal && (typeof(v) == 'string')) {
39232 // then we can use the store to find the values..
39233 // comma seperated at present.. this needs to allow JSON based encoding..
39234 this.hiddenEl.value = v;
39236 Roo.each(v.split(','), function(k) {
39237 Roo.log("CHECK " + this.valueField + ',' + k);
39238 var li = this.store.query(this.valueField, k);
39243 add[this.valueField] = k;
39244 add[this.displayField] = li.item(0).data[this.displayField];
39250 if (typeof(v) == 'object') {
39251 // then let's assume it's an array of objects..
39252 Roo.each(v, function(l) {
39260 setFromData: function(v)
39262 // this recieves an object, if setValues is called.
39264 this.el.dom.value = v[this.displayField];
39265 this.hiddenEl.dom.value = v[this.valueField];
39266 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39269 var kv = v[this.valueField];
39270 var dv = v[this.displayField];
39271 kv = typeof(kv) != 'string' ? '' : kv;
39272 dv = typeof(dv) != 'string' ? '' : dv;
39275 var keys = kv.split(',');
39276 var display = dv.split(',');
39277 for (var i = 0 ; i < keys.length; i++) {
39280 add[this.valueField] = keys[i];
39281 add[this.displayField] = display[i];
39289 validateValue : function(value){
39290 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39299 * @class Roo.form.ComboBoxArray.Item
39300 * @extends Roo.BoxComponent
39301 * A selected item in the list
39302 * Fred [x] Brian [x] [Pick another |v]
39305 * Create a new item.
39306 * @param {Object} config Configuration options
39309 Roo.form.ComboBoxArray.Item = function(config) {
39310 config.id = Roo.id();
39311 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39314 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39317 displayField : false,
39321 defaultAutoCreate : {
39323 cls: 'x-cbarray-item',
39330 src : Roo.BLANK_IMAGE_URL ,
39338 onRender : function(ct, position)
39340 Roo.form.Field.superclass.onRender.call(this, ct, position);
39343 var cfg = this.getAutoCreate();
39344 this.el = ct.createChild(cfg, position);
39347 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39349 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39350 this.cb.renderer(this.data) :
39351 String.format('{0}',this.data[this.displayField]);
39354 this.el.child('div').dom.setAttribute('qtip',
39355 String.format('{0}',this.data[this.tipField])
39358 this.el.child('img').on('click', this.remove, this);
39362 remove : function()
39365 this.cb.items.remove(this);
39366 this.el.child('img').un('click', this.remove, this);
39368 this.cb.updateHiddenEl();
39374 * Ext JS Library 1.1.1
39375 * Copyright(c) 2006-2007, Ext JS, LLC.
39377 * Originally Released Under LGPL - original licence link has changed is not relivant.
39380 * <script type="text/javascript">
39383 * @class Roo.form.Checkbox
39384 * @extends Roo.form.Field
39385 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
39387 * Creates a new Checkbox
39388 * @param {Object} config Configuration options
39390 Roo.form.Checkbox = function(config){
39391 Roo.form.Checkbox.superclass.constructor.call(this, config);
39395 * Fires when the checkbox is checked or unchecked.
39396 * @param {Roo.form.Checkbox} this This checkbox
39397 * @param {Boolean} checked The new checked value
39403 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
39405 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
39407 focusClass : undefined,
39409 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
39411 fieldClass: "x-form-field",
39413 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
39417 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39418 * {tag: "input", type: "checkbox", autocomplete: "off"})
39420 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
39422 * @cfg {String} boxLabel The text that appears beside the checkbox
39426 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
39430 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
39432 valueOff: '0', // value when not checked..
39434 actionMode : 'viewEl',
39437 itemCls : 'x-menu-check-item x-form-item',
39438 groupClass : 'x-menu-group-item',
39439 inputType : 'hidden',
39442 inSetChecked: false, // check that we are not calling self...
39444 inputElement: false, // real input element?
39445 basedOn: false, // ????
39447 isFormField: true, // not sure where this is needed!!!!
39449 onResize : function(){
39450 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
39451 if(!this.boxLabel){
39452 this.el.alignTo(this.wrap, 'c-c');
39456 initEvents : function(){
39457 Roo.form.Checkbox.superclass.initEvents.call(this);
39458 this.el.on("click", this.onClick, this);
39459 this.el.on("change", this.onClick, this);
39463 getResizeEl : function(){
39467 getPositionEl : function(){
39472 onRender : function(ct, position){
39473 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
39475 if(this.inputValue !== undefined){
39476 this.el.dom.value = this.inputValue;
39479 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
39480 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
39481 var viewEl = this.wrap.createChild({
39482 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
39483 this.viewEl = viewEl;
39484 this.wrap.on('click', this.onClick, this);
39486 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
39487 this.el.on('propertychange', this.setFromHidden, this); //ie
39492 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
39493 // viewEl.on('click', this.onClick, this);
39495 //if(this.checked){
39496 this.setChecked(this.checked);
39498 //this.checked = this.el.dom;
39504 initValue : Roo.emptyFn,
39507 * Returns the checked state of the checkbox.
39508 * @return {Boolean} True if checked, else false
39510 getValue : function(){
39512 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
39514 return this.valueOff;
39519 onClick : function(){
39520 this.setChecked(!this.checked);
39522 //if(this.el.dom.checked != this.checked){
39523 // this.setValue(this.el.dom.checked);
39528 * Sets the checked state of the checkbox.
39529 * On is always based on a string comparison between inputValue and the param.
39530 * @param {Boolean/String} value - the value to set
39531 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
39533 setValue : function(v,suppressEvent){
39536 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
39537 //if(this.el && this.el.dom){
39538 // this.el.dom.checked = this.checked;
39539 // this.el.dom.defaultChecked = this.checked;
39541 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
39542 //this.fireEvent("check", this, this.checked);
39545 setChecked : function(state,suppressEvent)
39547 if (this.inSetChecked) {
39548 this.checked = state;
39554 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
39556 this.checked = state;
39557 if(suppressEvent !== true){
39558 this.fireEvent('check', this, state);
39560 this.inSetChecked = true;
39561 this.el.dom.value = state ? this.inputValue : this.valueOff;
39562 this.inSetChecked = false;
39565 // handle setting of hidden value by some other method!!?!?
39566 setFromHidden: function()
39571 //console.log("SET FROM HIDDEN");
39572 //alert('setFrom hidden');
39573 this.setValue(this.el.dom.value);
39576 onDestroy : function()
39579 Roo.get(this.viewEl).remove();
39582 Roo.form.Checkbox.superclass.onDestroy.call(this);
39587 * Ext JS Library 1.1.1
39588 * Copyright(c) 2006-2007, Ext JS, LLC.
39590 * Originally Released Under LGPL - original licence link has changed is not relivant.
39593 * <script type="text/javascript">
39597 * @class Roo.form.Radio
39598 * @extends Roo.form.Checkbox
39599 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
39600 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
39602 * Creates a new Radio
39603 * @param {Object} config Configuration options
39605 Roo.form.Radio = function(){
39606 Roo.form.Radio.superclass.constructor.apply(this, arguments);
39608 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
39609 inputType: 'radio',
39612 * If this radio is part of a group, it will return the selected value
39615 getGroupValue : function(){
39616 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
39618 });//<script type="text/javascript">
39621 * Ext JS Library 1.1.1
39622 * Copyright(c) 2006-2007, Ext JS, LLC.
39623 * licensing@extjs.com
39625 * http://www.extjs.com/license
39631 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
39632 * - IE ? - no idea how much works there.
39640 * @class Ext.form.HtmlEditor
39641 * @extends Ext.form.Field
39642 * Provides a lightweight HTML Editor component.
39644 * This has been tested on Fireforx / Chrome.. IE may not be so great..
39646 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
39647 * supported by this editor.</b><br/><br/>
39648 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
39649 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
39651 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
39653 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
39657 * @cfg {String} createLinkText The default text for the create link prompt
39659 createLinkText : 'Please enter the URL for the link:',
39661 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
39663 defaultLinkValue : 'http:/'+'/',
39666 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
39671 * @cfg {Number} height (in pixels)
39675 * @cfg {Number} width (in pixels)
39680 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
39683 stylesheets: false,
39688 // private properties
39689 validationEvent : false,
39691 initialized : false,
39693 sourceEditMode : false,
39694 onFocus : Roo.emptyFn,
39696 hideMode:'offsets',
39698 defaultAutoCreate : { // modified by initCompnoent..
39700 style:"width:500px;height:300px;",
39701 autocomplete: "off"
39705 initComponent : function(){
39708 * @event initialize
39709 * Fires when the editor is fully initialized (including the iframe)
39710 * @param {HtmlEditor} this
39715 * Fires when the editor is first receives the focus. Any insertion must wait
39716 * until after this event.
39717 * @param {HtmlEditor} this
39721 * @event beforesync
39722 * Fires before the textarea is updated with content from the editor iframe. Return false
39723 * to cancel the sync.
39724 * @param {HtmlEditor} this
39725 * @param {String} html
39729 * @event beforepush
39730 * Fires before the iframe editor is updated with content from the textarea. Return false
39731 * to cancel the push.
39732 * @param {HtmlEditor} this
39733 * @param {String} html
39738 * Fires when the textarea is updated with content from the editor iframe.
39739 * @param {HtmlEditor} this
39740 * @param {String} html
39745 * Fires when the iframe editor is updated with content from the textarea.
39746 * @param {HtmlEditor} this
39747 * @param {String} html
39751 * @event editmodechange
39752 * Fires when the editor switches edit modes
39753 * @param {HtmlEditor} this
39754 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
39756 editmodechange: true,
39758 * @event editorevent
39759 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
39760 * @param {HtmlEditor} this
39764 this.defaultAutoCreate = {
39766 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
39767 autocomplete: "off"
39772 * Protected method that will not generally be called directly. It
39773 * is called when the editor creates its toolbar. Override this method if you need to
39774 * add custom toolbar buttons.
39775 * @param {HtmlEditor} editor
39777 createToolbar : function(editor){
39778 if (!editor.toolbars || !editor.toolbars.length) {
39779 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
39782 for (var i =0 ; i < editor.toolbars.length;i++) {
39783 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
39784 editor.toolbars[i].init(editor);
39791 * Protected method that will not generally be called directly. It
39792 * is called when the editor initializes the iframe with HTML contents. Override this method if you
39793 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
39795 getDocMarkup : function(){
39798 if (this.stylesheets === false) {
39800 Roo.get(document.head).select('style').each(function(node) {
39801 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
39804 Roo.get(document.head).select('link').each(function(node) {
39805 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
39808 } else if (!this.stylesheets.length) {
39810 st = '<style type="text/css">' +
39811 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
39814 Roo.each(this.stylesheets, function(s) {
39815 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
39820 st += '<style type="text/css">' +
39821 'IMG { cursor: pointer } ' +
39825 return '<html><head>' + st +
39826 //<style type="text/css">' +
39827 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
39829 ' </head><body class="roo-htmleditor-body"></body></html>';
39833 onRender : function(ct, position)
39836 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
39837 this.el.dom.style.border = '0 none';
39838 this.el.dom.setAttribute('tabIndex', -1);
39839 this.el.addClass('x-hidden');
39840 if(Roo.isIE){ // fix IE 1px bogus margin
39841 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
39843 this.wrap = this.el.wrap({
39844 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
39847 if (this.resizable) {
39848 this.resizeEl = new Roo.Resizable(this.wrap, {
39852 minHeight : this.height,
39853 height: this.height,
39854 handles : this.resizable,
39857 resize : function(r, w, h) {
39858 _t.onResize(w,h); // -something
39865 this.frameId = Roo.id();
39867 this.createToolbar(this);
39871 var iframe = this.wrap.createChild({
39874 name: this.frameId,
39875 frameBorder : 'no',
39876 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
39880 // console.log(iframe);
39881 //this.wrap.dom.appendChild(iframe);
39883 this.iframe = iframe.dom;
39885 this.assignDocWin();
39887 this.doc.designMode = 'on';
39890 this.doc.write(this.getDocMarkup());
39894 var task = { // must defer to wait for browser to be ready
39896 //console.log("run task?" + this.doc.readyState);
39897 this.assignDocWin();
39898 if(this.doc.body || this.doc.readyState == 'complete'){
39900 this.doc.designMode="on";
39904 Roo.TaskMgr.stop(task);
39905 this.initEditor.defer(10, this);
39912 Roo.TaskMgr.start(task);
39915 this.setSize(this.wrap.getSize());
39917 if (this.resizeEl) {
39918 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
39919 // should trigger onReize..
39924 onResize : function(w, h)
39926 //Roo.log('resize: ' +w + ',' + h );
39927 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
39928 if(this.el && this.iframe){
39929 if(typeof w == 'number'){
39930 var aw = w - this.wrap.getFrameWidth('lr');
39931 this.el.setWidth(this.adjustWidth('textarea', aw));
39932 this.iframe.style.width = aw + 'px';
39934 if(typeof h == 'number'){
39936 for (var i =0; i < this.toolbars.length;i++) {
39937 // fixme - ask toolbars for heights?
39938 tbh += this.toolbars[i].tb.el.getHeight();
39939 if (this.toolbars[i].footer) {
39940 tbh += this.toolbars[i].footer.el.getHeight();
39947 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
39948 ah -= 5; // knock a few pixes off for look..
39949 this.el.setHeight(this.adjustWidth('textarea', ah));
39950 this.iframe.style.height = ah + 'px';
39952 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
39959 * Toggles the editor between standard and source edit mode.
39960 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
39962 toggleSourceEdit : function(sourceEditMode){
39964 this.sourceEditMode = sourceEditMode === true;
39966 if(this.sourceEditMode){
39969 this.iframe.className = 'x-hidden';
39970 this.el.removeClass('x-hidden');
39971 this.el.dom.removeAttribute('tabIndex');
39976 this.iframe.className = '';
39977 this.el.addClass('x-hidden');
39978 this.el.dom.setAttribute('tabIndex', -1);
39981 this.setSize(this.wrap.getSize());
39982 this.fireEvent('editmodechange', this, this.sourceEditMode);
39985 // private used internally
39986 createLink : function(){
39987 var url = prompt(this.createLinkText, this.defaultLinkValue);
39988 if(url && url != 'http:/'+'/'){
39989 this.relayCmd('createlink', url);
39993 // private (for BoxComponent)
39994 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39996 // private (for BoxComponent)
39997 getResizeEl : function(){
40001 // private (for BoxComponent)
40002 getPositionEl : function(){
40007 initEvents : function(){
40008 this.originalValue = this.getValue();
40012 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40015 markInvalid : Roo.emptyFn,
40017 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40020 clearInvalid : Roo.emptyFn,
40022 setValue : function(v){
40023 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40028 * Protected method that will not generally be called directly. If you need/want
40029 * custom HTML cleanup, this is the method you should override.
40030 * @param {String} html The HTML to be cleaned
40031 * return {String} The cleaned HTML
40033 cleanHtml : function(html){
40034 html = String(html);
40035 if(html.length > 5){
40036 if(Roo.isSafari){ // strip safari nonsense
40037 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40040 if(html == ' '){
40047 * Protected method that will not generally be called directly. Syncs the contents
40048 * of the editor iframe with the textarea.
40050 syncValue : function(){
40051 if(this.initialized){
40052 var bd = (this.doc.body || this.doc.documentElement);
40053 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40054 var html = bd.innerHTML;
40056 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40057 var m = bs.match(/text-align:(.*?);/i);
40059 html = '<div style="'+m[0]+'">' + html + '</div>';
40062 html = this.cleanHtml(html);
40063 // fix up the special chars..
40064 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40065 return "&#"+b.charCodeAt()+";"
40067 if(this.fireEvent('beforesync', this, html) !== false){
40068 this.el.dom.value = html;
40069 this.fireEvent('sync', this, html);
40075 * Protected method that will not generally be called directly. Pushes the value of the textarea
40076 * into the iframe editor.
40078 pushValue : function(){
40079 if(this.initialized){
40080 var v = this.el.dom.value;
40085 if(this.fireEvent('beforepush', this, v) !== false){
40086 var d = (this.doc.body || this.doc.documentElement);
40088 this.cleanUpPaste();
40089 this.el.dom.value = d.innerHTML;
40090 this.fireEvent('push', this, v);
40096 deferFocus : function(){
40097 this.focus.defer(10, this);
40101 focus : function(){
40102 if(this.win && !this.sourceEditMode){
40109 assignDocWin: function()
40111 var iframe = this.iframe;
40114 this.doc = iframe.contentWindow.document;
40115 this.win = iframe.contentWindow;
40117 if (!Roo.get(this.frameId)) {
40120 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40121 this.win = Roo.get(this.frameId).dom.contentWindow;
40126 initEditor : function(){
40127 //console.log("INIT EDITOR");
40128 this.assignDocWin();
40132 this.doc.designMode="on";
40134 this.doc.write(this.getDocMarkup());
40137 var dbody = (this.doc.body || this.doc.documentElement);
40138 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40139 // this copies styles from the containing element into thsi one..
40140 // not sure why we need all of this..
40141 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40142 ss['background-attachment'] = 'fixed'; // w3c
40143 dbody.bgProperties = 'fixed'; // ie
40144 Roo.DomHelper.applyStyles(dbody, ss);
40145 Roo.EventManager.on(this.doc, {
40146 //'mousedown': this.onEditorEvent,
40147 'mouseup': this.onEditorEvent,
40148 'dblclick': this.onEditorEvent,
40149 'click': this.onEditorEvent,
40150 'keyup': this.onEditorEvent,
40155 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40157 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40158 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40160 this.initialized = true;
40162 this.fireEvent('initialize', this);
40167 onDestroy : function(){
40173 for (var i =0; i < this.toolbars.length;i++) {
40174 // fixme - ask toolbars for heights?
40175 this.toolbars[i].onDestroy();
40178 this.wrap.dom.innerHTML = '';
40179 this.wrap.remove();
40184 onFirstFocus : function(){
40186 this.assignDocWin();
40189 this.activated = true;
40190 for (var i =0; i < this.toolbars.length;i++) {
40191 this.toolbars[i].onFirstFocus();
40194 if(Roo.isGecko){ // prevent silly gecko errors
40196 var s = this.win.getSelection();
40197 if(!s.focusNode || s.focusNode.nodeType != 3){
40198 var r = s.getRangeAt(0);
40199 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40204 this.execCmd('useCSS', true);
40205 this.execCmd('styleWithCSS', false);
40208 this.fireEvent('activate', this);
40212 adjustFont: function(btn){
40213 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40214 //if(Roo.isSafari){ // safari
40217 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40218 if(Roo.isSafari){ // safari
40219 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40220 v = (v < 10) ? 10 : v;
40221 v = (v > 48) ? 48 : v;
40222 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40227 v = Math.max(1, v+adjust);
40229 this.execCmd('FontSize', v );
40232 onEditorEvent : function(e){
40233 this.fireEvent('editorevent', this, e);
40234 // this.updateToolbar();
40235 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40238 insertTag : function(tg)
40240 // could be a bit smarter... -> wrap the current selected tRoo..
40242 this.execCmd("formatblock", tg);
40246 insertText : function(txt)
40250 range = this.createRange();
40251 range.deleteContents();
40252 //alert(Sender.getAttribute('label'));
40254 range.insertNode(this.doc.createTextNode(txt));
40258 relayBtnCmd : function(btn){
40259 this.relayCmd(btn.cmd);
40263 * Executes a Midas editor command on the editor document and performs necessary focus and
40264 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40265 * @param {String} cmd The Midas command
40266 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40268 relayCmd : function(cmd, value){
40270 this.execCmd(cmd, value);
40271 this.fireEvent('editorevent', this);
40272 //this.updateToolbar();
40277 * Executes a Midas editor command directly on the editor document.
40278 * For visual commands, you should use {@link #relayCmd} instead.
40279 * <b>This should only be called after the editor is initialized.</b>
40280 * @param {String} cmd The Midas command
40281 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40283 execCmd : function(cmd, value){
40284 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40291 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40293 * @param {String} text | dom node..
40295 insertAtCursor : function(text)
40300 if(!this.activated){
40306 var r = this.doc.selection.createRange();
40317 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40321 // from jquery ui (MIT licenced)
40323 var win = this.win;
40325 if (win.getSelection && win.getSelection().getRangeAt) {
40326 range = win.getSelection().getRangeAt(0);
40327 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
40328 range.insertNode(node);
40329 } else if (win.document.selection && win.document.selection.createRange) {
40330 // no firefox support
40331 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40332 win.document.selection.createRange().pasteHTML(txt);
40334 // no firefox support
40335 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40336 this.execCmd('InsertHTML', txt);
40345 mozKeyPress : function(e){
40347 var c = e.getCharCode(), cmd;
40350 c = String.fromCharCode(c).toLowerCase();
40364 this.cleanUpPaste.defer(100, this);
40372 e.preventDefault();
40380 fixKeys : function(){ // load time branching for fastest keydown performance
40382 return function(e){
40383 var k = e.getKey(), r;
40386 r = this.doc.selection.createRange();
40389 r.pasteHTML('    ');
40396 r = this.doc.selection.createRange();
40398 var target = r.parentElement();
40399 if(!target || target.tagName.toLowerCase() != 'li'){
40401 r.pasteHTML('<br />');
40407 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40408 this.cleanUpPaste.defer(100, this);
40414 }else if(Roo.isOpera){
40415 return function(e){
40416 var k = e.getKey();
40420 this.execCmd('InsertHTML','    ');
40423 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40424 this.cleanUpPaste.defer(100, this);
40429 }else if(Roo.isSafari){
40430 return function(e){
40431 var k = e.getKey();
40435 this.execCmd('InsertText','\t');
40439 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40440 this.cleanUpPaste.defer(100, this);
40448 getAllAncestors: function()
40450 var p = this.getSelectedNode();
40453 a.push(p); // push blank onto stack..
40454 p = this.getParentElement();
40458 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
40462 a.push(this.doc.body);
40466 lastSelNode : false,
40469 getSelection : function()
40471 this.assignDocWin();
40472 return Roo.isIE ? this.doc.selection : this.win.getSelection();
40475 getSelectedNode: function()
40477 // this may only work on Gecko!!!
40479 // should we cache this!!!!
40484 var range = this.createRange(this.getSelection()).cloneRange();
40487 var parent = range.parentElement();
40489 var testRange = range.duplicate();
40490 testRange.moveToElementText(parent);
40491 if (testRange.inRange(range)) {
40494 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
40497 parent = parent.parentElement;
40502 // is ancestor a text element.
40503 var ac = range.commonAncestorContainer;
40504 if (ac.nodeType == 3) {
40505 ac = ac.parentNode;
40508 var ar = ac.childNodes;
40511 var other_nodes = [];
40512 var has_other_nodes = false;
40513 for (var i=0;i<ar.length;i++) {
40514 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
40517 // fullly contained node.
40519 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
40524 // probably selected..
40525 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
40526 other_nodes.push(ar[i]);
40530 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
40535 has_other_nodes = true;
40537 if (!nodes.length && other_nodes.length) {
40538 nodes= other_nodes;
40540 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
40546 createRange: function(sel)
40548 // this has strange effects when using with
40549 // top toolbar - not sure if it's a great idea.
40550 //this.editor.contentWindow.focus();
40551 if (typeof sel != "undefined") {
40553 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
40555 return this.doc.createRange();
40558 return this.doc.createRange();
40561 getParentElement: function()
40564 this.assignDocWin();
40565 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
40567 var range = this.createRange(sel);
40570 var p = range.commonAncestorContainer;
40571 while (p.nodeType == 3) { // text node
40582 * Range intersection.. the hard stuff...
40586 * [ -- selected range --- ]
40590 * if end is before start or hits it. fail.
40591 * if start is after end or hits it fail.
40593 * if either hits (but other is outside. - then it's not
40599 // @see http://www.thismuchiknow.co.uk/?p=64.
40600 rangeIntersectsNode : function(range, node)
40602 var nodeRange = node.ownerDocument.createRange();
40604 nodeRange.selectNode(node);
40606 nodeRange.selectNodeContents(node);
40609 var rangeStartRange = range.cloneRange();
40610 rangeStartRange.collapse(true);
40612 var rangeEndRange = range.cloneRange();
40613 rangeEndRange.collapse(false);
40615 var nodeStartRange = nodeRange.cloneRange();
40616 nodeStartRange.collapse(true);
40618 var nodeEndRange = nodeRange.cloneRange();
40619 nodeEndRange.collapse(false);
40621 return rangeStartRange.compareBoundaryPoints(
40622 Range.START_TO_START, nodeEndRange) == -1 &&
40623 rangeEndRange.compareBoundaryPoints(
40624 Range.START_TO_START, nodeStartRange) == 1;
40628 rangeCompareNode : function(range, node)
40630 var nodeRange = node.ownerDocument.createRange();
40632 nodeRange.selectNode(node);
40634 nodeRange.selectNodeContents(node);
40638 range.collapse(true);
40640 nodeRange.collapse(true);
40642 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
40643 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
40645 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
40647 var nodeIsBefore = ss == 1;
40648 var nodeIsAfter = ee == -1;
40650 if (nodeIsBefore && nodeIsAfter)
40652 if (!nodeIsBefore && nodeIsAfter)
40653 return 1; //right trailed.
40655 if (nodeIsBefore && !nodeIsAfter)
40656 return 2; // left trailed.
40661 // private? - in a new class?
40662 cleanUpPaste : function()
40664 // cleans up the whole document..
40665 Roo.log('cleanuppaste');
40666 this.cleanUpChildren(this.doc.body);
40667 var clean = this.cleanWordChars(this.doc.body.innerHTML);
40668 if (clean != this.doc.body.innerHTML) {
40669 this.doc.body.innerHTML = clean;
40674 cleanWordChars : function(input) {
40675 var he = Roo.form.HtmlEditor;
40677 var output = input;
40678 Roo.each(he.swapCodes, function(sw) {
40680 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
40681 output = output.replace(swapper, sw[1]);
40687 cleanUpChildren : function (n)
40689 if (!n.childNodes.length) {
40692 for (var i = n.childNodes.length-1; i > -1 ; i--) {
40693 this.cleanUpChild(n.childNodes[i]);
40700 cleanUpChild : function (node)
40702 //console.log(node);
40703 if (node.nodeName == "#text") {
40704 // clean up silly Windows -- stuff?
40707 if (node.nodeName == "#comment") {
40708 node.parentNode.removeChild(node);
40709 // clean up silly Windows -- stuff?
40713 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
40715 node.parentNode.removeChild(node);
40720 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
40722 // remove <a name=....> as rendering on yahoo mailer is bored with this.
40724 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
40725 remove_keep_children = true;
40728 if (remove_keep_children) {
40729 this.cleanUpChildren(node);
40730 // inserts everything just before this node...
40731 while (node.childNodes.length) {
40732 var cn = node.childNodes[0];
40733 node.removeChild(cn);
40734 node.parentNode.insertBefore(cn, node);
40736 node.parentNode.removeChild(node);
40740 if (!node.attributes || !node.attributes.length) {
40741 this.cleanUpChildren(node);
40745 function cleanAttr(n,v)
40748 if (v.match(/^\./) || v.match(/^\//)) {
40751 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
40754 if (v.match(/^#/)) {
40757 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
40758 node.removeAttribute(n);
40762 function cleanStyle(n,v)
40764 if (v.match(/expression/)) { //XSS?? should we even bother..
40765 node.removeAttribute(n);
40770 var parts = v.split(/;/);
40771 Roo.each(parts, function(p) {
40772 p = p.replace(/\s+/g,'');
40776 var l = p.split(':').shift().replace(/\s+/g,'');
40778 // only allow 'c whitelisted system attributes'
40779 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
40780 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
40781 node.removeAttribute(n);
40791 for (var i = node.attributes.length-1; i > -1 ; i--) {
40792 var a = node.attributes[i];
40794 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
40795 node.removeAttribute(a.name);
40798 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
40799 cleanAttr(a.name,a.value); // fixme..
40802 if (a.name == 'style') {
40803 cleanStyle(a.name,a.value);
40806 /// clean up MS crap..
40807 // tecnically this should be a list of valid class'es..
40810 if (a.name == 'class') {
40811 if (a.value.match(/^Mso/)) {
40812 node.className = '';
40815 if (a.value.match(/body/)) {
40816 node.className = '';
40827 this.cleanUpChildren(node);
40833 // hide stuff that is not compatible
40847 * @event specialkey
40851 * @cfg {String} fieldClass @hide
40854 * @cfg {String} focusClass @hide
40857 * @cfg {String} autoCreate @hide
40860 * @cfg {String} inputType @hide
40863 * @cfg {String} invalidClass @hide
40866 * @cfg {String} invalidText @hide
40869 * @cfg {String} msgFx @hide
40872 * @cfg {String} validateOnBlur @hide
40876 Roo.form.HtmlEditor.white = [
40877 'area', 'br', 'img', 'input', 'hr', 'wbr',
40879 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
40880 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
40881 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
40882 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
40883 'table', 'ul', 'xmp',
40885 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
40888 'dir', 'menu', 'ol', 'ul', 'dl',
40894 Roo.form.HtmlEditor.black = [
40895 // 'embed', 'object', // enable - backend responsiblity to clean thiese
40897 'base', 'basefont', 'bgsound', 'blink', 'body',
40898 'frame', 'frameset', 'head', 'html', 'ilayer',
40899 'iframe', 'layer', 'link', 'meta', 'object',
40900 'script', 'style' ,'title', 'xml' // clean later..
40902 Roo.form.HtmlEditor.clean = [
40903 'script', 'style', 'title', 'xml'
40905 Roo.form.HtmlEditor.remove = [
40910 Roo.form.HtmlEditor.ablack = [
40914 Roo.form.HtmlEditor.aclean = [
40915 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
40919 Roo.form.HtmlEditor.pwhite= [
40920 'http', 'https', 'mailto'
40923 // white listed style attributes.
40924 Roo.form.HtmlEditor.cwhite= [
40930 Roo.form.HtmlEditor.swapCodes =[
40941 // <script type="text/javascript">
40944 * Ext JS Library 1.1.1
40945 * Copyright(c) 2006-2007, Ext JS, LLC.
40951 * @class Roo.form.HtmlEditorToolbar1
40956 new Roo.form.HtmlEditor({
40959 new Roo.form.HtmlEditorToolbar1({
40960 disable : { fonts: 1 , format: 1, ..., ... , ...],
40966 * @cfg {Object} disable List of elements to disable..
40967 * @cfg {Array} btns List of additional buttons.
40971 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
40974 Roo.form.HtmlEditor.ToolbarStandard = function(config)
40977 Roo.apply(this, config);
40979 // default disabled, based on 'good practice'..
40980 this.disable = this.disable || {};
40981 Roo.applyIf(this.disable, {
40984 specialElements : true
40988 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40989 // dont call parent... till later.
40992 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41000 * @cfg {Object} disable List of toolbar elements to disable
41005 * @cfg {Array} fontFamilies An array of available font families
41023 // "á" , ?? a acute?
41028 "°" // , // degrees
41030 // "é" , // e ecute
41031 // "ú" , // u ecute?
41034 specialElements : [
41036 text: "Insert Table",
41039 ihtml : '<table><tr><td>Cell</td></tr></table>'
41043 text: "Insert Image",
41046 ihtml : '<img src="about:blank"/>'
41055 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41056 "input:submit", "input:button", "select", "textarea", "label" ],
41059 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41061 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
41064 * @cfg {String} defaultFont default font to use.
41066 defaultFont: 'tahoma',
41068 fontSelect : false,
41071 formatCombo : false,
41073 init : function(editor)
41075 this.editor = editor;
41078 var fid = editor.frameId;
41080 function btn(id, toggle, handler){
41081 var xid = fid + '-'+ id ;
41085 cls : 'x-btn-icon x-edit-'+id,
41086 enableToggle:toggle !== false,
41087 scope: editor, // was editor...
41088 handler:handler||editor.relayBtnCmd,
41089 clickEvent:'mousedown',
41090 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41097 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41099 // stop form submits
41100 tb.el.on('click', function(e){
41101 e.preventDefault(); // what does this do?
41104 if(!this.disable.font && !Roo.isSafari){
41105 /* why no safari for fonts
41106 editor.fontSelect = tb.el.createChild({
41109 cls:'x-font-select',
41110 html: editor.createFontOptions()
41112 editor.fontSelect.on('change', function(){
41113 var font = editor.fontSelect.dom.value;
41114 editor.relayCmd('fontname', font);
41115 editor.deferFocus();
41118 editor.fontSelect.dom,
41123 if(!this.disable.formats){
41124 this.formatCombo = new Roo.form.ComboBox({
41125 store: new Roo.data.SimpleStore({
41128 data : this.formats // from states.js
41131 //autoCreate : {tag: "div", size: "20"},
41132 displayField:'tag',
41136 triggerAction: 'all',
41137 emptyText:'Add tag',
41138 selectOnFocus:true,
41141 'select': function(c, r, i) {
41142 editor.insertTag(r.get('tag'));
41148 tb.addField(this.formatCombo);
41152 if(!this.disable.format){
41159 if(!this.disable.fontSize){
41164 btn('increasefontsize', false, editor.adjustFont),
41165 btn('decreasefontsize', false, editor.adjustFont)
41170 if(!this.disable.colors){
41173 id:editor.frameId +'-forecolor',
41174 cls:'x-btn-icon x-edit-forecolor',
41175 clickEvent:'mousedown',
41176 tooltip: this.buttonTips['forecolor'] || undefined,
41178 menu : new Roo.menu.ColorMenu({
41179 allowReselect: true,
41180 focus: Roo.emptyFn,
41183 selectHandler: function(cp, color){
41184 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41185 editor.deferFocus();
41188 clickEvent:'mousedown'
41191 id:editor.frameId +'backcolor',
41192 cls:'x-btn-icon x-edit-backcolor',
41193 clickEvent:'mousedown',
41194 tooltip: this.buttonTips['backcolor'] || undefined,
41196 menu : new Roo.menu.ColorMenu({
41197 focus: Roo.emptyFn,
41200 allowReselect: true,
41201 selectHandler: function(cp, color){
41203 editor.execCmd('useCSS', false);
41204 editor.execCmd('hilitecolor', color);
41205 editor.execCmd('useCSS', true);
41206 editor.deferFocus();
41208 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41209 Roo.isSafari || Roo.isIE ? '#'+color : color);
41210 editor.deferFocus();
41214 clickEvent:'mousedown'
41219 // now add all the items...
41222 if(!this.disable.alignments){
41225 btn('justifyleft'),
41226 btn('justifycenter'),
41227 btn('justifyright')
41231 //if(!Roo.isSafari){
41232 if(!this.disable.links){
41235 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41239 if(!this.disable.lists){
41242 btn('insertorderedlist'),
41243 btn('insertunorderedlist')
41246 if(!this.disable.sourceEdit){
41249 btn('sourceedit', true, function(btn){
41250 this.toggleSourceEdit(btn.pressed);
41257 // special menu.. - needs to be tidied up..
41258 if (!this.disable.special) {
41261 cls: 'x-edit-none',
41267 for (var i =0; i < this.specialChars.length; i++) {
41268 smenu.menu.items.push({
41270 html: this.specialChars[i],
41271 handler: function(a,b) {
41272 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41273 //editor.insertAtCursor(a.html);
41286 if (!this.disable.specialElements) {
41289 cls: 'x-edit-none',
41294 for (var i =0; i < this.specialElements.length; i++) {
41295 semenu.menu.items.push(
41297 handler: function(a,b) {
41298 editor.insertAtCursor(this.ihtml);
41300 }, this.specialElements[i])
41312 for(var i =0; i< this.btns.length;i++) {
41313 var b = Roo.factory(this.btns[i],Roo.form);
41314 b.cls = 'x-edit-none';
41323 // disable everything...
41325 this.tb.items.each(function(item){
41326 if(item.id != editor.frameId+ '-sourceedit'){
41330 this.rendered = true;
41332 // the all the btns;
41333 editor.on('editorevent', this.updateToolbar, this);
41334 // other toolbars need to implement this..
41335 //editor.on('editmodechange', this.updateToolbar, this);
41341 * Protected method that will not generally be called directly. It triggers
41342 * a toolbar update by reading the markup state of the current selection in the editor.
41344 updateToolbar: function(){
41346 if(!this.editor.activated){
41347 this.editor.onFirstFocus();
41351 var btns = this.tb.items.map,
41352 doc = this.editor.doc,
41353 frameId = this.editor.frameId;
41355 if(!this.disable.font && !Roo.isSafari){
41357 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
41358 if(name != this.fontSelect.dom.value){
41359 this.fontSelect.dom.value = name;
41363 if(!this.disable.format){
41364 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
41365 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
41366 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
41368 if(!this.disable.alignments){
41369 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
41370 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
41371 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
41373 if(!Roo.isSafari && !this.disable.lists){
41374 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
41375 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
41378 var ans = this.editor.getAllAncestors();
41379 if (this.formatCombo) {
41382 var store = this.formatCombo.store;
41383 this.formatCombo.setValue("");
41384 for (var i =0; i < ans.length;i++) {
41385 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
41387 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
41395 // hides menus... - so this cant be on a menu...
41396 Roo.menu.MenuMgr.hideAll();
41398 //this.editorsyncValue();
41402 createFontOptions : function(){
41403 var buf = [], fs = this.fontFamilies, ff, lc;
41404 for(var i = 0, len = fs.length; i< len; i++){
41406 lc = ff.toLowerCase();
41408 '<option value="',lc,'" style="font-family:',ff,';"',
41409 (this.defaultFont == lc ? ' selected="true">' : '>'),
41414 return buf.join('');
41417 toggleSourceEdit : function(sourceEditMode){
41418 if(sourceEditMode === undefined){
41419 sourceEditMode = !this.sourceEditMode;
41421 this.sourceEditMode = sourceEditMode === true;
41422 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
41423 // just toggle the button?
41424 if(btn.pressed !== this.editor.sourceEditMode){
41425 btn.toggle(this.editor.sourceEditMode);
41429 if(this.sourceEditMode){
41430 this.tb.items.each(function(item){
41431 if(item.cmd != 'sourceedit'){
41437 if(this.initialized){
41438 this.tb.items.each(function(item){
41444 // tell the editor that it's been pressed..
41445 this.editor.toggleSourceEdit(sourceEditMode);
41449 * Object collection of toolbar tooltips for the buttons in the editor. The key
41450 * is the command id associated with that button and the value is a valid QuickTips object.
41455 title: 'Bold (Ctrl+B)',
41456 text: 'Make the selected text bold.',
41457 cls: 'x-html-editor-tip'
41460 title: 'Italic (Ctrl+I)',
41461 text: 'Make the selected text italic.',
41462 cls: 'x-html-editor-tip'
41470 title: 'Bold (Ctrl+B)',
41471 text: 'Make the selected text bold.',
41472 cls: 'x-html-editor-tip'
41475 title: 'Italic (Ctrl+I)',
41476 text: 'Make the selected text italic.',
41477 cls: 'x-html-editor-tip'
41480 title: 'Underline (Ctrl+U)',
41481 text: 'Underline the selected text.',
41482 cls: 'x-html-editor-tip'
41484 increasefontsize : {
41485 title: 'Grow Text',
41486 text: 'Increase the font size.',
41487 cls: 'x-html-editor-tip'
41489 decreasefontsize : {
41490 title: 'Shrink Text',
41491 text: 'Decrease the font size.',
41492 cls: 'x-html-editor-tip'
41495 title: 'Text Highlight Color',
41496 text: 'Change the background color of the selected text.',
41497 cls: 'x-html-editor-tip'
41500 title: 'Font Color',
41501 text: 'Change the color of the selected text.',
41502 cls: 'x-html-editor-tip'
41505 title: 'Align Text Left',
41506 text: 'Align text to the left.',
41507 cls: 'x-html-editor-tip'
41510 title: 'Center Text',
41511 text: 'Center text in the editor.',
41512 cls: 'x-html-editor-tip'
41515 title: 'Align Text Right',
41516 text: 'Align text to the right.',
41517 cls: 'x-html-editor-tip'
41519 insertunorderedlist : {
41520 title: 'Bullet List',
41521 text: 'Start a bulleted list.',
41522 cls: 'x-html-editor-tip'
41524 insertorderedlist : {
41525 title: 'Numbered List',
41526 text: 'Start a numbered list.',
41527 cls: 'x-html-editor-tip'
41530 title: 'Hyperlink',
41531 text: 'Make the selected text a hyperlink.',
41532 cls: 'x-html-editor-tip'
41535 title: 'Source Edit',
41536 text: 'Switch to source editing mode.',
41537 cls: 'x-html-editor-tip'
41541 onDestroy : function(){
41544 this.tb.items.each(function(item){
41546 item.menu.removeAll();
41548 item.menu.el.destroy();
41556 onFirstFocus: function() {
41557 this.tb.items.each(function(item){
41566 // <script type="text/javascript">
41569 * Ext JS Library 1.1.1
41570 * Copyright(c) 2006-2007, Ext JS, LLC.
41577 * @class Roo.form.HtmlEditor.ToolbarContext
41582 new Roo.form.HtmlEditor({
41585 { xtype: 'ToolbarStandard', styles : {} }
41586 { xtype: 'ToolbarContext', disable : {} }
41592 * @config : {Object} disable List of elements to disable.. (not done yet.)
41593 * @config : {Object} styles Map of styles available.
41597 Roo.form.HtmlEditor.ToolbarContext = function(config)
41600 Roo.apply(this, config);
41601 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41602 // dont call parent... till later.
41603 this.styles = this.styles || {};
41605 Roo.form.HtmlEditor.ToolbarContext.types = {
41617 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
41679 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
41684 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
41738 // should we really allow this??
41739 // should this just be
41754 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
41762 * @cfg {Object} disable List of toolbar elements to disable
41767 * @cfg {Object} styles List of styles
41768 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
41770 * These must be defined in the page, so they get rendered correctly..
41781 init : function(editor)
41783 this.editor = editor;
41786 var fid = editor.frameId;
41788 function btn(id, toggle, handler){
41789 var xid = fid + '-'+ id ;
41793 cls : 'x-btn-icon x-edit-'+id,
41794 enableToggle:toggle !== false,
41795 scope: editor, // was editor...
41796 handler:handler||editor.relayBtnCmd,
41797 clickEvent:'mousedown',
41798 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41802 // create a new element.
41803 var wdiv = editor.wrap.createChild({
41805 }, editor.wrap.dom.firstChild.nextSibling, true);
41807 // can we do this more than once??
41809 // stop form submits
41812 // disable everything...
41813 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
41814 this.toolbars = {};
41816 for (var i in ty) {
41818 this.toolbars[i] = this.buildToolbar(ty[i],i);
41820 this.tb = this.toolbars.BODY;
41822 this.buildFooter();
41823 this.footer.show();
41824 editor.on('hide', function( ) { this.footer.hide() }, this);
41825 editor.on('show', function( ) { this.footer.show() }, this);
41828 this.rendered = true;
41830 // the all the btns;
41831 editor.on('editorevent', this.updateToolbar, this);
41832 // other toolbars need to implement this..
41833 //editor.on('editmodechange', this.updateToolbar, this);
41839 * Protected method that will not generally be called directly. It triggers
41840 * a toolbar update by reading the markup state of the current selection in the editor.
41842 updateToolbar: function(editor,ev,sel){
41845 // capture mouse up - this is handy for selecting images..
41846 // perhaps should go somewhere else...
41847 if(!this.editor.activated){
41848 this.editor.onFirstFocus();
41852 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
41853 // selectNode - might want to handle IE?
41855 (ev.type == 'mouseup' || ev.type == 'click' ) &&
41856 ev.target && ev.target.tagName == 'IMG') {
41857 // they have click on an image...
41858 // let's see if we can change the selection...
41861 var nodeRange = sel.ownerDocument.createRange();
41863 nodeRange.selectNode(sel);
41865 nodeRange.selectNodeContents(sel);
41867 //nodeRange.collapse(true);
41868 var s = editor.win.getSelection();
41869 s.removeAllRanges();
41870 s.addRange(nodeRange);
41874 var updateFooter = sel ? false : true;
41877 var ans = this.editor.getAllAncestors();
41880 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
41883 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
41884 sel = sel ? sel : this.editor.doc.body;
41885 sel = sel.tagName.length ? sel : this.editor.doc.body;
41888 // pick a menu that exists..
41889 var tn = sel.tagName.toUpperCase();
41890 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
41892 tn = sel.tagName.toUpperCase();
41894 var lastSel = this.tb.selectedNode
41896 this.tb.selectedNode = sel;
41898 // if current menu does not match..
41899 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
41902 ///console.log("show: " + tn);
41903 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
41906 this.tb.items.first().el.innerHTML = tn + ': ';
41909 // update attributes
41910 if (this.tb.fields) {
41911 this.tb.fields.each(function(e) {
41912 e.setValue(sel.getAttribute(e.attrname));
41916 var hasStyles = false;
41917 for(var i in this.styles) {
41924 var st = this.tb.fields.item(0);
41926 st.store.removeAll();
41929 var cn = sel.className.split(/\s+/);
41932 if (this.styles['*']) {
41934 Roo.each(this.styles['*'], function(v) {
41935 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
41938 if (this.styles[tn]) {
41939 Roo.each(this.styles[tn], function(v) {
41940 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
41944 st.store.loadData(avs);
41948 // flag our selected Node.
41949 this.tb.selectedNode = sel;
41952 Roo.menu.MenuMgr.hideAll();
41956 if (!updateFooter) {
41959 // update the footer
41963 this.footerEls = ans.reverse();
41964 Roo.each(this.footerEls, function(a,i) {
41965 if (!a) { return; }
41966 html += html.length ? ' > ' : '';
41968 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
41973 var sz = this.footDisp.up('td').getSize();
41974 this.footDisp.dom.style.width = (sz.width -10) + 'px';
41975 this.footDisp.dom.style.marginLeft = '5px';
41977 this.footDisp.dom.style.overflow = 'hidden';
41979 this.footDisp.dom.innerHTML = html;
41981 //this.editorsyncValue();
41986 onDestroy : function(){
41989 this.tb.items.each(function(item){
41991 item.menu.removeAll();
41993 item.menu.el.destroy();
42001 onFirstFocus: function() {
42002 // need to do this for all the toolbars..
42003 this.tb.items.each(function(item){
42007 buildToolbar: function(tlist, nm)
42009 var editor = this.editor;
42010 // create a new element.
42011 var wdiv = editor.wrap.createChild({
42013 }, editor.wrap.dom.firstChild.nextSibling, true);
42016 var tb = new Roo.Toolbar(wdiv);
42019 tb.add(nm+ ": ");
42022 for(var i in this.styles) {
42027 if (styles && styles.length) {
42029 // this needs a multi-select checkbox...
42030 tb.addField( new Roo.form.ComboBox({
42031 store: new Roo.data.SimpleStore({
42033 fields: ['val', 'selected'],
42036 name : '-roo-edit-className',
42037 attrname : 'className',
42038 displayField:'val',
42042 triggerAction: 'all',
42043 emptyText:'Select Style',
42044 selectOnFocus:true,
42047 'select': function(c, r, i) {
42048 // initial support only for on class per el..
42049 tb.selectedNode.className = r ? r.get('val') : '';
42050 editor.syncValue();
42059 for (var i in tlist) {
42061 var item = tlist[i];
42062 tb.add(item.title + ": ");
42068 // opts == pulldown..
42069 tb.addField( new Roo.form.ComboBox({
42070 store: new Roo.data.SimpleStore({
42075 name : '-roo-edit-' + i,
42077 displayField:'val',
42081 triggerAction: 'all',
42082 emptyText:'Select',
42083 selectOnFocus:true,
42084 width: item.width ? item.width : 130,
42086 'select': function(c, r, i) {
42087 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42096 tb.addField( new Roo.form.TextField({
42099 //allowBlank:false,
42104 tb.addField( new Roo.form.TextField({
42105 name: '-roo-edit-' + i,
42112 'change' : function(f, nv, ov) {
42113 tb.selectedNode.setAttribute(f.attrname, nv);
42119 tb.el.on('click', function(e){
42120 e.preventDefault(); // what does this do?
42122 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42125 // dont need to disable them... as they will get hidden
42130 buildFooter : function()
42133 var fel = this.editor.wrap.createChild();
42134 this.footer = new Roo.Toolbar(fel);
42135 // toolbar has scrolly on left / right?
42136 var footDisp= new Roo.Toolbar.Fill();
42142 handler : function() {
42143 _t.footDisp.scrollTo('left',0,true)
42147 this.footer.add( footDisp );
42152 handler : function() {
42154 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42158 var fel = Roo.get(footDisp.el);
42159 fel.addClass('x-editor-context');
42160 this.footDispWrap = fel;
42161 this.footDispWrap.overflow = 'hidden';
42163 this.footDisp = fel.createChild();
42164 this.footDispWrap.on('click', this.onContextClick, this)
42168 onContextClick : function (ev,dom)
42170 ev.preventDefault();
42171 var cn = dom.className;
42173 if (!cn.match(/x-ed-loc-/)) {
42176 var n = cn.split('-').pop();
42177 var ans = this.footerEls;
42181 var range = this.editor.createRange();
42183 range.selectNodeContents(sel);
42184 //range.selectNode(sel);
42187 var selection = this.editor.getSelection();
42188 selection.removeAllRanges();
42189 selection.addRange(range);
42193 this.updateToolbar(null, null, sel);
42210 * Ext JS Library 1.1.1
42211 * Copyright(c) 2006-2007, Ext JS, LLC.
42213 * Originally Released Under LGPL - original licence link has changed is not relivant.
42216 * <script type="text/javascript">
42220 * @class Roo.form.BasicForm
42221 * @extends Roo.util.Observable
42222 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
42224 * @param {String/HTMLElement/Roo.Element} el The form element or its id
42225 * @param {Object} config Configuration options
42227 Roo.form.BasicForm = function(el, config){
42228 this.allItems = [];
42229 this.childForms = [];
42230 Roo.apply(this, config);
42232 * The Roo.form.Field items in this form.
42233 * @type MixedCollection
42237 this.items = new Roo.util.MixedCollection(false, function(o){
42238 return o.id || (o.id = Roo.id());
42242 * @event beforeaction
42243 * Fires before any action is performed. Return false to cancel the action.
42244 * @param {Form} this
42245 * @param {Action} action The action to be performed
42247 beforeaction: true,
42249 * @event actionfailed
42250 * Fires when an action fails.
42251 * @param {Form} this
42252 * @param {Action} action The action that failed
42254 actionfailed : true,
42256 * @event actioncomplete
42257 * Fires when an action is completed.
42258 * @param {Form} this
42259 * @param {Action} action The action that completed
42261 actioncomplete : true
42266 Roo.form.BasicForm.superclass.constructor.call(this);
42269 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
42271 * @cfg {String} method
42272 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
42275 * @cfg {DataReader} reader
42276 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
42277 * This is optional as there is built-in support for processing JSON.
42280 * @cfg {DataReader} errorReader
42281 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
42282 * This is completely optional as there is built-in support for processing JSON.
42285 * @cfg {String} url
42286 * The URL to use for form actions if one isn't supplied in the action options.
42289 * @cfg {Boolean} fileUpload
42290 * Set to true if this form is a file upload.
42294 * @cfg {Object} baseParams
42295 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
42300 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
42305 activeAction : null,
42308 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
42309 * or setValues() data instead of when the form was first created.
42311 trackResetOnLoad : false,
42315 * childForms - used for multi-tab forms
42318 childForms : false,
42321 * allItems - full list of fields.
42327 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
42328 * element by passing it or its id or mask the form itself by passing in true.
42331 waitMsgTarget : false,
42334 initEl : function(el){
42335 this.el = Roo.get(el);
42336 this.id = this.el.id || Roo.id();
42337 this.el.on('submit', this.onSubmit, this);
42338 this.el.addClass('x-form');
42342 onSubmit : function(e){
42347 * Returns true if client-side validation on the form is successful.
42350 isValid : function(){
42352 this.items.each(function(f){
42361 * Returns true if any fields in this form have changed since their original load.
42364 isDirty : function(){
42366 this.items.each(function(f){
42376 * Performs a predefined action (submit or load) or custom actions you define on this form.
42377 * @param {String} actionName The name of the action type
42378 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
42379 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
42380 * accept other config options):
42382 Property Type Description
42383 ---------------- --------------- ----------------------------------------------------------------------------------
42384 url String The url for the action (defaults to the form's url)
42385 method String The form method to use (defaults to the form's method, or POST if not defined)
42386 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
42387 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
42388 validate the form on the client (defaults to false)
42390 * @return {BasicForm} this
42392 doAction : function(action, options){
42393 if(typeof action == 'string'){
42394 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
42396 if(this.fireEvent('beforeaction', this, action) !== false){
42397 this.beforeAction(action);
42398 action.run.defer(100, action);
42404 * Shortcut to do a submit action.
42405 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
42406 * @return {BasicForm} this
42408 submit : function(options){
42409 this.doAction('submit', options);
42414 * Shortcut to do a load action.
42415 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
42416 * @return {BasicForm} this
42418 load : function(options){
42419 this.doAction('load', options);
42424 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
42425 * @param {Record} record The record to edit
42426 * @return {BasicForm} this
42428 updateRecord : function(record){
42429 record.beginEdit();
42430 var fs = record.fields;
42431 fs.each(function(f){
42432 var field = this.findField(f.name);
42434 record.set(f.name, field.getValue());
42442 * Loads an Roo.data.Record into this form.
42443 * @param {Record} record The record to load
42444 * @return {BasicForm} this
42446 loadRecord : function(record){
42447 this.setValues(record.data);
42452 beforeAction : function(action){
42453 var o = action.options;
42456 if(this.waitMsgTarget === true){
42457 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
42458 }else if(this.waitMsgTarget){
42459 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
42460 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
42462 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
42468 afterAction : function(action, success){
42469 this.activeAction = null;
42470 var o = action.options;
42472 if(this.waitMsgTarget === true){
42474 }else if(this.waitMsgTarget){
42475 this.waitMsgTarget.unmask();
42477 Roo.MessageBox.updateProgress(1);
42478 Roo.MessageBox.hide();
42485 Roo.callback(o.success, o.scope, [this, action]);
42486 this.fireEvent('actioncomplete', this, action);
42490 // failure condition..
42491 // we have a scenario where updates need confirming.
42492 // eg. if a locking scenario exists..
42493 // we look for { errors : { needs_confirm : true }} in the response.
42495 (typeof(action.result) != 'undefined') &&
42496 (typeof(action.result.errors) != 'undefined') &&
42497 (typeof(action.result.errors.needs_confirm) != 'undefined')
42500 Roo.MessageBox.confirm(
42501 "Change requires confirmation",
42502 action.result.errorMsg,
42507 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
42517 Roo.callback(o.failure, o.scope, [this, action]);
42518 // show an error message if no failed handler is set..
42519 if (!this.hasListener('actionfailed')) {
42520 Roo.MessageBox.alert("Error",
42521 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
42522 action.result.errorMsg :
42523 "Saving Failed, please check your entries or try again"
42527 this.fireEvent('actionfailed', this, action);
42533 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
42534 * @param {String} id The value to search for
42537 findField : function(id){
42538 var field = this.items.get(id);
42540 this.items.each(function(f){
42541 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
42547 return field || null;
42551 * Add a secondary form to this one,
42552 * Used to provide tabbed forms. One form is primary, with hidden values
42553 * which mirror the elements from the other forms.
42555 * @param {Roo.form.Form} form to add.
42558 addForm : function(form)
42561 if (this.childForms.indexOf(form) > -1) {
42565 this.childForms.push(form);
42567 Roo.each(form.allItems, function (fe) {
42569 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
42570 if (this.findField(n)) { // already added..
42573 var add = new Roo.form.Hidden({
42576 add.render(this.el);
42583 * Mark fields in this form invalid in bulk.
42584 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
42585 * @return {BasicForm} this
42587 markInvalid : function(errors){
42588 if(errors instanceof Array){
42589 for(var i = 0, len = errors.length; i < len; i++){
42590 var fieldError = errors[i];
42591 var f = this.findField(fieldError.id);
42593 f.markInvalid(fieldError.msg);
42599 if(typeof errors[id] != 'function' && (field = this.findField(id))){
42600 field.markInvalid(errors[id]);
42604 Roo.each(this.childForms || [], function (f) {
42605 f.markInvalid(errors);
42612 * Set values for fields in this form in bulk.
42613 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
42614 * @return {BasicForm} this
42616 setValues : function(values){
42617 if(values instanceof Array){ // array of objects
42618 for(var i = 0, len = values.length; i < len; i++){
42620 var f = this.findField(v.id);
42622 f.setValue(v.value);
42623 if(this.trackResetOnLoad){
42624 f.originalValue = f.getValue();
42628 }else{ // object hash
42631 if(typeof values[id] != 'function' && (field = this.findField(id))){
42633 if (field.setFromData &&
42634 field.valueField &&
42635 field.displayField &&
42636 // combos' with local stores can
42637 // be queried via setValue()
42638 // to set their value..
42639 (field.store && !field.store.isLocal)
42643 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
42644 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
42645 field.setFromData(sd);
42648 field.setValue(values[id]);
42652 if(this.trackResetOnLoad){
42653 field.originalValue = field.getValue();
42659 Roo.each(this.childForms || [], function (f) {
42660 f.setValues(values);
42667 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
42668 * they are returned as an array.
42669 * @param {Boolean} asString
42672 getValues : function(asString){
42673 if (this.childForms) {
42674 // copy values from the child forms
42675 Roo.each(this.childForms, function (f) {
42676 this.setValues(f.getValues());
42682 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
42683 if(asString === true){
42686 return Roo.urlDecode(fs);
42690 * Returns the fields in this form as an object with key/value pairs.
42691 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
42694 getFieldValues : function(with_hidden)
42696 if (this.childForms) {
42697 // copy values from the child forms
42698 // should this call getFieldValues - probably not as we do not currently copy
42699 // hidden fields when we generate..
42700 Roo.each(this.childForms, function (f) {
42701 this.setValues(f.getValues());
42706 this.items.each(function(f){
42707 if (!f.getName()) {
42710 var v = f.getValue();
42711 // not sure if this supported any more..
42712 if ((typeof(v) == 'object') && f.getRawValue) {
42713 v = f.getRawValue() ; // dates..
42715 // combo boxes where name != hiddenName...
42716 if (f.name != f.getName()) {
42717 ret[f.name] = f.getRawValue();
42719 ret[f.getName()] = v;
42726 * Clears all invalid messages in this form.
42727 * @return {BasicForm} this
42729 clearInvalid : function(){
42730 this.items.each(function(f){
42734 Roo.each(this.childForms || [], function (f) {
42743 * Resets this form.
42744 * @return {BasicForm} this
42746 reset : function(){
42747 this.items.each(function(f){
42751 Roo.each(this.childForms || [], function (f) {
42760 * Add Roo.form components to this form.
42761 * @param {Field} field1
42762 * @param {Field} field2 (optional)
42763 * @param {Field} etc (optional)
42764 * @return {BasicForm} this
42767 this.items.addAll(Array.prototype.slice.call(arguments, 0));
42773 * Removes a field from the items collection (does NOT remove its markup).
42774 * @param {Field} field
42775 * @return {BasicForm} this
42777 remove : function(field){
42778 this.items.remove(field);
42783 * Looks at the fields in this form, checks them for an id attribute,
42784 * and calls applyTo on the existing dom element with that id.
42785 * @return {BasicForm} this
42787 render : function(){
42788 this.items.each(function(f){
42789 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
42797 * Calls {@link Ext#apply} for all fields in this form with the passed object.
42798 * @param {Object} values
42799 * @return {BasicForm} this
42801 applyToFields : function(o){
42802 this.items.each(function(f){
42809 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
42810 * @param {Object} values
42811 * @return {BasicForm} this
42813 applyIfToFields : function(o){
42814 this.items.each(function(f){
42822 Roo.BasicForm = Roo.form.BasicForm;/*
42824 * Ext JS Library 1.1.1
42825 * Copyright(c) 2006-2007, Ext JS, LLC.
42827 * Originally Released Under LGPL - original licence link has changed is not relivant.
42830 * <script type="text/javascript">
42834 * @class Roo.form.Form
42835 * @extends Roo.form.BasicForm
42836 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
42838 * @param {Object} config Configuration options
42840 Roo.form.Form = function(config){
42842 if (config.items) {
42843 xitems = config.items;
42844 delete config.items;
42848 Roo.form.Form.superclass.constructor.call(this, null, config);
42849 this.url = this.url || this.action;
42851 this.root = new Roo.form.Layout(Roo.applyIf({
42855 this.active = this.root;
42857 * Array of all the buttons that have been added to this form via {@link addButton}
42861 this.allItems = [];
42864 * @event clientvalidation
42865 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
42866 * @param {Form} this
42867 * @param {Boolean} valid true if the form has passed client-side validation
42869 clientvalidation: true,
42872 * Fires when the form is rendered
42873 * @param {Roo.form.Form} form
42878 if (this.progressUrl) {
42879 // push a hidden field onto the list of fields..
42883 name : 'UPLOAD_IDENTIFIER'
42888 Roo.each(xitems, this.addxtype, this);
42894 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
42896 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
42899 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
42902 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
42904 buttonAlign:'center',
42907 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
42912 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
42913 * This property cascades to child containers if not set.
42918 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
42919 * fires a looping event with that state. This is required to bind buttons to the valid
42920 * state using the config value formBind:true on the button.
42922 monitorValid : false,
42925 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
42930 * @cfg {String} progressUrl - Url to return progress data
42933 progressUrl : false,
42936 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
42937 * fields are added and the column is closed. If no fields are passed the column remains open
42938 * until end() is called.
42939 * @param {Object} config The config to pass to the column
42940 * @param {Field} field1 (optional)
42941 * @param {Field} field2 (optional)
42942 * @param {Field} etc (optional)
42943 * @return Column The column container object
42945 column : function(c){
42946 var col = new Roo.form.Column(c);
42948 if(arguments.length > 1){ // duplicate code required because of Opera
42949 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42956 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
42957 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
42958 * until end() is called.
42959 * @param {Object} config The config to pass to the fieldset
42960 * @param {Field} field1 (optional)
42961 * @param {Field} field2 (optional)
42962 * @param {Field} etc (optional)
42963 * @return FieldSet The fieldset container object
42965 fieldset : function(c){
42966 var fs = new Roo.form.FieldSet(c);
42968 if(arguments.length > 1){ // duplicate code required because of Opera
42969 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42976 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
42977 * fields are added and the container is closed. If no fields are passed the container remains open
42978 * until end() is called.
42979 * @param {Object} config The config to pass to the Layout
42980 * @param {Field} field1 (optional)
42981 * @param {Field} field2 (optional)
42982 * @param {Field} etc (optional)
42983 * @return Layout The container object
42985 container : function(c){
42986 var l = new Roo.form.Layout(c);
42988 if(arguments.length > 1){ // duplicate code required because of Opera
42989 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
42996 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
42997 * @param {Object} container A Roo.form.Layout or subclass of Layout
42998 * @return {Form} this
43000 start : function(c){
43001 // cascade label info
43002 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43003 this.active.stack.push(c);
43004 c.ownerCt = this.active;
43010 * Closes the current open container
43011 * @return {Form} this
43014 if(this.active == this.root){
43017 this.active = this.active.ownerCt;
43022 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43023 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43024 * as the label of the field.
43025 * @param {Field} field1
43026 * @param {Field} field2 (optional)
43027 * @param {Field} etc. (optional)
43028 * @return {Form} this
43031 this.active.stack.push.apply(this.active.stack, arguments);
43032 this.allItems.push.apply(this.allItems,arguments);
43034 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43035 if(a[i].isFormField){
43040 Roo.form.Form.superclass.add.apply(this, r);
43050 * Find any element that has been added to a form, using it's ID or name
43051 * This can include framesets, columns etc. along with regular fields..
43052 * @param {String} id - id or name to find.
43054 * @return {Element} e - or false if nothing found.
43056 findbyId : function(id)
43062 Roo.each(this.allItems, function(f){
43063 if (f.id == id || f.name == id ){
43074 * Render this form into the passed container. This should only be called once!
43075 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43076 * @return {Form} this
43078 render : function(ct)
43084 var o = this.autoCreate || {
43086 method : this.method || 'POST',
43087 id : this.id || Roo.id()
43089 this.initEl(ct.createChild(o));
43091 this.root.render(this.el);
43095 this.items.each(function(f){
43096 f.render('x-form-el-'+f.id);
43099 if(this.buttons.length > 0){
43100 // tables are required to maintain order and for correct IE layout
43101 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43102 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43103 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43105 var tr = tb.getElementsByTagName('tr')[0];
43106 for(var i = 0, len = this.buttons.length; i < len; i++) {
43107 var b = this.buttons[i];
43108 var td = document.createElement('td');
43109 td.className = 'x-form-btn-td';
43110 b.render(tr.appendChild(td));
43113 if(this.monitorValid){ // initialize after render
43114 this.startMonitoring();
43116 this.fireEvent('rendered', this);
43121 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43122 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43123 * object or a valid Roo.DomHelper element config
43124 * @param {Function} handler The function called when the button is clicked
43125 * @param {Object} scope (optional) The scope of the handler function
43126 * @return {Roo.Button}
43128 addButton : function(config, handler, scope){
43132 minWidth: this.minButtonWidth,
43135 if(typeof config == "string"){
43138 Roo.apply(bc, config);
43140 var btn = new Roo.Button(null, bc);
43141 this.buttons.push(btn);
43146 * Adds a series of form elements (using the xtype property as the factory method.
43147 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43148 * @param {Object} config
43151 addxtype : function()
43153 var ar = Array.prototype.slice.call(arguments, 0);
43155 for(var i = 0; i < ar.length; i++) {
43157 continue; // skip -- if this happends something invalid got sent, we
43158 // should ignore it, as basically that interface element will not show up
43159 // and that should be pretty obvious!!
43162 if (Roo.form[ar[i].xtype]) {
43164 var fe = Roo.factory(ar[i], Roo.form);
43170 fe.store.form = this;
43175 this.allItems.push(fe);
43176 if (fe.items && fe.addxtype) {
43177 fe.addxtype.apply(fe, fe.items);
43187 // console.log('adding ' + ar[i].xtype);
43189 if (ar[i].xtype == 'Button') {
43190 //console.log('adding button');
43191 //console.log(ar[i]);
43192 this.addButton(ar[i]);
43193 this.allItems.push(fe);
43197 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
43198 alert('end is not supported on xtype any more, use items');
43200 // //console.log('adding end');
43208 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
43209 * option "monitorValid"
43211 startMonitoring : function(){
43214 Roo.TaskMgr.start({
43215 run : this.bindHandler,
43216 interval : this.monitorPoll || 200,
43223 * Stops monitoring of the valid state of this form
43225 stopMonitoring : function(){
43226 this.bound = false;
43230 bindHandler : function(){
43232 return false; // stops binding
43235 this.items.each(function(f){
43236 if(!f.isValid(true)){
43241 for(var i = 0, len = this.buttons.length; i < len; i++){
43242 var btn = this.buttons[i];
43243 if(btn.formBind === true && btn.disabled === valid){
43244 btn.setDisabled(!valid);
43247 this.fireEvent('clientvalidation', this, valid);
43261 Roo.Form = Roo.form.Form;
43264 * Ext JS Library 1.1.1
43265 * Copyright(c) 2006-2007, Ext JS, LLC.
43267 * Originally Released Under LGPL - original licence link has changed is not relivant.
43270 * <script type="text/javascript">
43274 * @class Roo.form.Action
43275 * Internal Class used to handle form actions
43277 * @param {Roo.form.BasicForm} el The form element or its id
43278 * @param {Object} config Configuration options
43282 // define the action interface
43283 Roo.form.Action = function(form, options){
43285 this.options = options || {};
43288 * Client Validation Failed
43291 Roo.form.Action.CLIENT_INVALID = 'client';
43293 * Server Validation Failed
43296 Roo.form.Action.SERVER_INVALID = 'server';
43298 * Connect to Server Failed
43301 Roo.form.Action.CONNECT_FAILURE = 'connect';
43303 * Reading Data from Server Failed
43306 Roo.form.Action.LOAD_FAILURE = 'load';
43308 Roo.form.Action.prototype = {
43310 failureType : undefined,
43311 response : undefined,
43312 result : undefined,
43314 // interface method
43315 run : function(options){
43319 // interface method
43320 success : function(response){
43324 // interface method
43325 handleResponse : function(response){
43329 // default connection failure
43330 failure : function(response){
43332 this.response = response;
43333 this.failureType = Roo.form.Action.CONNECT_FAILURE;
43334 this.form.afterAction(this, false);
43337 processResponse : function(response){
43338 this.response = response;
43339 if(!response.responseText){
43342 this.result = this.handleResponse(response);
43343 return this.result;
43346 // utility functions used internally
43347 getUrl : function(appendParams){
43348 var url = this.options.url || this.form.url || this.form.el.dom.action;
43350 var p = this.getParams();
43352 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
43358 getMethod : function(){
43359 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
43362 getParams : function(){
43363 var bp = this.form.baseParams;
43364 var p = this.options.params;
43366 if(typeof p == "object"){
43367 p = Roo.urlEncode(Roo.applyIf(p, bp));
43368 }else if(typeof p == 'string' && bp){
43369 p += '&' + Roo.urlEncode(bp);
43372 p = Roo.urlEncode(bp);
43377 createCallback : function(){
43379 success: this.success,
43380 failure: this.failure,
43382 timeout: (this.form.timeout*1000),
43383 upload: this.form.fileUpload ? this.success : undefined
43388 Roo.form.Action.Submit = function(form, options){
43389 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
43392 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
43395 haveProgress : false,
43396 uploadComplete : false,
43398 // uploadProgress indicator.
43399 uploadProgress : function()
43401 if (!this.form.progressUrl) {
43405 if (!this.haveProgress) {
43406 Roo.MessageBox.progress("Uploading", "Uploading");
43408 if (this.uploadComplete) {
43409 Roo.MessageBox.hide();
43413 this.haveProgress = true;
43415 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
43417 var c = new Roo.data.Connection();
43419 url : this.form.progressUrl,
43424 success : function(req){
43425 //console.log(data);
43429 rdata = Roo.decode(req.responseText)
43431 Roo.log("Invalid data from server..");
43435 if (!rdata || !rdata.success) {
43439 var data = rdata.data;
43441 if (this.uploadComplete) {
43442 Roo.MessageBox.hide();
43447 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
43448 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
43451 this.uploadProgress.defer(2000,this);
43454 failure: function(data) {
43455 Roo.log('progress url failed ');
43466 // run get Values on the form, so it syncs any secondary forms.
43467 this.form.getValues();
43469 var o = this.options;
43470 var method = this.getMethod();
43471 var isPost = method == 'POST';
43472 if(o.clientValidation === false || this.form.isValid()){
43474 if (this.form.progressUrl) {
43475 this.form.findField('UPLOAD_IDENTIFIER').setValue(
43476 (new Date() * 1) + '' + Math.random());
43481 Roo.Ajax.request(Roo.apply(this.createCallback(), {
43482 form:this.form.el.dom,
43483 url:this.getUrl(!isPost),
43485 params:isPost ? this.getParams() : null,
43486 isUpload: this.form.fileUpload
43489 this.uploadProgress();
43491 }else if (o.clientValidation !== false){ // client validation failed
43492 this.failureType = Roo.form.Action.CLIENT_INVALID;
43493 this.form.afterAction(this, false);
43497 success : function(response)
43499 this.uploadComplete= true;
43500 if (this.haveProgress) {
43501 Roo.MessageBox.hide();
43505 var result = this.processResponse(response);
43506 if(result === true || result.success){
43507 this.form.afterAction(this, true);
43511 this.form.markInvalid(result.errors);
43512 this.failureType = Roo.form.Action.SERVER_INVALID;
43514 this.form.afterAction(this, false);
43516 failure : function(response)
43518 this.uploadComplete= true;
43519 if (this.haveProgress) {
43520 Roo.MessageBox.hide();
43523 this.response = response;
43524 this.failureType = Roo.form.Action.CONNECT_FAILURE;
43525 this.form.afterAction(this, false);
43528 handleResponse : function(response){
43529 if(this.form.errorReader){
43530 var rs = this.form.errorReader.read(response);
43533 for(var i = 0, len = rs.records.length; i < len; i++) {
43534 var r = rs.records[i];
43535 errors[i] = r.data;
43538 if(errors.length < 1){
43542 success : rs.success,
43548 ret = Roo.decode(response.responseText);
43552 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
43562 Roo.form.Action.Load = function(form, options){
43563 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
43564 this.reader = this.form.reader;
43567 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
43572 Roo.Ajax.request(Roo.apply(
43573 this.createCallback(), {
43574 method:this.getMethod(),
43575 url:this.getUrl(false),
43576 params:this.getParams()
43580 success : function(response){
43582 var result = this.processResponse(response);
43583 if(result === true || !result.success || !result.data){
43584 this.failureType = Roo.form.Action.LOAD_FAILURE;
43585 this.form.afterAction(this, false);
43588 this.form.clearInvalid();
43589 this.form.setValues(result.data);
43590 this.form.afterAction(this, true);
43593 handleResponse : function(response){
43594 if(this.form.reader){
43595 var rs = this.form.reader.read(response);
43596 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
43598 success : rs.success,
43602 return Roo.decode(response.responseText);
43606 Roo.form.Action.ACTION_TYPES = {
43607 'load' : Roo.form.Action.Load,
43608 'submit' : Roo.form.Action.Submit
43611 * Ext JS Library 1.1.1
43612 * Copyright(c) 2006-2007, Ext JS, LLC.
43614 * Originally Released Under LGPL - original licence link has changed is not relivant.
43617 * <script type="text/javascript">
43621 * @class Roo.form.Layout
43622 * @extends Roo.Component
43623 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
43625 * @param {Object} config Configuration options
43627 Roo.form.Layout = function(config){
43629 if (config.items) {
43630 xitems = config.items;
43631 delete config.items;
43633 Roo.form.Layout.superclass.constructor.call(this, config);
43635 Roo.each(xitems, this.addxtype, this);
43639 Roo.extend(Roo.form.Layout, Roo.Component, {
43641 * @cfg {String/Object} autoCreate
43642 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
43645 * @cfg {String/Object/Function} style
43646 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
43647 * a function which returns such a specification.
43650 * @cfg {String} labelAlign
43651 * Valid values are "left," "top" and "right" (defaults to "left")
43654 * @cfg {Number} labelWidth
43655 * Fixed width in pixels of all field labels (defaults to undefined)
43658 * @cfg {Boolean} clear
43659 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
43663 * @cfg {String} labelSeparator
43664 * The separator to use after field labels (defaults to ':')
43666 labelSeparator : ':',
43668 * @cfg {Boolean} hideLabels
43669 * True to suppress the display of field labels in this layout (defaults to false)
43671 hideLabels : false,
43674 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
43679 onRender : function(ct, position){
43680 if(this.el){ // from markup
43681 this.el = Roo.get(this.el);
43682 }else { // generate
43683 var cfg = this.getAutoCreate();
43684 this.el = ct.createChild(cfg, position);
43687 this.el.applyStyles(this.style);
43689 if(this.labelAlign){
43690 this.el.addClass('x-form-label-'+this.labelAlign);
43692 if(this.hideLabels){
43693 this.labelStyle = "display:none";
43694 this.elementStyle = "padding-left:0;";
43696 if(typeof this.labelWidth == 'number'){
43697 this.labelStyle = "width:"+this.labelWidth+"px;";
43698 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
43700 if(this.labelAlign == 'top'){
43701 this.labelStyle = "width:auto;";
43702 this.elementStyle = "padding-left:0;";
43705 var stack = this.stack;
43706 var slen = stack.length;
43708 if(!this.fieldTpl){
43709 var t = new Roo.Template(
43710 '<div class="x-form-item {5}">',
43711 '<label for="{0}" style="{2}">{1}{4}</label>',
43712 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
43714 '</div><div class="x-form-clear-left"></div>'
43716 t.disableFormats = true;
43718 Roo.form.Layout.prototype.fieldTpl = t;
43720 for(var i = 0; i < slen; i++) {
43721 if(stack[i].isFormField){
43722 this.renderField(stack[i]);
43724 this.renderComponent(stack[i]);
43729 this.el.createChild({cls:'x-form-clear'});
43734 renderField : function(f){
43735 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
43738 f.labelStyle||this.labelStyle||'', //2
43739 this.elementStyle||'', //3
43740 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
43741 f.itemCls||this.itemCls||'' //5
43742 ], true).getPrevSibling());
43746 renderComponent : function(c){
43747 c.render(c.isLayout ? this.el : this.el.createChild());
43750 * Adds a object form elements (using the xtype property as the factory method.)
43751 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
43752 * @param {Object} config
43754 addxtype : function(o)
43756 // create the lement.
43757 o.form = this.form;
43758 var fe = Roo.factory(o, Roo.form);
43759 this.form.allItems.push(fe);
43760 this.stack.push(fe);
43762 if (fe.isFormField) {
43763 this.form.items.add(fe);
43771 * @class Roo.form.Column
43772 * @extends Roo.form.Layout
43773 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
43775 * @param {Object} config Configuration options
43777 Roo.form.Column = function(config){
43778 Roo.form.Column.superclass.constructor.call(this, config);
43781 Roo.extend(Roo.form.Column, Roo.form.Layout, {
43783 * @cfg {Number/String} width
43784 * The fixed width of the column in pixels or CSS value (defaults to "auto")
43787 * @cfg {String/Object} autoCreate
43788 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
43792 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
43795 onRender : function(ct, position){
43796 Roo.form.Column.superclass.onRender.call(this, ct, position);
43798 this.el.setWidth(this.width);
43805 * @class Roo.form.Row
43806 * @extends Roo.form.Layout
43807 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
43809 * @param {Object} config Configuration options
43813 Roo.form.Row = function(config){
43814 Roo.form.Row.superclass.constructor.call(this, config);
43817 Roo.extend(Roo.form.Row, Roo.form.Layout, {
43819 * @cfg {Number/String} width
43820 * The fixed width of the column in pixels or CSS value (defaults to "auto")
43823 * @cfg {Number/String} height
43824 * The fixed height of the column in pixels or CSS value (defaults to "auto")
43826 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
43830 onRender : function(ct, position){
43831 //console.log('row render');
43833 var t = new Roo.Template(
43834 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
43835 '<label for="{0}" style="{2}">{1}{4}</label>',
43836 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
43840 t.disableFormats = true;
43842 Roo.form.Layout.prototype.rowTpl = t;
43844 this.fieldTpl = this.rowTpl;
43846 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
43847 var labelWidth = 100;
43849 if ((this.labelAlign != 'top')) {
43850 if (typeof this.labelWidth == 'number') {
43851 labelWidth = this.labelWidth
43853 this.padWidth = 20 + labelWidth;
43857 Roo.form.Column.superclass.onRender.call(this, ct, position);
43859 this.el.setWidth(this.width);
43862 this.el.setHeight(this.height);
43867 renderField : function(f){
43868 f.fieldEl = this.fieldTpl.append(this.el, [
43869 f.id, f.fieldLabel,
43870 f.labelStyle||this.labelStyle||'',
43871 this.elementStyle||'',
43872 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
43873 f.itemCls||this.itemCls||'',
43874 f.width ? f.width + this.padWidth : 160 + this.padWidth
43881 * @class Roo.form.FieldSet
43882 * @extends Roo.form.Layout
43883 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
43885 * @param {Object} config Configuration options
43887 Roo.form.FieldSet = function(config){
43888 Roo.form.FieldSet.superclass.constructor.call(this, config);
43891 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
43893 * @cfg {String} legend
43894 * The text to display as the legend for the FieldSet (defaults to '')
43897 * @cfg {String/Object} autoCreate
43898 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
43902 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
43905 onRender : function(ct, position){
43906 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
43908 this.setLegend(this.legend);
43913 setLegend : function(text){
43915 this.el.child('legend').update(text);
43920 * Ext JS Library 1.1.1
43921 * Copyright(c) 2006-2007, Ext JS, LLC.
43923 * Originally Released Under LGPL - original licence link has changed is not relivant.
43926 * <script type="text/javascript">
43929 * @class Roo.form.VTypes
43930 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
43933 Roo.form.VTypes = function(){
43934 // closure these in so they are only created once.
43935 var alpha = /^[a-zA-Z_]+$/;
43936 var alphanum = /^[a-zA-Z0-9_]+$/;
43937 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
43938 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
43940 // All these messages and functions are configurable
43943 * The function used to validate email addresses
43944 * @param {String} value The email address
43946 'email' : function(v){
43947 return email.test(v);
43950 * The error text to display when the email validation function returns false
43953 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
43955 * The keystroke filter mask to be applied on email input
43958 'emailMask' : /[a-z0-9_\.\-@]/i,
43961 * The function used to validate URLs
43962 * @param {String} value The URL
43964 'url' : function(v){
43965 return url.test(v);
43968 * The error text to display when the url validation function returns false
43971 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
43974 * The function used to validate alpha values
43975 * @param {String} value The value
43977 'alpha' : function(v){
43978 return alpha.test(v);
43981 * The error text to display when the alpha validation function returns false
43984 'alphaText' : 'This field should only contain letters and _',
43986 * The keystroke filter mask to be applied on alpha input
43989 'alphaMask' : /[a-z_]/i,
43992 * The function used to validate alphanumeric values
43993 * @param {String} value The value
43995 'alphanum' : function(v){
43996 return alphanum.test(v);
43999 * The error text to display when the alphanumeric validation function returns false
44002 'alphanumText' : 'This field should only contain letters, numbers and _',
44004 * The keystroke filter mask to be applied on alphanumeric input
44007 'alphanumMask' : /[a-z0-9_]/i
44009 }();//<script type="text/javascript">
44012 * @class Roo.form.FCKeditor
44013 * @extends Roo.form.TextArea
44014 * Wrapper around the FCKEditor http://www.fckeditor.net
44016 * Creates a new FCKeditor
44017 * @param {Object} config Configuration options
44019 Roo.form.FCKeditor = function(config){
44020 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44023 * @event editorinit
44024 * Fired when the editor is initialized - you can add extra handlers here..
44025 * @param {FCKeditor} this
44026 * @param {Object} the FCK object.
44033 Roo.form.FCKeditor.editors = { };
44034 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44036 //defaultAutoCreate : {
44037 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44041 * @cfg {Object} fck options - see fck manual for details.
44046 * @cfg {Object} fck toolbar set (Basic or Default)
44048 toolbarSet : 'Basic',
44050 * @cfg {Object} fck BasePath
44052 basePath : '/fckeditor/',
44060 onRender : function(ct, position)
44063 this.defaultAutoCreate = {
44065 style:"width:300px;height:60px;",
44066 autocomplete: "off"
44069 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44072 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44073 if(this.preventScrollbars){
44074 this.el.setStyle("overflow", "hidden");
44076 this.el.setHeight(this.growMin);
44079 //console.log('onrender' + this.getId() );
44080 Roo.form.FCKeditor.editors[this.getId()] = this;
44083 this.replaceTextarea() ;
44087 getEditor : function() {
44088 return this.fckEditor;
44091 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44092 * @param {Mixed} value The value to set
44096 setValue : function(value)
44098 //console.log('setValue: ' + value);
44100 if(typeof(value) == 'undefined') { // not sure why this is happending...
44103 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44105 //if(!this.el || !this.getEditor()) {
44106 // this.value = value;
44107 //this.setValue.defer(100,this,[value]);
44111 if(!this.getEditor()) {
44115 this.getEditor().SetData(value);
44122 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44123 * @return {Mixed} value The field value
44125 getValue : function()
44128 if (this.frame && this.frame.dom.style.display == 'none') {
44129 return Roo.form.FCKeditor.superclass.getValue.call(this);
44132 if(!this.el || !this.getEditor()) {
44134 // this.getValue.defer(100,this);
44139 var value=this.getEditor().GetData();
44140 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44141 return Roo.form.FCKeditor.superclass.getValue.call(this);
44147 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44148 * @return {Mixed} value The field value
44150 getRawValue : function()
44152 if (this.frame && this.frame.dom.style.display == 'none') {
44153 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44156 if(!this.el || !this.getEditor()) {
44157 //this.getRawValue.defer(100,this);
44164 var value=this.getEditor().GetData();
44165 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44166 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44170 setSize : function(w,h) {
44174 //if (this.frame && this.frame.dom.style.display == 'none') {
44175 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44178 //if(!this.el || !this.getEditor()) {
44179 // this.setSize.defer(100,this, [w,h]);
44185 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44187 this.frame.dom.setAttribute('width', w);
44188 this.frame.dom.setAttribute('height', h);
44189 this.frame.setSize(w,h);
44193 toggleSourceEdit : function(value) {
44197 this.el.dom.style.display = value ? '' : 'none';
44198 this.frame.dom.style.display = value ? 'none' : '';
44203 focus: function(tag)
44205 if (this.frame.dom.style.display == 'none') {
44206 return Roo.form.FCKeditor.superclass.focus.call(this);
44208 if(!this.el || !this.getEditor()) {
44209 this.focus.defer(100,this, [tag]);
44216 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
44217 this.getEditor().Focus();
44219 if (!this.getEditor().Selection.GetSelection()) {
44220 this.focus.defer(100,this, [tag]);
44225 var r = this.getEditor().EditorDocument.createRange();
44226 r.setStart(tgs[0],0);
44227 r.setEnd(tgs[0],0);
44228 this.getEditor().Selection.GetSelection().removeAllRanges();
44229 this.getEditor().Selection.GetSelection().addRange(r);
44230 this.getEditor().Focus();
44237 replaceTextarea : function()
44239 if ( document.getElementById( this.getId() + '___Frame' ) )
44241 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
44243 // We must check the elements firstly using the Id and then the name.
44244 var oTextarea = document.getElementById( this.getId() );
44246 var colElementsByName = document.getElementsByName( this.getId() ) ;
44248 oTextarea.style.display = 'none' ;
44250 if ( oTextarea.tabIndex ) {
44251 this.TabIndex = oTextarea.tabIndex ;
44254 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
44255 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
44256 this.frame = Roo.get(this.getId() + '___Frame')
44259 _getConfigHtml : function()
44263 for ( var o in this.fckconfig ) {
44264 sConfig += sConfig.length > 0 ? '&' : '';
44265 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
44268 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
44272 _getIFrameHtml : function()
44274 var sFile = 'fckeditor.html' ;
44275 /* no idea what this is about..
44278 if ( (/fcksource=true/i).test( window.top.location.search ) )
44279 sFile = 'fckeditor.original.html' ;
44284 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
44285 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
44288 var html = '<iframe id="' + this.getId() +
44289 '___Frame" src="' + sLink +
44290 '" width="' + this.width +
44291 '" height="' + this.height + '"' +
44292 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
44293 ' frameborder="0" scrolling="no"></iframe>' ;
44298 _insertHtmlBefore : function( html, element )
44300 if ( element.insertAdjacentHTML ) {
44302 element.insertAdjacentHTML( 'beforeBegin', html ) ;
44304 var oRange = document.createRange() ;
44305 oRange.setStartBefore( element ) ;
44306 var oFragment = oRange.createContextualFragment( html );
44307 element.parentNode.insertBefore( oFragment, element ) ;
44320 //Roo.reg('fckeditor', Roo.form.FCKeditor);
44322 function FCKeditor_OnComplete(editorInstance){
44323 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
44324 f.fckEditor = editorInstance;
44325 //console.log("loaded");
44326 f.fireEvent('editorinit', f, editorInstance);
44346 //<script type="text/javascript">
44348 * @class Roo.form.GridField
44349 * @extends Roo.form.Field
44350 * Embed a grid (or editable grid into a form)
44353 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
44355 * xgrid.store = Roo.data.Store
44356 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
44357 * xgrid.store.reader = Roo.data.JsonReader
44361 * Creates a new GridField
44362 * @param {Object} config Configuration options
44364 Roo.form.GridField = function(config){
44365 Roo.form.GridField.superclass.constructor.call(this, config);
44369 Roo.extend(Roo.form.GridField, Roo.form.Field, {
44371 * @cfg {Number} width - used to restrict width of grid..
44375 * @cfg {Number} height - used to restrict height of grid..
44379 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
44385 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44386 * {tag: "input", type: "checkbox", autocomplete: "off"})
44388 // defaultAutoCreate : { tag: 'div' },
44389 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
44391 * @cfg {String} addTitle Text to include for adding a title.
44395 onResize : function(){
44396 Roo.form.Field.superclass.onResize.apply(this, arguments);
44399 initEvents : function(){
44400 // Roo.form.Checkbox.superclass.initEvents.call(this);
44401 // has no events...
44406 getResizeEl : function(){
44410 getPositionEl : function(){
44415 onRender : function(ct, position){
44417 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
44418 var style = this.style;
44421 Roo.form.GridField.superclass.onRender.call(this, ct, position);
44422 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
44423 this.viewEl = this.wrap.createChild({ tag: 'div' });
44425 this.viewEl.applyStyles(style);
44428 this.viewEl.setWidth(this.width);
44431 this.viewEl.setHeight(this.height);
44433 //if(this.inputValue !== undefined){
44434 //this.setValue(this.value);
44437 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
44440 this.grid.render();
44441 this.grid.getDataSource().on('remove', this.refreshValue, this);
44442 this.grid.getDataSource().on('update', this.refreshValue, this);
44443 this.grid.on('afteredit', this.refreshValue, this);
44449 * Sets the value of the item.
44450 * @param {String} either an object or a string..
44452 setValue : function(v){
44454 v = v || []; // empty set..
44455 // this does not seem smart - it really only affects memoryproxy grids..
44456 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
44457 var ds = this.grid.getDataSource();
44458 // assumes a json reader..
44460 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
44461 ds.loadData( data);
44463 // clear selection so it does not get stale.
44464 if (this.grid.sm) {
44465 this.grid.sm.clearSelections();
44468 Roo.form.GridField.superclass.setValue.call(this, v);
44469 this.refreshValue();
44470 // should load data in the grid really....
44474 refreshValue: function() {
44476 this.grid.getDataSource().each(function(r) {
44479 this.el.dom.value = Roo.encode(val);
44487 * Ext JS Library 1.1.1
44488 * Copyright(c) 2006-2007, Ext JS, LLC.
44490 * Originally Released Under LGPL - original licence link has changed is not relivant.
44493 * <script type="text/javascript">
44496 * @class Roo.form.DisplayField
44497 * @extends Roo.form.Field
44498 * A generic Field to display non-editable data.
44500 * Creates a new Display Field item.
44501 * @param {Object} config Configuration options
44503 Roo.form.DisplayField = function(config){
44504 Roo.form.DisplayField.superclass.constructor.call(this, config);
44508 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
44509 inputType: 'hidden',
44515 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44517 focusClass : undefined,
44519 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44521 fieldClass: 'x-form-field',
44524 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
44526 valueRenderer: undefined,
44530 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44531 * {tag: "input", type: "checkbox", autocomplete: "off"})
44534 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
44536 onResize : function(){
44537 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
44541 initEvents : function(){
44542 // Roo.form.Checkbox.superclass.initEvents.call(this);
44543 // has no events...
44548 getResizeEl : function(){
44552 getPositionEl : function(){
44557 onRender : function(ct, position){
44559 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
44560 //if(this.inputValue !== undefined){
44561 this.wrap = this.el.wrap();
44563 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
44565 if (this.bodyStyle) {
44566 this.viewEl.applyStyles(this.bodyStyle);
44568 //this.viewEl.setStyle('padding', '2px');
44570 this.setValue(this.value);
44575 initValue : Roo.emptyFn,
44580 onClick : function(){
44585 * Sets the checked state of the checkbox.
44586 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
44588 setValue : function(v){
44590 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
44591 // this might be called before we have a dom element..
44592 if (!this.viewEl) {
44595 this.viewEl.dom.innerHTML = html;
44596 Roo.form.DisplayField.superclass.setValue.call(this, v);
44606 * @class Roo.form.DayPicker
44607 * @extends Roo.form.Field
44608 * A Day picker show [M] [T] [W] ....
44610 * Creates a new Day Picker
44611 * @param {Object} config Configuration options
44613 Roo.form.DayPicker= function(config){
44614 Roo.form.DayPicker.superclass.constructor.call(this, config);
44618 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
44620 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44622 focusClass : undefined,
44624 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44626 fieldClass: "x-form-field",
44629 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44630 * {tag: "input", type: "checkbox", autocomplete: "off"})
44632 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
44635 actionMode : 'viewEl',
44639 inputType : 'hidden',
44642 inputElement: false, // real input element?
44643 basedOn: false, // ????
44645 isFormField: true, // not sure where this is needed!!!!
44647 onResize : function(){
44648 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
44649 if(!this.boxLabel){
44650 this.el.alignTo(this.wrap, 'c-c');
44654 initEvents : function(){
44655 Roo.form.Checkbox.superclass.initEvents.call(this);
44656 this.el.on("click", this.onClick, this);
44657 this.el.on("change", this.onClick, this);
44661 getResizeEl : function(){
44665 getPositionEl : function(){
44671 onRender : function(ct, position){
44672 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44674 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
44676 var r1 = '<table><tr>';
44677 var r2 = '<tr class="x-form-daypick-icons">';
44678 for (var i=0; i < 7; i++) {
44679 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
44680 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
44683 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
44684 viewEl.select('img').on('click', this.onClick, this);
44685 this.viewEl = viewEl;
44688 // this will not work on Chrome!!!
44689 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44690 this.el.on('propertychange', this.setFromHidden, this); //ie
44698 initValue : Roo.emptyFn,
44701 * Returns the checked state of the checkbox.
44702 * @return {Boolean} True if checked, else false
44704 getValue : function(){
44705 return this.el.dom.value;
44710 onClick : function(e){
44711 //this.setChecked(!this.checked);
44712 Roo.get(e.target).toggleClass('x-menu-item-checked');
44713 this.refreshValue();
44714 //if(this.el.dom.checked != this.checked){
44715 // this.setValue(this.el.dom.checked);
44720 refreshValue : function()
44723 this.viewEl.select('img',true).each(function(e,i,n) {
44724 val += e.is(".x-menu-item-checked") ? String(n) : '';
44726 this.setValue(val, true);
44730 * Sets the checked state of the checkbox.
44731 * On is always based on a string comparison between inputValue and the param.
44732 * @param {Boolean/String} value - the value to set
44733 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
44735 setValue : function(v,suppressEvent){
44736 if (!this.el.dom) {
44739 var old = this.el.dom.value ;
44740 this.el.dom.value = v;
44741 if (suppressEvent) {
44745 // update display..
44746 this.viewEl.select('img',true).each(function(e,i,n) {
44748 var on = e.is(".x-menu-item-checked");
44749 var newv = v.indexOf(String(n)) > -1;
44751 e.toggleClass('x-menu-item-checked');
44757 this.fireEvent('change', this, v, old);
44762 // handle setting of hidden value by some other method!!?!?
44763 setFromHidden: function()
44768 //console.log("SET FROM HIDDEN");
44769 //alert('setFrom hidden');
44770 this.setValue(this.el.dom.value);
44773 onDestroy : function()
44776 Roo.get(this.viewEl).remove();
44779 Roo.form.DayPicker.superclass.onDestroy.call(this);
44783 * RooJS Library 1.1.1
44784 * Copyright(c) 2008-2011 Alan Knowles
44791 * @class Roo.form.ComboCheck
44792 * @extends Roo.form.ComboBox
44793 * A combobox for multiple select items.
44795 * FIXME - could do with a reset button..
44798 * Create a new ComboCheck
44799 * @param {Object} config Configuration options
44801 Roo.form.ComboCheck = function(config){
44802 Roo.form.ComboCheck.superclass.constructor.call(this, config);
44803 // should verify some data...
44805 // hiddenName = required..
44806 // displayField = required
44807 // valudField == required
44808 var req= [ 'hiddenName', 'displayField', 'valueField' ];
44810 Roo.each(req, function(e) {
44811 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
44812 throw "Roo.form.ComboCheck : missing value for: " + e;
44819 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
44824 selectedClass: 'x-menu-item-checked',
44827 onRender : function(ct, position){
44833 var cls = 'x-combo-list';
44836 this.tpl = new Roo.Template({
44837 html : '<div class="'+cls+'-item x-menu-check-item">' +
44838 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
44839 '<span>{' + this.displayField + '}</span>' +
44846 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
44847 this.view.singleSelect = false;
44848 this.view.multiSelect = true;
44849 this.view.toggleSelect = true;
44850 this.pageTb.add(new Roo.Toolbar.Fill(), {
44853 handler: function()
44860 onViewOver : function(e, t){
44866 onViewClick : function(doFocus,index){
44870 select: function () {
44871 //Roo.log("SELECT CALLED");
44874 selectByValue : function(xv, scrollIntoView){
44875 var ar = this.getValueArray();
44878 Roo.each(ar, function(v) {
44879 if(v === undefined || v === null){
44882 var r = this.findRecord(this.valueField, v);
44884 sels.push(this.store.indexOf(r))
44888 this.view.select(sels);
44894 onSelect : function(record, index){
44895 // Roo.log("onselect Called");
44896 // this is only called by the clear button now..
44897 this.view.clearSelections();
44898 this.setValue('[]');
44899 if (this.value != this.valueBefore) {
44900 this.fireEvent('change', this, this.value, this.valueBefore);
44903 getValueArray : function()
44908 //Roo.log(this.value);
44909 if (typeof(this.value) == 'undefined') {
44912 var ar = Roo.decode(this.value);
44913 return ar instanceof Array ? ar : []; //?? valid?
44916 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
44921 expand : function ()
44923 Roo.form.ComboCheck.superclass.expand.call(this);
44924 this.valueBefore = this.value;
44929 collapse : function(){
44930 Roo.form.ComboCheck.superclass.collapse.call(this);
44931 var sl = this.view.getSelectedIndexes();
44932 var st = this.store;
44936 Roo.each(sl, function(i) {
44938 nv.push(r.get(this.valueField));
44940 this.setValue(Roo.encode(nv));
44941 if (this.value != this.valueBefore) {
44943 this.fireEvent('change', this, this.value, this.valueBefore);
44948 setValue : function(v){
44952 var vals = this.getValueArray();
44954 Roo.each(vals, function(k) {
44955 var r = this.findRecord(this.valueField, k);
44957 tv.push(r.data[this.displayField]);
44958 }else if(this.valueNotFoundText !== undefined){
44959 tv.push( this.valueNotFoundText );
44964 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
44965 this.hiddenField.value = v;
44969 });//<script type="text/javasscript">
44973 * @class Roo.DDView
44974 * A DnD enabled version of Roo.View.
44975 * @param {Element/String} container The Element in which to create the View.
44976 * @param {String} tpl The template string used to create the markup for each element of the View
44977 * @param {Object} config The configuration properties. These include all the config options of
44978 * {@link Roo.View} plus some specific to this class.<br>
44980 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
44981 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
44983 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
44984 .x-view-drag-insert-above {
44985 border-top:1px dotted #3366cc;
44987 .x-view-drag-insert-below {
44988 border-bottom:1px dotted #3366cc;
44994 Roo.DDView = function(container, tpl, config) {
44995 Roo.DDView.superclass.constructor.apply(this, arguments);
44996 this.getEl().setStyle("outline", "0px none");
44997 this.getEl().unselectable();
44998 if (this.dragGroup) {
44999 this.setDraggable(this.dragGroup.split(","));
45001 if (this.dropGroup) {
45002 this.setDroppable(this.dropGroup.split(","));
45004 if (this.deletable) {
45005 this.setDeletable();
45007 this.isDirtyFlag = false;
45013 Roo.extend(Roo.DDView, Roo.View, {
45014 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
45015 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
45016 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
45017 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
45021 reset: Roo.emptyFn,
45023 clearInvalid: Roo.form.Field.prototype.clearInvalid,
45025 validate: function() {
45029 destroy: function() {
45030 this.purgeListeners();
45031 this.getEl.removeAllListeners();
45032 this.getEl().remove();
45033 if (this.dragZone) {
45034 if (this.dragZone.destroy) {
45035 this.dragZone.destroy();
45038 if (this.dropZone) {
45039 if (this.dropZone.destroy) {
45040 this.dropZone.destroy();
45045 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
45046 getName: function() {
45050 /** Loads the View from a JSON string representing the Records to put into the Store. */
45051 setValue: function(v) {
45053 throw "DDView.setValue(). DDView must be constructed with a valid Store";
45056 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
45057 this.store.proxy = new Roo.data.MemoryProxy(data);
45061 /** @return {String} a parenthesised list of the ids of the Records in the View. */
45062 getValue: function() {
45064 this.store.each(function(rec) {
45065 result += rec.id + ',';
45067 return result.substr(0, result.length - 1) + ')';
45070 getIds: function() {
45071 var i = 0, result = new Array(this.store.getCount());
45072 this.store.each(function(rec) {
45073 result[i++] = rec.id;
45078 isDirty: function() {
45079 return this.isDirtyFlag;
45083 * Part of the Roo.dd.DropZone interface. If no target node is found, the
45084 * whole Element becomes the target, and this causes the drop gesture to append.
45086 getTargetFromEvent : function(e) {
45087 var target = e.getTarget();
45088 while ((target !== null) && (target.parentNode != this.el.dom)) {
45089 target = target.parentNode;
45092 target = this.el.dom.lastChild || this.el.dom;
45098 * Create the drag data which consists of an object which has the property "ddel" as
45099 * the drag proxy element.
45101 getDragData : function(e) {
45102 var target = this.findItemFromChild(e.getTarget());
45104 this.handleSelection(e);
45105 var selNodes = this.getSelectedNodes();
45108 copy: this.copy || (this.allowCopy && e.ctrlKey),
45112 var selectedIndices = this.getSelectedIndexes();
45113 for (var i = 0; i < selectedIndices.length; i++) {
45114 dragData.records.push(this.store.getAt(selectedIndices[i]));
45116 if (selNodes.length == 1) {
45117 dragData.ddel = target.cloneNode(true); // the div element
45119 var div = document.createElement('div'); // create the multi element drag "ghost"
45120 div.className = 'multi-proxy';
45121 for (var i = 0, len = selNodes.length; i < len; i++) {
45122 div.appendChild(selNodes[i].cloneNode(true));
45124 dragData.ddel = div;
45126 //console.log(dragData)
45127 //console.log(dragData.ddel.innerHTML)
45130 //console.log('nodragData')
45134 /** Specify to which ddGroup items in this DDView may be dragged. */
45135 setDraggable: function(ddGroup) {
45136 if (ddGroup instanceof Array) {
45137 Roo.each(ddGroup, this.setDraggable, this);
45140 if (this.dragZone) {
45141 this.dragZone.addToGroup(ddGroup);
45143 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
45144 containerScroll: true,
45148 // Draggability implies selection. DragZone's mousedown selects the element.
45149 if (!this.multiSelect) { this.singleSelect = true; }
45151 // Wire the DragZone's handlers up to methods in *this*
45152 this.dragZone.getDragData = this.getDragData.createDelegate(this);
45156 /** Specify from which ddGroup this DDView accepts drops. */
45157 setDroppable: function(ddGroup) {
45158 if (ddGroup instanceof Array) {
45159 Roo.each(ddGroup, this.setDroppable, this);
45162 if (this.dropZone) {
45163 this.dropZone.addToGroup(ddGroup);
45165 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
45166 containerScroll: true,
45170 // Wire the DropZone's handlers up to methods in *this*
45171 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
45172 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
45173 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
45174 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
45175 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
45179 /** Decide whether to drop above or below a View node. */
45180 getDropPoint : function(e, n, dd){
45181 if (n == this.el.dom) { return "above"; }
45182 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
45183 var c = t + (b - t) / 2;
45184 var y = Roo.lib.Event.getPageY(e);
45192 onNodeEnter : function(n, dd, e, data){
45196 onNodeOver : function(n, dd, e, data){
45197 var pt = this.getDropPoint(e, n, dd);
45198 // set the insert point style on the target node
45199 var dragElClass = this.dropNotAllowed;
45202 if (pt == "above"){
45203 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
45204 targetElClass = "x-view-drag-insert-above";
45206 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
45207 targetElClass = "x-view-drag-insert-below";
45209 if (this.lastInsertClass != targetElClass){
45210 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
45211 this.lastInsertClass = targetElClass;
45214 return dragElClass;
45217 onNodeOut : function(n, dd, e, data){
45218 this.removeDropIndicators(n);
45221 onNodeDrop : function(n, dd, e, data){
45222 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
45225 var pt = this.getDropPoint(e, n, dd);
45226 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
45227 if (pt == "below") { insertAt++; }
45228 for (var i = 0; i < data.records.length; i++) {
45229 var r = data.records[i];
45230 var dup = this.store.getById(r.id);
45231 if (dup && (dd != this.dragZone)) {
45232 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
45235 this.store.insert(insertAt++, r.copy());
45237 data.source.isDirtyFlag = true;
45239 this.store.insert(insertAt++, r);
45241 this.isDirtyFlag = true;
45244 this.dragZone.cachedTarget = null;
45248 removeDropIndicators : function(n){
45250 Roo.fly(n).removeClass([
45251 "x-view-drag-insert-above",
45252 "x-view-drag-insert-below"]);
45253 this.lastInsertClass = "_noclass";
45258 * Utility method. Add a delete option to the DDView's context menu.
45259 * @param {String} imageUrl The URL of the "delete" icon image.
45261 setDeletable: function(imageUrl) {
45262 if (!this.singleSelect && !this.multiSelect) {
45263 this.singleSelect = true;
45265 var c = this.getContextMenu();
45266 this.contextMenu.on("itemclick", function(item) {
45269 this.remove(this.getSelectedIndexes());
45273 this.contextMenu.add({
45280 /** Return the context menu for this DDView. */
45281 getContextMenu: function() {
45282 if (!this.contextMenu) {
45283 // Create the View's context menu
45284 this.contextMenu = new Roo.menu.Menu({
45285 id: this.id + "-contextmenu"
45287 this.el.on("contextmenu", this.showContextMenu, this);
45289 return this.contextMenu;
45292 disableContextMenu: function() {
45293 if (this.contextMenu) {
45294 this.el.un("contextmenu", this.showContextMenu, this);
45298 showContextMenu: function(e, item) {
45299 item = this.findItemFromChild(e.getTarget());
45302 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
45303 this.contextMenu.showAt(e.getXY());
45308 * Remove {@link Roo.data.Record}s at the specified indices.
45309 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
45311 remove: function(selectedIndices) {
45312 selectedIndices = [].concat(selectedIndices);
45313 for (var i = 0; i < selectedIndices.length; i++) {
45314 var rec = this.store.getAt(selectedIndices[i]);
45315 this.store.remove(rec);
45320 * Double click fires the event, but also, if this is draggable, and there is only one other
45321 * related DropZone, it transfers the selected node.
45323 onDblClick : function(e){
45324 var item = this.findItemFromChild(e.getTarget());
45326 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
45329 if (this.dragGroup) {
45330 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
45331 while (targets.indexOf(this.dropZone) > -1) {
45332 targets.remove(this.dropZone);
45334 if (targets.length == 1) {
45335 this.dragZone.cachedTarget = null;
45336 var el = Roo.get(targets[0].getEl());
45337 var box = el.getBox(true);
45338 targets[0].onNodeDrop(el.dom, {
45340 xy: [box.x, box.y + box.height - 1]
45341 }, null, this.getDragData(e));
45347 handleSelection: function(e) {
45348 this.dragZone.cachedTarget = null;
45349 var item = this.findItemFromChild(e.getTarget());
45351 this.clearSelections(true);
45354 if (item && (this.multiSelect || this.singleSelect)){
45355 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
45356 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
45357 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
45358 this.unselect(item);
45360 this.select(item, this.multiSelect && e.ctrlKey);
45361 this.lastSelection = item;
45366 onItemClick : function(item, index, e){
45367 if(this.fireEvent("beforeclick", this, index, item, e) === false){
45373 unselect : function(nodeInfo, suppressEvent){
45374 var node = this.getNode(nodeInfo);
45375 if(node && this.isSelected(node)){
45376 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
45377 Roo.fly(node).removeClass(this.selectedClass);
45378 this.selections.remove(node);
45379 if(!suppressEvent){
45380 this.fireEvent("selectionchange", this, this.selections);
45388 * Ext JS Library 1.1.1
45389 * Copyright(c) 2006-2007, Ext JS, LLC.
45391 * Originally Released Under LGPL - original licence link has changed is not relivant.
45394 * <script type="text/javascript">
45398 * @class Roo.LayoutManager
45399 * @extends Roo.util.Observable
45400 * Base class for layout managers.
45402 Roo.LayoutManager = function(container, config){
45403 Roo.LayoutManager.superclass.constructor.call(this);
45404 this.el = Roo.get(container);
45405 // ie scrollbar fix
45406 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
45407 document.body.scroll = "no";
45408 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
45409 this.el.position('relative');
45411 this.id = this.el.id;
45412 this.el.addClass("x-layout-container");
45413 /** false to disable window resize monitoring @type Boolean */
45414 this.monitorWindowResize = true;
45419 * Fires when a layout is performed.
45420 * @param {Roo.LayoutManager} this
45424 * @event regionresized
45425 * Fires when the user resizes a region.
45426 * @param {Roo.LayoutRegion} region The resized region
45427 * @param {Number} newSize The new size (width for east/west, height for north/south)
45429 "regionresized" : true,
45431 * @event regioncollapsed
45432 * Fires when a region is collapsed.
45433 * @param {Roo.LayoutRegion} region The collapsed region
45435 "regioncollapsed" : true,
45437 * @event regionexpanded
45438 * Fires when a region is expanded.
45439 * @param {Roo.LayoutRegion} region The expanded region
45441 "regionexpanded" : true
45443 this.updating = false;
45444 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
45447 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
45449 * Returns true if this layout is currently being updated
45450 * @return {Boolean}
45452 isUpdating : function(){
45453 return this.updating;
45457 * Suspend the LayoutManager from doing auto-layouts while
45458 * making multiple add or remove calls
45460 beginUpdate : function(){
45461 this.updating = true;
45465 * Restore auto-layouts and optionally disable the manager from performing a layout
45466 * @param {Boolean} noLayout true to disable a layout update
45468 endUpdate : function(noLayout){
45469 this.updating = false;
45475 layout: function(){
45479 onRegionResized : function(region, newSize){
45480 this.fireEvent("regionresized", region, newSize);
45484 onRegionCollapsed : function(region){
45485 this.fireEvent("regioncollapsed", region);
45488 onRegionExpanded : function(region){
45489 this.fireEvent("regionexpanded", region);
45493 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
45494 * performs box-model adjustments.
45495 * @return {Object} The size as an object {width: (the width), height: (the height)}
45497 getViewSize : function(){
45499 if(this.el.dom != document.body){
45500 size = this.el.getSize();
45502 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
45504 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
45505 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
45510 * Returns the Element this layout is bound to.
45511 * @return {Roo.Element}
45513 getEl : function(){
45518 * Returns the specified region.
45519 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
45520 * @return {Roo.LayoutRegion}
45522 getRegion : function(target){
45523 return this.regions[target.toLowerCase()];
45526 onWindowResize : function(){
45527 if(this.monitorWindowResize){
45533 * Ext JS Library 1.1.1
45534 * Copyright(c) 2006-2007, Ext JS, LLC.
45536 * Originally Released Under LGPL - original licence link has changed is not relivant.
45539 * <script type="text/javascript">
45542 * @class Roo.BorderLayout
45543 * @extends Roo.LayoutManager
45544 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
45545 * please see: <br><br>
45546 * <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>
45547 * <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>
45550 var layout = new Roo.BorderLayout(document.body, {
45584 preferredTabWidth: 150
45589 var CP = Roo.ContentPanel;
45591 layout.beginUpdate();
45592 layout.add("north", new CP("north", "North"));
45593 layout.add("south", new CP("south", {title: "South", closable: true}));
45594 layout.add("west", new CP("west", {title: "West"}));
45595 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
45596 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
45597 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
45598 layout.getRegion("center").showPanel("center1");
45599 layout.endUpdate();
45602 <b>The container the layout is rendered into can be either the body element or any other element.
45603 If it is not the body element, the container needs to either be an absolute positioned element,
45604 or you will need to add "position:relative" to the css of the container. You will also need to specify
45605 the container size if it is not the body element.</b>
45608 * Create a new BorderLayout
45609 * @param {String/HTMLElement/Element} container The container this layout is bound to
45610 * @param {Object} config Configuration options
45612 Roo.BorderLayout = function(container, config){
45613 config = config || {};
45614 Roo.BorderLayout.superclass.constructor.call(this, container, config);
45615 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
45616 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
45617 var target = this.factory.validRegions[i];
45618 if(config[target]){
45619 this.addRegion(target, config[target]);
45624 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
45626 * Creates and adds a new region if it doesn't already exist.
45627 * @param {String} target The target region key (north, south, east, west or center).
45628 * @param {Object} config The regions config object
45629 * @return {BorderLayoutRegion} The new region
45631 addRegion : function(target, config){
45632 if(!this.regions[target]){
45633 var r = this.factory.create(target, this, config);
45634 this.bindRegion(target, r);
45636 return this.regions[target];
45640 bindRegion : function(name, r){
45641 this.regions[name] = r;
45642 r.on("visibilitychange", this.layout, this);
45643 r.on("paneladded", this.layout, this);
45644 r.on("panelremoved", this.layout, this);
45645 r.on("invalidated", this.layout, this);
45646 r.on("resized", this.onRegionResized, this);
45647 r.on("collapsed", this.onRegionCollapsed, this);
45648 r.on("expanded", this.onRegionExpanded, this);
45652 * Performs a layout update.
45654 layout : function(){
45655 if(this.updating) return;
45656 var size = this.getViewSize();
45657 var w = size.width;
45658 var h = size.height;
45663 //var x = 0, y = 0;
45665 var rs = this.regions;
45666 var north = rs["north"];
45667 var south = rs["south"];
45668 var west = rs["west"];
45669 var east = rs["east"];
45670 var center = rs["center"];
45671 //if(this.hideOnLayout){ // not supported anymore
45672 //c.el.setStyle("display", "none");
45674 if(north && north.isVisible()){
45675 var b = north.getBox();
45676 var m = north.getMargins();
45677 b.width = w - (m.left+m.right);
45680 centerY = b.height + b.y + m.bottom;
45681 centerH -= centerY;
45682 north.updateBox(this.safeBox(b));
45684 if(south && south.isVisible()){
45685 var b = south.getBox();
45686 var m = south.getMargins();
45687 b.width = w - (m.left+m.right);
45689 var totalHeight = (b.height + m.top + m.bottom);
45690 b.y = h - totalHeight + m.top;
45691 centerH -= totalHeight;
45692 south.updateBox(this.safeBox(b));
45694 if(west && west.isVisible()){
45695 var b = west.getBox();
45696 var m = west.getMargins();
45697 b.height = centerH - (m.top+m.bottom);
45699 b.y = centerY + m.top;
45700 var totalWidth = (b.width + m.left + m.right);
45701 centerX += totalWidth;
45702 centerW -= totalWidth;
45703 west.updateBox(this.safeBox(b));
45705 if(east && east.isVisible()){
45706 var b = east.getBox();
45707 var m = east.getMargins();
45708 b.height = centerH - (m.top+m.bottom);
45709 var totalWidth = (b.width + m.left + m.right);
45710 b.x = w - totalWidth + m.left;
45711 b.y = centerY + m.top;
45712 centerW -= totalWidth;
45713 east.updateBox(this.safeBox(b));
45716 var m = center.getMargins();
45718 x: centerX + m.left,
45719 y: centerY + m.top,
45720 width: centerW - (m.left+m.right),
45721 height: centerH - (m.top+m.bottom)
45723 //if(this.hideOnLayout){
45724 //center.el.setStyle("display", "block");
45726 center.updateBox(this.safeBox(centerBox));
45729 this.fireEvent("layout", this);
45733 safeBox : function(box){
45734 box.width = Math.max(0, box.width);
45735 box.height = Math.max(0, box.height);
45740 * Adds a ContentPanel (or subclass) to this layout.
45741 * @param {String} target The target region key (north, south, east, west or center).
45742 * @param {Roo.ContentPanel} panel The panel to add
45743 * @return {Roo.ContentPanel} The added panel
45745 add : function(target, panel){
45747 target = target.toLowerCase();
45748 return this.regions[target].add(panel);
45752 * Remove a ContentPanel (or subclass) to this layout.
45753 * @param {String} target The target region key (north, south, east, west or center).
45754 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
45755 * @return {Roo.ContentPanel} The removed panel
45757 remove : function(target, panel){
45758 target = target.toLowerCase();
45759 return this.regions[target].remove(panel);
45763 * Searches all regions for a panel with the specified id
45764 * @param {String} panelId
45765 * @return {Roo.ContentPanel} The panel or null if it wasn't found
45767 findPanel : function(panelId){
45768 var rs = this.regions;
45769 for(var target in rs){
45770 if(typeof rs[target] != "function"){
45771 var p = rs[target].getPanel(panelId);
45781 * Searches all regions for a panel with the specified id and activates (shows) it.
45782 * @param {String/ContentPanel} panelId The panels id or the panel itself
45783 * @return {Roo.ContentPanel} The shown panel or null
45785 showPanel : function(panelId) {
45786 var rs = this.regions;
45787 for(var target in rs){
45788 var r = rs[target];
45789 if(typeof r != "function"){
45790 if(r.hasPanel(panelId)){
45791 return r.showPanel(panelId);
45799 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
45800 * @param {Roo.state.Provider} provider (optional) An alternate state provider
45802 restoreState : function(provider){
45804 provider = Roo.state.Manager;
45806 var sm = new Roo.LayoutStateManager();
45807 sm.init(this, provider);
45811 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
45812 * object should contain properties for each region to add ContentPanels to, and each property's value should be
45813 * a valid ContentPanel config object. Example:
45815 // Create the main layout
45816 var layout = new Roo.BorderLayout('main-ct', {
45827 // Create and add multiple ContentPanels at once via configs
45830 id: 'source-files',
45832 title:'Ext Source Files',
45845 * @param {Object} regions An object containing ContentPanel configs by region name
45847 batchAdd : function(regions){
45848 this.beginUpdate();
45849 for(var rname in regions){
45850 var lr = this.regions[rname];
45852 this.addTypedPanels(lr, regions[rname]);
45859 addTypedPanels : function(lr, ps){
45860 if(typeof ps == 'string'){
45861 lr.add(new Roo.ContentPanel(ps));
45863 else if(ps instanceof Array){
45864 for(var i =0, len = ps.length; i < len; i++){
45865 this.addTypedPanels(lr, ps[i]);
45868 else if(!ps.events){ // raw config?
45870 delete ps.el; // prevent conflict
45871 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
45873 else { // panel object assumed!
45878 * Adds a xtype elements to the layout.
45882 xtype : 'ContentPanel',
45889 xtype : 'NestedLayoutPanel',
45895 items : [ ... list of content panels or nested layout panels.. ]
45899 * @param {Object} cfg Xtype definition of item to add.
45901 addxtype : function(cfg)
45903 // basically accepts a pannel...
45904 // can accept a layout region..!?!?
45905 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
45907 if (!cfg.xtype.match(/Panel$/)) {
45912 if (typeof(cfg.region) == 'undefined') {
45913 Roo.log("Failed to add Panel, region was not set");
45917 var region = cfg.region;
45923 xitems = cfg.items;
45930 case 'ContentPanel': // ContentPanel (el, cfg)
45931 case 'ScrollPanel': // ContentPanel (el, cfg)
45932 if(cfg.autoCreate) {
45933 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
45935 var el = this.el.createChild();
45936 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
45939 this.add(region, ret);
45943 case 'TreePanel': // our new panel!
45944 cfg.el = this.el.createChild();
45945 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
45946 this.add(region, ret);
45949 case 'NestedLayoutPanel':
45950 // create a new Layout (which is a Border Layout...
45951 var el = this.el.createChild();
45952 var clayout = cfg.layout;
45954 clayout.items = clayout.items || [];
45955 // replace this exitems with the clayout ones..
45956 xitems = clayout.items;
45959 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
45960 cfg.background = false;
45962 var layout = new Roo.BorderLayout(el, clayout);
45964 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
45965 //console.log('adding nested layout panel ' + cfg.toSource());
45966 this.add(region, ret);
45967 nb = {}; /// find first...
45972 // needs grid and region
45974 //var el = this.getRegion(region).el.createChild();
45975 var el = this.el.createChild();
45976 // create the grid first...
45978 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
45980 if (region == 'center' && this.active ) {
45981 cfg.background = false;
45983 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
45985 this.add(region, ret);
45986 if (cfg.background) {
45987 ret.on('activate', function(gp) {
45988 if (!gp.grid.rendered) {
46001 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
46003 // GridPanel (grid, cfg)
46006 this.beginUpdate();
46010 Roo.each(xitems, function(i) {
46011 region = nb && i.region ? i.region : false;
46013 var add = ret.addxtype(i);
46016 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
46017 if (!i.background) {
46018 abn[region] = nb[region] ;
46025 // make the last non-background panel active..
46026 //if (nb) { Roo.log(abn); }
46029 for(var r in abn) {
46030 region = this.getRegion(r);
46032 // tried using nb[r], but it does not work..
46034 region.showPanel(abn[r]);
46045 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
46046 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
46047 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
46048 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
46051 var CP = Roo.ContentPanel;
46053 var layout = Roo.BorderLayout.create({
46057 panels: [new CP("north", "North")]
46066 panels: [new CP("west", {title: "West"})]
46075 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
46084 panels: [new CP("south", {title: "South", closable: true})]
46091 preferredTabWidth: 150,
46093 new CP("center1", {title: "Close Me", closable: true}),
46094 new CP("center2", {title: "Center Panel", closable: false})
46099 layout.getRegion("center").showPanel("center1");
46104 Roo.BorderLayout.create = function(config, targetEl){
46105 var layout = new Roo.BorderLayout(targetEl || document.body, config);
46106 layout.beginUpdate();
46107 var regions = Roo.BorderLayout.RegionFactory.validRegions;
46108 for(var j = 0, jlen = regions.length; j < jlen; j++){
46109 var lr = regions[j];
46110 if(layout.regions[lr] && config[lr].panels){
46111 var r = layout.regions[lr];
46112 var ps = config[lr].panels;
46113 layout.addTypedPanels(r, ps);
46116 layout.endUpdate();
46121 Roo.BorderLayout.RegionFactory = {
46123 validRegions : ["north","south","east","west","center"],
46126 create : function(target, mgr, config){
46127 target = target.toLowerCase();
46128 if(config.lightweight || config.basic){
46129 return new Roo.BasicLayoutRegion(mgr, config, target);
46133 return new Roo.NorthLayoutRegion(mgr, config);
46135 return new Roo.SouthLayoutRegion(mgr, config);
46137 return new Roo.EastLayoutRegion(mgr, config);
46139 return new Roo.WestLayoutRegion(mgr, config);
46141 return new Roo.CenterLayoutRegion(mgr, config);
46143 throw 'Layout region "'+target+'" not supported.';
46147 * Ext JS Library 1.1.1
46148 * Copyright(c) 2006-2007, Ext JS, LLC.
46150 * Originally Released Under LGPL - original licence link has changed is not relivant.
46153 * <script type="text/javascript">
46157 * @class Roo.BasicLayoutRegion
46158 * @extends Roo.util.Observable
46159 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
46160 * and does not have a titlebar, tabs or any other features. All it does is size and position
46161 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
46163 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
46165 this.position = pos;
46168 * @scope Roo.BasicLayoutRegion
46172 * @event beforeremove
46173 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
46174 * @param {Roo.LayoutRegion} this
46175 * @param {Roo.ContentPanel} panel The panel
46176 * @param {Object} e The cancel event object
46178 "beforeremove" : true,
46180 * @event invalidated
46181 * Fires when the layout for this region is changed.
46182 * @param {Roo.LayoutRegion} this
46184 "invalidated" : true,
46186 * @event visibilitychange
46187 * Fires when this region is shown or hidden
46188 * @param {Roo.LayoutRegion} this
46189 * @param {Boolean} visibility true or false
46191 "visibilitychange" : true,
46193 * @event paneladded
46194 * Fires when a panel is added.
46195 * @param {Roo.LayoutRegion} this
46196 * @param {Roo.ContentPanel} panel The panel
46198 "paneladded" : true,
46200 * @event panelremoved
46201 * Fires when a panel is removed.
46202 * @param {Roo.LayoutRegion} this
46203 * @param {Roo.ContentPanel} panel The panel
46205 "panelremoved" : true,
46208 * Fires when this region is collapsed.
46209 * @param {Roo.LayoutRegion} this
46211 "collapsed" : true,
46214 * Fires when this region is expanded.
46215 * @param {Roo.LayoutRegion} this
46220 * Fires when this region is slid into view.
46221 * @param {Roo.LayoutRegion} this
46223 "slideshow" : true,
46226 * Fires when this region slides out of view.
46227 * @param {Roo.LayoutRegion} this
46229 "slidehide" : true,
46231 * @event panelactivated
46232 * Fires when a panel is activated.
46233 * @param {Roo.LayoutRegion} this
46234 * @param {Roo.ContentPanel} panel The activated panel
46236 "panelactivated" : true,
46239 * Fires when the user resizes this region.
46240 * @param {Roo.LayoutRegion} this
46241 * @param {Number} newSize The new size (width for east/west, height for north/south)
46245 /** A collection of panels in this region. @type Roo.util.MixedCollection */
46246 this.panels = new Roo.util.MixedCollection();
46247 this.panels.getKey = this.getPanelId.createDelegate(this);
46249 this.activePanel = null;
46250 // ensure listeners are added...
46252 if (config.listeners || config.events) {
46253 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
46254 listeners : config.listeners || {},
46255 events : config.events || {}
46259 if(skipConfig !== true){
46260 this.applyConfig(config);
46264 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
46265 getPanelId : function(p){
46269 applyConfig : function(config){
46270 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
46271 this.config = config;
46276 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
46277 * the width, for horizontal (north, south) the height.
46278 * @param {Number} newSize The new width or height
46280 resizeTo : function(newSize){
46281 var el = this.el ? this.el :
46282 (this.activePanel ? this.activePanel.getEl() : null);
46284 switch(this.position){
46287 el.setWidth(newSize);
46288 this.fireEvent("resized", this, newSize);
46292 el.setHeight(newSize);
46293 this.fireEvent("resized", this, newSize);
46299 getBox : function(){
46300 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
46303 getMargins : function(){
46304 return this.margins;
46307 updateBox : function(box){
46309 var el = this.activePanel.getEl();
46310 el.dom.style.left = box.x + "px";
46311 el.dom.style.top = box.y + "px";
46312 this.activePanel.setSize(box.width, box.height);
46316 * Returns the container element for this region.
46317 * @return {Roo.Element}
46319 getEl : function(){
46320 return this.activePanel;
46324 * Returns true if this region is currently visible.
46325 * @return {Boolean}
46327 isVisible : function(){
46328 return this.activePanel ? true : false;
46331 setActivePanel : function(panel){
46332 panel = this.getPanel(panel);
46333 if(this.activePanel && this.activePanel != panel){
46334 this.activePanel.setActiveState(false);
46335 this.activePanel.getEl().setLeftTop(-10000,-10000);
46337 this.activePanel = panel;
46338 panel.setActiveState(true);
46340 panel.setSize(this.box.width, this.box.height);
46342 this.fireEvent("panelactivated", this, panel);
46343 this.fireEvent("invalidated");
46347 * Show the specified panel.
46348 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
46349 * @return {Roo.ContentPanel} The shown panel or null
46351 showPanel : function(panel){
46352 if(panel = this.getPanel(panel)){
46353 this.setActivePanel(panel);
46359 * Get the active panel for this region.
46360 * @return {Roo.ContentPanel} The active panel or null
46362 getActivePanel : function(){
46363 return this.activePanel;
46367 * Add the passed ContentPanel(s)
46368 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
46369 * @return {Roo.ContentPanel} The panel added (if only one was added)
46371 add : function(panel){
46372 if(arguments.length > 1){
46373 for(var i = 0, len = arguments.length; i < len; i++) {
46374 this.add(arguments[i]);
46378 if(this.hasPanel(panel)){
46379 this.showPanel(panel);
46382 var el = panel.getEl();
46383 if(el.dom.parentNode != this.mgr.el.dom){
46384 this.mgr.el.dom.appendChild(el.dom);
46386 if(panel.setRegion){
46387 panel.setRegion(this);
46389 this.panels.add(panel);
46390 el.setStyle("position", "absolute");
46391 if(!panel.background){
46392 this.setActivePanel(panel);
46393 if(this.config.initialSize && this.panels.getCount()==1){
46394 this.resizeTo(this.config.initialSize);
46397 this.fireEvent("paneladded", this, panel);
46402 * Returns true if the panel is in this region.
46403 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46404 * @return {Boolean}
46406 hasPanel : function(panel){
46407 if(typeof panel == "object"){ // must be panel obj
46408 panel = panel.getId();
46410 return this.getPanel(panel) ? true : false;
46414 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
46415 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46416 * @param {Boolean} preservePanel Overrides the config preservePanel option
46417 * @return {Roo.ContentPanel} The panel that was removed
46419 remove : function(panel, preservePanel){
46420 panel = this.getPanel(panel);
46425 this.fireEvent("beforeremove", this, panel, e);
46426 if(e.cancel === true){
46429 var panelId = panel.getId();
46430 this.panels.removeKey(panelId);
46435 * Returns the panel specified or null if it's not in this region.
46436 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46437 * @return {Roo.ContentPanel}
46439 getPanel : function(id){
46440 if(typeof id == "object"){ // must be panel obj
46443 return this.panels.get(id);
46447 * Returns this regions position (north/south/east/west/center).
46450 getPosition: function(){
46451 return this.position;
46455 * Ext JS Library 1.1.1
46456 * Copyright(c) 2006-2007, Ext JS, LLC.
46458 * Originally Released Under LGPL - original licence link has changed is not relivant.
46461 * <script type="text/javascript">
46465 * @class Roo.LayoutRegion
46466 * @extends Roo.BasicLayoutRegion
46467 * This class represents a region in a layout manager.
46468 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
46469 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
46470 * @cfg {Boolean} floatable False to disable floating (defaults to true)
46471 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
46472 * @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})
46473 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
46474 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
46475 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
46476 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
46477 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
46478 * @cfg {String} title The title for the region (overrides panel titles)
46479 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
46480 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
46481 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
46482 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
46483 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
46484 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
46485 * the space available, similar to FireFox 1.5 tabs (defaults to false)
46486 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
46487 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
46488 * @cfg {Boolean} showPin True to show a pin button
46489 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
46490 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
46491 * @cfg {Boolean} disableTabTips True to disable tab tooltips
46492 * @cfg {Number} width For East/West panels
46493 * @cfg {Number} height For North/South panels
46494 * @cfg {Boolean} split To show the splitter
46495 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
46497 Roo.LayoutRegion = function(mgr, config, pos){
46498 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
46499 var dh = Roo.DomHelper;
46500 /** This region's container element
46501 * @type Roo.Element */
46502 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
46503 /** This region's title element
46504 * @type Roo.Element */
46506 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
46507 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
46508 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
46510 this.titleEl.enableDisplayMode();
46511 /** This region's title text element
46512 * @type HTMLElement */
46513 this.titleTextEl = this.titleEl.dom.firstChild;
46514 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
46515 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
46516 this.closeBtn.enableDisplayMode();
46517 this.closeBtn.on("click", this.closeClicked, this);
46518 this.closeBtn.hide();
46520 this.createBody(config);
46521 this.visible = true;
46522 this.collapsed = false;
46524 if(config.hideWhenEmpty){
46526 this.on("paneladded", this.validateVisibility, this);
46527 this.on("panelremoved", this.validateVisibility, this);
46529 this.applyConfig(config);
46532 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
46534 createBody : function(){
46535 /** This region's body element
46536 * @type Roo.Element */
46537 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
46540 applyConfig : function(c){
46541 if(c.collapsible && this.position != "center" && !this.collapsedEl){
46542 var dh = Roo.DomHelper;
46543 if(c.titlebar !== false){
46544 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
46545 this.collapseBtn.on("click", this.collapse, this);
46546 this.collapseBtn.enableDisplayMode();
46548 if(c.showPin === true || this.showPin){
46549 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
46550 this.stickBtn.enableDisplayMode();
46551 this.stickBtn.on("click", this.expand, this);
46552 this.stickBtn.hide();
46555 /** This region's collapsed element
46556 * @type Roo.Element */
46557 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
46558 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
46560 if(c.floatable !== false){
46561 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
46562 this.collapsedEl.on("click", this.collapseClick, this);
46565 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
46566 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
46567 id: "message", unselectable: "on", style:{"float":"left"}});
46568 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
46570 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
46571 this.expandBtn.on("click", this.expand, this);
46573 if(this.collapseBtn){
46574 this.collapseBtn.setVisible(c.collapsible == true);
46576 this.cmargins = c.cmargins || this.cmargins ||
46577 (this.position == "west" || this.position == "east" ?
46578 {top: 0, left: 2, right:2, bottom: 0} :
46579 {top: 2, left: 0, right:0, bottom: 2});
46580 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
46581 this.bottomTabs = c.tabPosition != "top";
46582 this.autoScroll = c.autoScroll || false;
46583 if(this.autoScroll){
46584 this.bodyEl.setStyle("overflow", "auto");
46586 this.bodyEl.setStyle("overflow", "hidden");
46588 //if(c.titlebar !== false){
46589 if((!c.titlebar && !c.title) || c.titlebar === false){
46590 this.titleEl.hide();
46592 this.titleEl.show();
46594 this.titleTextEl.innerHTML = c.title;
46598 this.duration = c.duration || .30;
46599 this.slideDuration = c.slideDuration || .45;
46602 this.collapse(true);
46609 * Returns true if this region is currently visible.
46610 * @return {Boolean}
46612 isVisible : function(){
46613 return this.visible;
46617 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
46618 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
46620 setCollapsedTitle : function(title){
46621 title = title || " ";
46622 if(this.collapsedTitleTextEl){
46623 this.collapsedTitleTextEl.innerHTML = title;
46627 getBox : function(){
46629 if(!this.collapsed){
46630 b = this.el.getBox(false, true);
46632 b = this.collapsedEl.getBox(false, true);
46637 getMargins : function(){
46638 return this.collapsed ? this.cmargins : this.margins;
46641 highlight : function(){
46642 this.el.addClass("x-layout-panel-dragover");
46645 unhighlight : function(){
46646 this.el.removeClass("x-layout-panel-dragover");
46649 updateBox : function(box){
46651 if(!this.collapsed){
46652 this.el.dom.style.left = box.x + "px";
46653 this.el.dom.style.top = box.y + "px";
46654 this.updateBody(box.width, box.height);
46656 this.collapsedEl.dom.style.left = box.x + "px";
46657 this.collapsedEl.dom.style.top = box.y + "px";
46658 this.collapsedEl.setSize(box.width, box.height);
46661 this.tabs.autoSizeTabs();
46665 updateBody : function(w, h){
46667 this.el.setWidth(w);
46668 w -= this.el.getBorderWidth("rl");
46669 if(this.config.adjustments){
46670 w += this.config.adjustments[0];
46674 this.el.setHeight(h);
46675 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
46676 h -= this.el.getBorderWidth("tb");
46677 if(this.config.adjustments){
46678 h += this.config.adjustments[1];
46680 this.bodyEl.setHeight(h);
46682 h = this.tabs.syncHeight(h);
46685 if(this.panelSize){
46686 w = w !== null ? w : this.panelSize.width;
46687 h = h !== null ? h : this.panelSize.height;
46689 if(this.activePanel){
46690 var el = this.activePanel.getEl();
46691 w = w !== null ? w : el.getWidth();
46692 h = h !== null ? h : el.getHeight();
46693 this.panelSize = {width: w, height: h};
46694 this.activePanel.setSize(w, h);
46696 if(Roo.isIE && this.tabs){
46697 this.tabs.el.repaint();
46702 * Returns the container element for this region.
46703 * @return {Roo.Element}
46705 getEl : function(){
46710 * Hides this region.
46713 if(!this.collapsed){
46714 this.el.dom.style.left = "-2000px";
46717 this.collapsedEl.dom.style.left = "-2000px";
46718 this.collapsedEl.hide();
46720 this.visible = false;
46721 this.fireEvent("visibilitychange", this, false);
46725 * Shows this region if it was previously hidden.
46728 if(!this.collapsed){
46731 this.collapsedEl.show();
46733 this.visible = true;
46734 this.fireEvent("visibilitychange", this, true);
46737 closeClicked : function(){
46738 if(this.activePanel){
46739 this.remove(this.activePanel);
46743 collapseClick : function(e){
46745 e.stopPropagation();
46748 e.stopPropagation();
46754 * Collapses this region.
46755 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
46757 collapse : function(skipAnim){
46758 if(this.collapsed) return;
46759 this.collapsed = true;
46761 this.split.el.hide();
46763 if(this.config.animate && skipAnim !== true){
46764 this.fireEvent("invalidated", this);
46765 this.animateCollapse();
46767 this.el.setLocation(-20000,-20000);
46769 this.collapsedEl.show();
46770 this.fireEvent("collapsed", this);
46771 this.fireEvent("invalidated", this);
46775 animateCollapse : function(){
46780 * Expands this region if it was previously collapsed.
46781 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
46782 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
46784 expand : function(e, skipAnim){
46785 if(e) e.stopPropagation();
46786 if(!this.collapsed || this.el.hasActiveFx()) return;
46788 this.afterSlideIn();
46791 this.collapsed = false;
46792 if(this.config.animate && skipAnim !== true){
46793 this.animateExpand();
46797 this.split.el.show();
46799 this.collapsedEl.setLocation(-2000,-2000);
46800 this.collapsedEl.hide();
46801 this.fireEvent("invalidated", this);
46802 this.fireEvent("expanded", this);
46806 animateExpand : function(){
46810 initTabs : function()
46812 this.bodyEl.setStyle("overflow", "hidden");
46813 var ts = new Roo.TabPanel(
46816 tabPosition: this.bottomTabs ? 'bottom' : 'top',
46817 disableTooltips: this.config.disableTabTips,
46818 toolbar : this.config.toolbar
46821 if(this.config.hideTabs){
46822 ts.stripWrap.setDisplayed(false);
46825 ts.resizeTabs = this.config.resizeTabs === true;
46826 ts.minTabWidth = this.config.minTabWidth || 40;
46827 ts.maxTabWidth = this.config.maxTabWidth || 250;
46828 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
46829 ts.monitorResize = false;
46830 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
46831 ts.bodyEl.addClass('x-layout-tabs-body');
46832 this.panels.each(this.initPanelAsTab, this);
46835 initPanelAsTab : function(panel){
46836 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
46837 this.config.closeOnTab && panel.isClosable());
46838 if(panel.tabTip !== undefined){
46839 ti.setTooltip(panel.tabTip);
46841 ti.on("activate", function(){
46842 this.setActivePanel(panel);
46844 if(this.config.closeOnTab){
46845 ti.on("beforeclose", function(t, e){
46847 this.remove(panel);
46853 updatePanelTitle : function(panel, title){
46854 if(this.activePanel == panel){
46855 this.updateTitle(title);
46858 var ti = this.tabs.getTab(panel.getEl().id);
46860 if(panel.tabTip !== undefined){
46861 ti.setTooltip(panel.tabTip);
46866 updateTitle : function(title){
46867 if(this.titleTextEl && !this.config.title){
46868 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
46872 setActivePanel : function(panel){
46873 panel = this.getPanel(panel);
46874 if(this.activePanel && this.activePanel != panel){
46875 this.activePanel.setActiveState(false);
46877 this.activePanel = panel;
46878 panel.setActiveState(true);
46879 if(this.panelSize){
46880 panel.setSize(this.panelSize.width, this.panelSize.height);
46883 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
46885 this.updateTitle(panel.getTitle());
46887 this.fireEvent("invalidated", this);
46889 this.fireEvent("panelactivated", this, panel);
46893 * Shows the specified panel.
46894 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
46895 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
46897 showPanel : function(panel){
46898 if(panel = this.getPanel(panel)){
46900 var tab = this.tabs.getTab(panel.getEl().id);
46901 if(tab.isHidden()){
46902 this.tabs.unhideTab(tab.id);
46906 this.setActivePanel(panel);
46913 * Get the active panel for this region.
46914 * @return {Roo.ContentPanel} The active panel or null
46916 getActivePanel : function(){
46917 return this.activePanel;
46920 validateVisibility : function(){
46921 if(this.panels.getCount() < 1){
46922 this.updateTitle(" ");
46923 this.closeBtn.hide();
46926 if(!this.isVisible()){
46933 * Adds the passed ContentPanel(s) to this region.
46934 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
46935 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
46937 add : function(panel){
46938 if(arguments.length > 1){
46939 for(var i = 0, len = arguments.length; i < len; i++) {
46940 this.add(arguments[i]);
46944 if(this.hasPanel(panel)){
46945 this.showPanel(panel);
46948 panel.setRegion(this);
46949 this.panels.add(panel);
46950 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
46951 this.bodyEl.dom.appendChild(panel.getEl().dom);
46952 if(panel.background !== true){
46953 this.setActivePanel(panel);
46955 this.fireEvent("paneladded", this, panel);
46961 this.initPanelAsTab(panel);
46963 if(panel.background !== true){
46964 this.tabs.activate(panel.getEl().id);
46966 this.fireEvent("paneladded", this, panel);
46971 * Hides the tab for the specified panel.
46972 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46974 hidePanel : function(panel){
46975 if(this.tabs && (panel = this.getPanel(panel))){
46976 this.tabs.hideTab(panel.getEl().id);
46981 * Unhides the tab for a previously hidden panel.
46982 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46984 unhidePanel : function(panel){
46985 if(this.tabs && (panel = this.getPanel(panel))){
46986 this.tabs.unhideTab(panel.getEl().id);
46990 clearPanels : function(){
46991 while(this.panels.getCount() > 0){
46992 this.remove(this.panels.first());
46997 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
46998 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46999 * @param {Boolean} preservePanel Overrides the config preservePanel option
47000 * @return {Roo.ContentPanel} The panel that was removed
47002 remove : function(panel, preservePanel){
47003 panel = this.getPanel(panel);
47008 this.fireEvent("beforeremove", this, panel, e);
47009 if(e.cancel === true){
47012 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
47013 var panelId = panel.getId();
47014 this.panels.removeKey(panelId);
47016 document.body.appendChild(panel.getEl().dom);
47019 this.tabs.removeTab(panel.getEl().id);
47020 }else if (!preservePanel){
47021 this.bodyEl.dom.removeChild(panel.getEl().dom);
47023 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
47024 var p = this.panels.first();
47025 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
47026 tempEl.appendChild(p.getEl().dom);
47027 this.bodyEl.update("");
47028 this.bodyEl.dom.appendChild(p.getEl().dom);
47030 this.updateTitle(p.getTitle());
47032 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47033 this.setActivePanel(p);
47035 panel.setRegion(null);
47036 if(this.activePanel == panel){
47037 this.activePanel = null;
47039 if(this.config.autoDestroy !== false && preservePanel !== true){
47040 try{panel.destroy();}catch(e){}
47042 this.fireEvent("panelremoved", this, panel);
47047 * Returns the TabPanel component used by this region
47048 * @return {Roo.TabPanel}
47050 getTabs : function(){
47054 createTool : function(parentEl, className){
47055 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
47056 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
47057 btn.addClassOnOver("x-layout-tools-button-over");
47062 * Ext JS Library 1.1.1
47063 * Copyright(c) 2006-2007, Ext JS, LLC.
47065 * Originally Released Under LGPL - original licence link has changed is not relivant.
47068 * <script type="text/javascript">
47074 * @class Roo.SplitLayoutRegion
47075 * @extends Roo.LayoutRegion
47076 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
47078 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
47079 this.cursor = cursor;
47080 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
47083 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
47084 splitTip : "Drag to resize.",
47085 collapsibleSplitTip : "Drag to resize. Double click to hide.",
47086 useSplitTips : false,
47088 applyConfig : function(config){
47089 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
47092 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
47093 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
47094 /** The SplitBar for this region
47095 * @type Roo.SplitBar */
47096 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
47097 this.split.on("moved", this.onSplitMove, this);
47098 this.split.useShim = config.useShim === true;
47099 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
47100 if(this.useSplitTips){
47101 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
47103 if(config.collapsible){
47104 this.split.el.on("dblclick", this.collapse, this);
47107 if(typeof config.minSize != "undefined"){
47108 this.split.minSize = config.minSize;
47110 if(typeof config.maxSize != "undefined"){
47111 this.split.maxSize = config.maxSize;
47113 if(config.hideWhenEmpty || config.hidden || config.collapsed){
47114 this.hideSplitter();
47119 getHMaxSize : function(){
47120 var cmax = this.config.maxSize || 10000;
47121 var center = this.mgr.getRegion("center");
47122 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
47125 getVMaxSize : function(){
47126 var cmax = this.config.maxSize || 10000;
47127 var center = this.mgr.getRegion("center");
47128 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
47131 onSplitMove : function(split, newSize){
47132 this.fireEvent("resized", this, newSize);
47136 * Returns the {@link Roo.SplitBar} for this region.
47137 * @return {Roo.SplitBar}
47139 getSplitBar : function(){
47144 this.hideSplitter();
47145 Roo.SplitLayoutRegion.superclass.hide.call(this);
47148 hideSplitter : function(){
47150 this.split.el.setLocation(-2000,-2000);
47151 this.split.el.hide();
47157 this.split.el.show();
47159 Roo.SplitLayoutRegion.superclass.show.call(this);
47162 beforeSlide: function(){
47163 if(Roo.isGecko){// firefox overflow auto bug workaround
47164 this.bodyEl.clip();
47165 if(this.tabs) this.tabs.bodyEl.clip();
47166 if(this.activePanel){
47167 this.activePanel.getEl().clip();
47169 if(this.activePanel.beforeSlide){
47170 this.activePanel.beforeSlide();
47176 afterSlide : function(){
47177 if(Roo.isGecko){// firefox overflow auto bug workaround
47178 this.bodyEl.unclip();
47179 if(this.tabs) this.tabs.bodyEl.unclip();
47180 if(this.activePanel){
47181 this.activePanel.getEl().unclip();
47182 if(this.activePanel.afterSlide){
47183 this.activePanel.afterSlide();
47189 initAutoHide : function(){
47190 if(this.autoHide !== false){
47191 if(!this.autoHideHd){
47192 var st = new Roo.util.DelayedTask(this.slideIn, this);
47193 this.autoHideHd = {
47194 "mouseout": function(e){
47195 if(!e.within(this.el, true)){
47199 "mouseover" : function(e){
47205 this.el.on(this.autoHideHd);
47209 clearAutoHide : function(){
47210 if(this.autoHide !== false){
47211 this.el.un("mouseout", this.autoHideHd.mouseout);
47212 this.el.un("mouseover", this.autoHideHd.mouseover);
47216 clearMonitor : function(){
47217 Roo.get(document).un("click", this.slideInIf, this);
47220 // these names are backwards but not changed for compat
47221 slideOut : function(){
47222 if(this.isSlid || this.el.hasActiveFx()){
47225 this.isSlid = true;
47226 if(this.collapseBtn){
47227 this.collapseBtn.hide();
47229 this.closeBtnState = this.closeBtn.getStyle('display');
47230 this.closeBtn.hide();
47232 this.stickBtn.show();
47235 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
47236 this.beforeSlide();
47237 this.el.setStyle("z-index", 10001);
47238 this.el.slideIn(this.getSlideAnchor(), {
47239 callback: function(){
47241 this.initAutoHide();
47242 Roo.get(document).on("click", this.slideInIf, this);
47243 this.fireEvent("slideshow", this);
47250 afterSlideIn : function(){
47251 this.clearAutoHide();
47252 this.isSlid = false;
47253 this.clearMonitor();
47254 this.el.setStyle("z-index", "");
47255 if(this.collapseBtn){
47256 this.collapseBtn.show();
47258 this.closeBtn.setStyle('display', this.closeBtnState);
47260 this.stickBtn.hide();
47262 this.fireEvent("slidehide", this);
47265 slideIn : function(cb){
47266 if(!this.isSlid || this.el.hasActiveFx()){
47270 this.isSlid = false;
47271 this.beforeSlide();
47272 this.el.slideOut(this.getSlideAnchor(), {
47273 callback: function(){
47274 this.el.setLeftTop(-10000, -10000);
47276 this.afterSlideIn();
47284 slideInIf : function(e){
47285 if(!e.within(this.el)){
47290 animateCollapse : function(){
47291 this.beforeSlide();
47292 this.el.setStyle("z-index", 20000);
47293 var anchor = this.getSlideAnchor();
47294 this.el.slideOut(anchor, {
47295 callback : function(){
47296 this.el.setStyle("z-index", "");
47297 this.collapsedEl.slideIn(anchor, {duration:.3});
47299 this.el.setLocation(-10000,-10000);
47301 this.fireEvent("collapsed", this);
47308 animateExpand : function(){
47309 this.beforeSlide();
47310 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
47311 this.el.setStyle("z-index", 20000);
47312 this.collapsedEl.hide({
47315 this.el.slideIn(this.getSlideAnchor(), {
47316 callback : function(){
47317 this.el.setStyle("z-index", "");
47320 this.split.el.show();
47322 this.fireEvent("invalidated", this);
47323 this.fireEvent("expanded", this);
47351 getAnchor : function(){
47352 return this.anchors[this.position];
47355 getCollapseAnchor : function(){
47356 return this.canchors[this.position];
47359 getSlideAnchor : function(){
47360 return this.sanchors[this.position];
47363 getAlignAdj : function(){
47364 var cm = this.cmargins;
47365 switch(this.position){
47381 getExpandAdj : function(){
47382 var c = this.collapsedEl, cm = this.cmargins;
47383 switch(this.position){
47385 return [-(cm.right+c.getWidth()+cm.left), 0];
47388 return [cm.right+c.getWidth()+cm.left, 0];
47391 return [0, -(cm.top+cm.bottom+c.getHeight())];
47394 return [0, cm.top+cm.bottom+c.getHeight()];
47400 * Ext JS Library 1.1.1
47401 * Copyright(c) 2006-2007, Ext JS, LLC.
47403 * Originally Released Under LGPL - original licence link has changed is not relivant.
47406 * <script type="text/javascript">
47409 * These classes are private internal classes
47411 Roo.CenterLayoutRegion = function(mgr, config){
47412 Roo.LayoutRegion.call(this, mgr, config, "center");
47413 this.visible = true;
47414 this.minWidth = config.minWidth || 20;
47415 this.minHeight = config.minHeight || 20;
47418 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
47420 // center panel can't be hidden
47424 // center panel can't be hidden
47427 getMinWidth: function(){
47428 return this.minWidth;
47431 getMinHeight: function(){
47432 return this.minHeight;
47437 Roo.NorthLayoutRegion = function(mgr, config){
47438 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
47440 this.split.placement = Roo.SplitBar.TOP;
47441 this.split.orientation = Roo.SplitBar.VERTICAL;
47442 this.split.el.addClass("x-layout-split-v");
47444 var size = config.initialSize || config.height;
47445 if(typeof size != "undefined"){
47446 this.el.setHeight(size);
47449 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
47450 orientation: Roo.SplitBar.VERTICAL,
47451 getBox : function(){
47452 if(this.collapsed){
47453 return this.collapsedEl.getBox();
47455 var box = this.el.getBox();
47457 box.height += this.split.el.getHeight();
47462 updateBox : function(box){
47463 if(this.split && !this.collapsed){
47464 box.height -= this.split.el.getHeight();
47465 this.split.el.setLeft(box.x);
47466 this.split.el.setTop(box.y+box.height);
47467 this.split.el.setWidth(box.width);
47469 if(this.collapsed){
47470 this.updateBody(box.width, null);
47472 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47476 Roo.SouthLayoutRegion = function(mgr, config){
47477 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
47479 this.split.placement = Roo.SplitBar.BOTTOM;
47480 this.split.orientation = Roo.SplitBar.VERTICAL;
47481 this.split.el.addClass("x-layout-split-v");
47483 var size = config.initialSize || config.height;
47484 if(typeof size != "undefined"){
47485 this.el.setHeight(size);
47488 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
47489 orientation: Roo.SplitBar.VERTICAL,
47490 getBox : function(){
47491 if(this.collapsed){
47492 return this.collapsedEl.getBox();
47494 var box = this.el.getBox();
47496 var sh = this.split.el.getHeight();
47503 updateBox : function(box){
47504 if(this.split && !this.collapsed){
47505 var sh = this.split.el.getHeight();
47508 this.split.el.setLeft(box.x);
47509 this.split.el.setTop(box.y-sh);
47510 this.split.el.setWidth(box.width);
47512 if(this.collapsed){
47513 this.updateBody(box.width, null);
47515 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47519 Roo.EastLayoutRegion = function(mgr, config){
47520 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
47522 this.split.placement = Roo.SplitBar.RIGHT;
47523 this.split.orientation = Roo.SplitBar.HORIZONTAL;
47524 this.split.el.addClass("x-layout-split-h");
47526 var size = config.initialSize || config.width;
47527 if(typeof size != "undefined"){
47528 this.el.setWidth(size);
47531 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
47532 orientation: Roo.SplitBar.HORIZONTAL,
47533 getBox : function(){
47534 if(this.collapsed){
47535 return this.collapsedEl.getBox();
47537 var box = this.el.getBox();
47539 var sw = this.split.el.getWidth();
47546 updateBox : function(box){
47547 if(this.split && !this.collapsed){
47548 var sw = this.split.el.getWidth();
47550 this.split.el.setLeft(box.x);
47551 this.split.el.setTop(box.y);
47552 this.split.el.setHeight(box.height);
47555 if(this.collapsed){
47556 this.updateBody(null, box.height);
47558 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47562 Roo.WestLayoutRegion = function(mgr, config){
47563 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
47565 this.split.placement = Roo.SplitBar.LEFT;
47566 this.split.orientation = Roo.SplitBar.HORIZONTAL;
47567 this.split.el.addClass("x-layout-split-h");
47569 var size = config.initialSize || config.width;
47570 if(typeof size != "undefined"){
47571 this.el.setWidth(size);
47574 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
47575 orientation: Roo.SplitBar.HORIZONTAL,
47576 getBox : function(){
47577 if(this.collapsed){
47578 return this.collapsedEl.getBox();
47580 var box = this.el.getBox();
47582 box.width += this.split.el.getWidth();
47587 updateBox : function(box){
47588 if(this.split && !this.collapsed){
47589 var sw = this.split.el.getWidth();
47591 this.split.el.setLeft(box.x+box.width);
47592 this.split.el.setTop(box.y);
47593 this.split.el.setHeight(box.height);
47595 if(this.collapsed){
47596 this.updateBody(null, box.height);
47598 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47603 * Ext JS Library 1.1.1
47604 * Copyright(c) 2006-2007, Ext JS, LLC.
47606 * Originally Released Under LGPL - original licence link has changed is not relivant.
47609 * <script type="text/javascript">
47614 * Private internal class for reading and applying state
47616 Roo.LayoutStateManager = function(layout){
47617 // default empty state
47626 Roo.LayoutStateManager.prototype = {
47627 init : function(layout, provider){
47628 this.provider = provider;
47629 var state = provider.get(layout.id+"-layout-state");
47631 var wasUpdating = layout.isUpdating();
47633 layout.beginUpdate();
47635 for(var key in state){
47636 if(typeof state[key] != "function"){
47637 var rstate = state[key];
47638 var r = layout.getRegion(key);
47641 r.resizeTo(rstate.size);
47643 if(rstate.collapsed == true){
47646 r.expand(null, true);
47652 layout.endUpdate();
47654 this.state = state;
47656 this.layout = layout;
47657 layout.on("regionresized", this.onRegionResized, this);
47658 layout.on("regioncollapsed", this.onRegionCollapsed, this);
47659 layout.on("regionexpanded", this.onRegionExpanded, this);
47662 storeState : function(){
47663 this.provider.set(this.layout.id+"-layout-state", this.state);
47666 onRegionResized : function(region, newSize){
47667 this.state[region.getPosition()].size = newSize;
47671 onRegionCollapsed : function(region){
47672 this.state[region.getPosition()].collapsed = true;
47676 onRegionExpanded : function(region){
47677 this.state[region.getPosition()].collapsed = false;
47682 * Ext JS Library 1.1.1
47683 * Copyright(c) 2006-2007, Ext JS, LLC.
47685 * Originally Released Under LGPL - original licence link has changed is not relivant.
47688 * <script type="text/javascript">
47691 * @class Roo.ContentPanel
47692 * @extends Roo.util.Observable
47693 * A basic ContentPanel element.
47694 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
47695 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
47696 * @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
47697 * @cfg {Boolean} closable True if the panel can be closed/removed
47698 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
47699 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
47700 * @cfg {Toolbar} toolbar A toolbar for this panel
47701 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
47702 * @cfg {String} title The title for this panel
47703 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
47704 * @cfg {String} url Calls {@link #setUrl} with this value
47705 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
47706 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
47707 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
47708 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
47711 * Create a new ContentPanel.
47712 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
47713 * @param {String/Object} config A string to set only the title or a config object
47714 * @param {String} content (optional) Set the HTML content for this panel
47715 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
47717 Roo.ContentPanel = function(el, config, content){
47721 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
47725 if (config && config.parentLayout) {
47726 el = config.parentLayout.el.createChild();
47729 if(el.autoCreate){ // xtype is available if this is called from factory
47733 this.el = Roo.get(el);
47734 if(!this.el && config && config.autoCreate){
47735 if(typeof config.autoCreate == "object"){
47736 if(!config.autoCreate.id){
47737 config.autoCreate.id = config.id||el;
47739 this.el = Roo.DomHelper.append(document.body,
47740 config.autoCreate, true);
47742 this.el = Roo.DomHelper.append(document.body,
47743 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
47746 this.closable = false;
47747 this.loaded = false;
47748 this.active = false;
47749 if(typeof config == "string"){
47750 this.title = config;
47752 Roo.apply(this, config);
47755 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
47756 this.wrapEl = this.el.wrap();
47757 this.toolbar.container = this.el.insertSibling(false, 'before');
47758 this.toolbar = new Roo.Toolbar(this.toolbar);
47764 this.resizeEl = Roo.get(this.resizeEl, true);
47766 this.resizeEl = this.el;
47771 * Fires when this panel is activated.
47772 * @param {Roo.ContentPanel} this
47776 * @event deactivate
47777 * Fires when this panel is activated.
47778 * @param {Roo.ContentPanel} this
47780 "deactivate" : true,
47784 * Fires when this panel is resized if fitToFrame is true.
47785 * @param {Roo.ContentPanel} this
47786 * @param {Number} width The width after any component adjustments
47787 * @param {Number} height The height after any component adjustments
47793 * Fires when this tab is created
47794 * @param {Roo.ContentPanel} this
47801 if(this.autoScroll){
47802 this.resizeEl.setStyle("overflow", "auto");
47804 // fix randome scrolling
47805 this.el.on('scroll', function() {
47806 Roo.log('fix random scolling');
47807 this.scrollTo('top',0);
47810 content = content || this.content;
47812 this.setContent(content);
47814 if(config && config.url){
47815 this.setUrl(this.url, this.params, this.loadOnce);
47820 Roo.ContentPanel.superclass.constructor.call(this);
47822 this.fireEvent('render', this);
47825 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
47827 setRegion : function(region){
47828 this.region = region;
47830 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
47832 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
47837 * Returns the toolbar for this Panel if one was configured.
47838 * @return {Roo.Toolbar}
47840 getToolbar : function(){
47841 return this.toolbar;
47844 setActiveState : function(active){
47845 this.active = active;
47847 this.fireEvent("deactivate", this);
47849 this.fireEvent("activate", this);
47853 * Updates this panel's element
47854 * @param {String} content The new content
47855 * @param {Boolean} loadScripts (optional) true to look for and process scripts
47857 setContent : function(content, loadScripts){
47858 this.el.update(content, loadScripts);
47861 ignoreResize : function(w, h){
47862 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
47865 this.lastSize = {width: w, height: h};
47870 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
47871 * @return {Roo.UpdateManager} The UpdateManager
47873 getUpdateManager : function(){
47874 return this.el.getUpdateManager();
47877 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
47878 * @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:
47881 url: "your-url.php",
47882 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
47883 callback: yourFunction,
47884 scope: yourObject, //(optional scope)
47887 text: "Loading...",
47892 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
47893 * 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.
47894 * @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}
47895 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
47896 * @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.
47897 * @return {Roo.ContentPanel} this
47900 var um = this.el.getUpdateManager();
47901 um.update.apply(um, arguments);
47907 * 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.
47908 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
47909 * @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)
47910 * @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)
47911 * @return {Roo.UpdateManager} The UpdateManager
47913 setUrl : function(url, params, loadOnce){
47914 if(this.refreshDelegate){
47915 this.removeListener("activate", this.refreshDelegate);
47917 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
47918 this.on("activate", this.refreshDelegate);
47919 return this.el.getUpdateManager();
47922 _handleRefresh : function(url, params, loadOnce){
47923 if(!loadOnce || !this.loaded){
47924 var updater = this.el.getUpdateManager();
47925 updater.update(url, params, this._setLoaded.createDelegate(this));
47929 _setLoaded : function(){
47930 this.loaded = true;
47934 * Returns this panel's id
47937 getId : function(){
47942 * Returns this panel's element - used by regiosn to add.
47943 * @return {Roo.Element}
47945 getEl : function(){
47946 return this.wrapEl || this.el;
47949 adjustForComponents : function(width, height){
47950 if(this.resizeEl != this.el){
47951 width -= this.el.getFrameWidth('lr');
47952 height -= this.el.getFrameWidth('tb');
47955 var te = this.toolbar.getEl();
47956 height -= te.getHeight();
47957 te.setWidth(width);
47959 if(this.adjustments){
47960 width += this.adjustments[0];
47961 height += this.adjustments[1];
47963 return {"width": width, "height": height};
47966 setSize : function(width, height){
47967 if(this.fitToFrame && !this.ignoreResize(width, height)){
47968 if(this.fitContainer && this.resizeEl != this.el){
47969 this.el.setSize(width, height);
47971 var size = this.adjustForComponents(width, height);
47972 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
47973 this.fireEvent('resize', this, size.width, size.height);
47978 * Returns this panel's title
47981 getTitle : function(){
47986 * Set this panel's title
47987 * @param {String} title
47989 setTitle : function(title){
47990 this.title = title;
47992 this.region.updatePanelTitle(this, title);
47997 * Returns true is this panel was configured to be closable
47998 * @return {Boolean}
48000 isClosable : function(){
48001 return this.closable;
48004 beforeSlide : function(){
48006 this.resizeEl.clip();
48009 afterSlide : function(){
48011 this.resizeEl.unclip();
48015 * Force a content refresh from the URL specified in the {@link #setUrl} method.
48016 * Will fail silently if the {@link #setUrl} method has not been called.
48017 * This does not activate the panel, just updates its content.
48019 refresh : function(){
48020 if(this.refreshDelegate){
48021 this.loaded = false;
48022 this.refreshDelegate();
48027 * Destroys this panel
48029 destroy : function(){
48030 this.el.removeAllListeners();
48031 var tempEl = document.createElement("span");
48032 tempEl.appendChild(this.el.dom);
48033 tempEl.innerHTML = "";
48039 * form - if the content panel contains a form - this is a reference to it.
48040 * @type {Roo.form.Form}
48044 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
48045 * This contains a reference to it.
48051 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
48061 * @param {Object} cfg Xtype definition of item to add.
48064 addxtype : function(cfg) {
48066 if (cfg.xtype.match(/^Form$/)) {
48067 var el = this.el.createChild();
48069 this.form = new Roo.form.Form(cfg);
48072 if ( this.form.allItems.length) this.form.render(el.dom);
48075 // should only have one of theses..
48076 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
48078 cfg.el = this.el.appendChild(document.createElement("div"));
48081 var ret = new Roo.factory(cfg);
48082 ret.render && ret.render(false, ''); // render blank..
48091 * @class Roo.GridPanel
48092 * @extends Roo.ContentPanel
48094 * Create a new GridPanel.
48095 * @param {Roo.grid.Grid} grid The grid for this panel
48096 * @param {String/Object} config A string to set only the panel's title, or a config object
48098 Roo.GridPanel = function(grid, config){
48101 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
48102 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
48104 this.wrapper.dom.appendChild(grid.getGridEl().dom);
48106 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
48109 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
48111 // xtype created footer. - not sure if will work as we normally have to render first..
48112 if (this.footer && !this.footer.el && this.footer.xtype) {
48114 this.footer.container = this.grid.getView().getFooterPanel(true);
48115 this.footer.dataSource = this.grid.dataSource;
48116 this.footer = Roo.factory(this.footer, Roo);
48120 grid.monitorWindowResize = false; // turn off autosizing
48121 grid.autoHeight = false;
48122 grid.autoWidth = false;
48124 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
48127 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
48128 getId : function(){
48129 return this.grid.id;
48133 * Returns the grid for this panel
48134 * @return {Roo.grid.Grid}
48136 getGrid : function(){
48140 setSize : function(width, height){
48141 if(!this.ignoreResize(width, height)){
48142 var grid = this.grid;
48143 var size = this.adjustForComponents(width, height);
48144 grid.getGridEl().setSize(size.width, size.height);
48149 beforeSlide : function(){
48150 this.grid.getView().scroller.clip();
48153 afterSlide : function(){
48154 this.grid.getView().scroller.unclip();
48157 destroy : function(){
48158 this.grid.destroy();
48160 Roo.GridPanel.superclass.destroy.call(this);
48166 * @class Roo.NestedLayoutPanel
48167 * @extends Roo.ContentPanel
48169 * Create a new NestedLayoutPanel.
48172 * @param {Roo.BorderLayout} layout The layout for this panel
48173 * @param {String/Object} config A string to set only the title or a config object
48175 Roo.NestedLayoutPanel = function(layout, config)
48177 // construct with only one argument..
48178 /* FIXME - implement nicer consturctors
48179 if (layout.layout) {
48181 layout = config.layout;
48182 delete config.layout;
48184 if (layout.xtype && !layout.getEl) {
48185 // then layout needs constructing..
48186 layout = Roo.factory(layout, Roo);
48191 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
48193 layout.monitorWindowResize = false; // turn off autosizing
48194 this.layout = layout;
48195 this.layout.getEl().addClass("x-layout-nested-layout");
48202 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
48204 setSize : function(width, height){
48205 if(!this.ignoreResize(width, height)){
48206 var size = this.adjustForComponents(width, height);
48207 var el = this.layout.getEl();
48208 el.setSize(size.width, size.height);
48209 var touch = el.dom.offsetWidth;
48210 this.layout.layout();
48211 // ie requires a double layout on the first pass
48212 if(Roo.isIE && !this.initialized){
48213 this.initialized = true;
48214 this.layout.layout();
48219 // activate all subpanels if not currently active..
48221 setActiveState : function(active){
48222 this.active = active;
48224 this.fireEvent("deactivate", this);
48228 this.fireEvent("activate", this);
48229 // not sure if this should happen before or after..
48230 if (!this.layout) {
48231 return; // should not happen..
48234 for (var r in this.layout.regions) {
48235 reg = this.layout.getRegion(r);
48236 if (reg.getActivePanel()) {
48237 //reg.showPanel(reg.getActivePanel()); // force it to activate..
48238 reg.setActivePanel(reg.getActivePanel());
48241 if (!reg.panels.length) {
48244 reg.showPanel(reg.getPanel(0));
48253 * Returns the nested BorderLayout for this panel
48254 * @return {Roo.BorderLayout}
48256 getLayout : function(){
48257 return this.layout;
48261 * Adds a xtype elements to the layout of the nested panel
48265 xtype : 'ContentPanel',
48272 xtype : 'NestedLayoutPanel',
48278 items : [ ... list of content panels or nested layout panels.. ]
48282 * @param {Object} cfg Xtype definition of item to add.
48284 addxtype : function(cfg) {
48285 return this.layout.addxtype(cfg);
48290 Roo.ScrollPanel = function(el, config, content){
48291 config = config || {};
48292 config.fitToFrame = true;
48293 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
48295 this.el.dom.style.overflow = "hidden";
48296 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
48297 this.el.removeClass("x-layout-inactive-content");
48298 this.el.on("mousewheel", this.onWheel, this);
48300 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
48301 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
48302 up.unselectable(); down.unselectable();
48303 up.on("click", this.scrollUp, this);
48304 down.on("click", this.scrollDown, this);
48305 up.addClassOnOver("x-scroller-btn-over");
48306 down.addClassOnOver("x-scroller-btn-over");
48307 up.addClassOnClick("x-scroller-btn-click");
48308 down.addClassOnClick("x-scroller-btn-click");
48309 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
48311 this.resizeEl = this.el;
48312 this.el = wrap; this.up = up; this.down = down;
48315 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
48317 wheelIncrement : 5,
48318 scrollUp : function(){
48319 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
48322 scrollDown : function(){
48323 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
48326 afterScroll : function(){
48327 var el = this.resizeEl;
48328 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
48329 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
48330 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
48333 setSize : function(){
48334 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
48335 this.afterScroll();
48338 onWheel : function(e){
48339 var d = e.getWheelDelta();
48340 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
48341 this.afterScroll();
48345 setContent : function(content, loadScripts){
48346 this.resizeEl.update(content, loadScripts);
48360 * @class Roo.TreePanel
48361 * @extends Roo.ContentPanel
48363 * Create a new TreePanel. - defaults to fit/scoll contents.
48364 * @param {String/Object} config A string to set only the panel's title, or a config object
48365 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
48367 Roo.TreePanel = function(config){
48368 var el = config.el;
48369 var tree = config.tree;
48370 delete config.tree;
48371 delete config.el; // hopefull!
48373 // wrapper for IE7 strict & safari scroll issue
48375 var treeEl = el.createChild();
48376 config.resizeEl = treeEl;
48380 Roo.TreePanel.superclass.constructor.call(this, el, config);
48383 this.tree = new Roo.tree.TreePanel(treeEl , tree);
48384 //console.log(tree);
48385 this.on('activate', function()
48387 if (this.tree.rendered) {
48390 //console.log('render tree');
48391 this.tree.render();
48393 // this should not be needed.. - it's actually the 'el' that resizes?
48394 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
48396 //this.on('resize', function (cp, w, h) {
48397 // this.tree.innerCt.setWidth(w);
48398 // this.tree.innerCt.setHeight(h);
48399 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
48406 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
48423 * Ext JS Library 1.1.1
48424 * Copyright(c) 2006-2007, Ext JS, LLC.
48426 * Originally Released Under LGPL - original licence link has changed is not relivant.
48429 * <script type="text/javascript">
48434 * @class Roo.ReaderLayout
48435 * @extends Roo.BorderLayout
48436 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
48437 * center region containing two nested regions (a top one for a list view and one for item preview below),
48438 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
48439 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
48440 * expedites the setup of the overall layout and regions for this common application style.
48443 var reader = new Roo.ReaderLayout();
48444 var CP = Roo.ContentPanel; // shortcut for adding
48446 reader.beginUpdate();
48447 reader.add("north", new CP("north", "North"));
48448 reader.add("west", new CP("west", {title: "West"}));
48449 reader.add("east", new CP("east", {title: "East"}));
48451 reader.regions.listView.add(new CP("listView", "List"));
48452 reader.regions.preview.add(new CP("preview", "Preview"));
48453 reader.endUpdate();
48456 * Create a new ReaderLayout
48457 * @param {Object} config Configuration options
48458 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
48459 * document.body if omitted)
48461 Roo.ReaderLayout = function(config, renderTo){
48462 var c = config || {size:{}};
48463 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
48464 north: c.north !== false ? Roo.apply({
48468 }, c.north) : false,
48469 west: c.west !== false ? Roo.apply({
48477 margins:{left:5,right:0,bottom:5,top:5},
48478 cmargins:{left:5,right:5,bottom:5,top:5}
48479 }, c.west) : false,
48480 east: c.east !== false ? Roo.apply({
48488 margins:{left:0,right:5,bottom:5,top:5},
48489 cmargins:{left:5,right:5,bottom:5,top:5}
48490 }, c.east) : false,
48491 center: Roo.apply({
48492 tabPosition: 'top',
48496 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
48500 this.el.addClass('x-reader');
48502 this.beginUpdate();
48504 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
48505 south: c.preview !== false ? Roo.apply({
48512 cmargins:{top:5,left:0, right:0, bottom:0}
48513 }, c.preview) : false,
48514 center: Roo.apply({
48520 this.add('center', new Roo.NestedLayoutPanel(inner,
48521 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
48525 this.regions.preview = inner.getRegion('south');
48526 this.regions.listView = inner.getRegion('center');
48529 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
48531 * Ext JS Library 1.1.1
48532 * Copyright(c) 2006-2007, Ext JS, LLC.
48534 * Originally Released Under LGPL - original licence link has changed is not relivant.
48537 * <script type="text/javascript">
48541 * @class Roo.grid.Grid
48542 * @extends Roo.util.Observable
48543 * This class represents the primary interface of a component based grid control.
48544 * <br><br>Usage:<pre><code>
48545 var grid = new Roo.grid.Grid("my-container-id", {
48548 selModel: mySelectionModel,
48549 autoSizeColumns: true,
48550 monitorWindowResize: false,
48551 trackMouseOver: true
48556 * <b>Common Problems:</b><br/>
48557 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
48558 * element will correct this<br/>
48559 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
48560 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
48561 * are unpredictable.<br/>
48562 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
48563 * grid to calculate dimensions/offsets.<br/>
48565 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
48566 * The container MUST have some type of size defined for the grid to fill. The container will be
48567 * automatically set to position relative if it isn't already.
48568 * @param {Object} config A config object that sets properties on this grid.
48570 Roo.grid.Grid = function(container, config){
48571 // initialize the container
48572 this.container = Roo.get(container);
48573 this.container.update("");
48574 this.container.setStyle("overflow", "hidden");
48575 this.container.addClass('x-grid-container');
48577 this.id = this.container.id;
48579 Roo.apply(this, config);
48580 // check and correct shorthanded configs
48582 this.dataSource = this.ds;
48586 this.colModel = this.cm;
48590 this.selModel = this.sm;
48594 if (this.selModel) {
48595 this.selModel = Roo.factory(this.selModel, Roo.grid);
48596 this.sm = this.selModel;
48597 this.sm.xmodule = this.xmodule || false;
48599 if (typeof(this.colModel.config) == 'undefined') {
48600 this.colModel = new Roo.grid.ColumnModel(this.colModel);
48601 this.cm = this.colModel;
48602 this.cm.xmodule = this.xmodule || false;
48604 if (this.dataSource) {
48605 this.dataSource= Roo.factory(this.dataSource, Roo.data);
48606 this.ds = this.dataSource;
48607 this.ds.xmodule = this.xmodule || false;
48614 this.container.setWidth(this.width);
48618 this.container.setHeight(this.height);
48625 * The raw click event for the entire grid.
48626 * @param {Roo.EventObject} e
48631 * The raw dblclick event for the entire grid.
48632 * @param {Roo.EventObject} e
48636 * @event contextmenu
48637 * The raw contextmenu event for the entire grid.
48638 * @param {Roo.EventObject} e
48640 "contextmenu" : true,
48643 * The raw mousedown event for the entire grid.
48644 * @param {Roo.EventObject} e
48646 "mousedown" : true,
48649 * The raw mouseup event for the entire grid.
48650 * @param {Roo.EventObject} e
48655 * The raw mouseover event for the entire grid.
48656 * @param {Roo.EventObject} e
48658 "mouseover" : true,
48661 * The raw mouseout event for the entire grid.
48662 * @param {Roo.EventObject} e
48667 * The raw keypress event for the entire grid.
48668 * @param {Roo.EventObject} e
48673 * The raw keydown event for the entire grid.
48674 * @param {Roo.EventObject} e
48682 * Fires when a cell is clicked
48683 * @param {Grid} this
48684 * @param {Number} rowIndex
48685 * @param {Number} columnIndex
48686 * @param {Roo.EventObject} e
48688 "cellclick" : true,
48690 * @event celldblclick
48691 * Fires when a cell is double clicked
48692 * @param {Grid} this
48693 * @param {Number} rowIndex
48694 * @param {Number} columnIndex
48695 * @param {Roo.EventObject} e
48697 "celldblclick" : true,
48700 * Fires when a row is clicked
48701 * @param {Grid} this
48702 * @param {Number} rowIndex
48703 * @param {Roo.EventObject} e
48707 * @event rowdblclick
48708 * Fires when a row is double clicked
48709 * @param {Grid} this
48710 * @param {Number} rowIndex
48711 * @param {Roo.EventObject} e
48713 "rowdblclick" : true,
48715 * @event headerclick
48716 * Fires when a header is clicked
48717 * @param {Grid} this
48718 * @param {Number} columnIndex
48719 * @param {Roo.EventObject} e
48721 "headerclick" : true,
48723 * @event headerdblclick
48724 * Fires when a header cell is double clicked
48725 * @param {Grid} this
48726 * @param {Number} columnIndex
48727 * @param {Roo.EventObject} e
48729 "headerdblclick" : true,
48731 * @event rowcontextmenu
48732 * Fires when a row is right clicked
48733 * @param {Grid} this
48734 * @param {Number} rowIndex
48735 * @param {Roo.EventObject} e
48737 "rowcontextmenu" : true,
48739 * @event cellcontextmenu
48740 * Fires when a cell is right clicked
48741 * @param {Grid} this
48742 * @param {Number} rowIndex
48743 * @param {Number} cellIndex
48744 * @param {Roo.EventObject} e
48746 "cellcontextmenu" : true,
48748 * @event headercontextmenu
48749 * Fires when a header is right clicked
48750 * @param {Grid} this
48751 * @param {Number} columnIndex
48752 * @param {Roo.EventObject} e
48754 "headercontextmenu" : true,
48756 * @event bodyscroll
48757 * Fires when the body element is scrolled
48758 * @param {Number} scrollLeft
48759 * @param {Number} scrollTop
48761 "bodyscroll" : true,
48763 * @event columnresize
48764 * Fires when the user resizes a column
48765 * @param {Number} columnIndex
48766 * @param {Number} newSize
48768 "columnresize" : true,
48770 * @event columnmove
48771 * Fires when the user moves a column
48772 * @param {Number} oldIndex
48773 * @param {Number} newIndex
48775 "columnmove" : true,
48778 * Fires when row(s) start being dragged
48779 * @param {Grid} this
48780 * @param {Roo.GridDD} dd The drag drop object
48781 * @param {event} e The raw browser event
48783 "startdrag" : true,
48786 * Fires when a drag operation is complete
48787 * @param {Grid} this
48788 * @param {Roo.GridDD} dd The drag drop object
48789 * @param {event} e The raw browser event
48794 * Fires when dragged row(s) are dropped on a valid DD target
48795 * @param {Grid} this
48796 * @param {Roo.GridDD} dd The drag drop object
48797 * @param {String} targetId The target drag drop object
48798 * @param {event} e The raw browser event
48803 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
48804 * @param {Grid} this
48805 * @param {Roo.GridDD} dd The drag drop object
48806 * @param {String} targetId The target drag drop object
48807 * @param {event} e The raw browser event
48812 * Fires when the dragged row(s) first cross another DD target while being dragged
48813 * @param {Grid} this
48814 * @param {Roo.GridDD} dd The drag drop object
48815 * @param {String} targetId The target drag drop object
48816 * @param {event} e The raw browser event
48818 "dragenter" : true,
48821 * Fires when the dragged row(s) leave another DD target while being dragged
48822 * @param {Grid} this
48823 * @param {Roo.GridDD} dd The drag drop object
48824 * @param {String} targetId The target drag drop object
48825 * @param {event} e The raw browser event
48830 * Fires when a row is rendered, so you can change add a style to it.
48831 * @param {GridView} gridview The grid view
48832 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
48838 * Fires when the grid is rendered
48839 * @param {Grid} grid
48844 Roo.grid.Grid.superclass.constructor.call(this);
48846 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
48849 * @cfg {String} ddGroup - drag drop group.
48853 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
48855 minColumnWidth : 25,
48858 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
48859 * <b>on initial render.</b> It is more efficient to explicitly size the columns
48860 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
48862 autoSizeColumns : false,
48865 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
48867 autoSizeHeaders : true,
48870 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
48872 monitorWindowResize : true,
48875 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
48876 * rows measured to get a columns size. Default is 0 (all rows).
48878 maxRowsToMeasure : 0,
48881 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
48883 trackMouseOver : true,
48886 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
48890 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
48892 enableDragDrop : false,
48895 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
48897 enableColumnMove : true,
48900 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
48902 enableColumnHide : true,
48905 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
48907 enableRowHeightSync : false,
48910 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
48915 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
48917 autoHeight : false,
48920 * @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.
48922 autoExpandColumn : false,
48925 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
48928 autoExpandMin : 50,
48931 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
48933 autoExpandMax : 1000,
48936 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
48941 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
48945 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
48955 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
48956 * of a fixed width. Default is false.
48959 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
48962 * Called once after all setup has been completed and the grid is ready to be rendered.
48963 * @return {Roo.grid.Grid} this
48965 render : function()
48967 var c = this.container;
48968 // try to detect autoHeight/width mode
48969 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
48970 this.autoHeight = true;
48972 var view = this.getView();
48975 c.on("click", this.onClick, this);
48976 c.on("dblclick", this.onDblClick, this);
48977 c.on("contextmenu", this.onContextMenu, this);
48978 c.on("keydown", this.onKeyDown, this);
48980 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
48982 this.getSelectionModel().init(this);
48987 this.loadMask = new Roo.LoadMask(this.container,
48988 Roo.apply({store:this.dataSource}, this.loadMask));
48992 if (this.toolbar && this.toolbar.xtype) {
48993 this.toolbar.container = this.getView().getHeaderPanel(true);
48994 this.toolbar = new Roo.Toolbar(this.toolbar);
48996 if (this.footer && this.footer.xtype) {
48997 this.footer.dataSource = this.getDataSource();
48998 this.footer.container = this.getView().getFooterPanel(true);
48999 this.footer = Roo.factory(this.footer, Roo);
49001 if (this.dropTarget && this.dropTarget.xtype) {
49002 delete this.dropTarget.xtype;
49003 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
49007 this.rendered = true;
49008 this.fireEvent('render', this);
49013 * Reconfigures the grid to use a different Store and Column Model.
49014 * The View will be bound to the new objects and refreshed.
49015 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
49016 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
49018 reconfigure : function(dataSource, colModel){
49020 this.loadMask.destroy();
49021 this.loadMask = new Roo.LoadMask(this.container,
49022 Roo.apply({store:dataSource}, this.loadMask));
49024 this.view.bind(dataSource, colModel);
49025 this.dataSource = dataSource;
49026 this.colModel = colModel;
49027 this.view.refresh(true);
49031 onKeyDown : function(e){
49032 this.fireEvent("keydown", e);
49036 * Destroy this grid.
49037 * @param {Boolean} removeEl True to remove the element
49039 destroy : function(removeEl, keepListeners){
49041 this.loadMask.destroy();
49043 var c = this.container;
49044 c.removeAllListeners();
49045 this.view.destroy();
49046 this.colModel.purgeListeners();
49047 if(!keepListeners){
49048 this.purgeListeners();
49051 if(removeEl === true){
49057 processEvent : function(name, e){
49058 this.fireEvent(name, e);
49059 var t = e.getTarget();
49061 var header = v.findHeaderIndex(t);
49062 if(header !== false){
49063 this.fireEvent("header" + name, this, header, e);
49065 var row = v.findRowIndex(t);
49066 var cell = v.findCellIndex(t);
49068 this.fireEvent("row" + name, this, row, e);
49069 if(cell !== false){
49070 this.fireEvent("cell" + name, this, row, cell, e);
49077 onClick : function(e){
49078 this.processEvent("click", e);
49082 onContextMenu : function(e, t){
49083 this.processEvent("contextmenu", e);
49087 onDblClick : function(e){
49088 this.processEvent("dblclick", e);
49092 walkCells : function(row, col, step, fn, scope){
49093 var cm = this.colModel, clen = cm.getColumnCount();
49094 var ds = this.dataSource, rlen = ds.getCount(), first = true;
49106 if(fn.call(scope || this, row, col, cm) === true){
49124 if(fn.call(scope || this, row, col, cm) === true){
49136 getSelections : function(){
49137 return this.selModel.getSelections();
49141 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
49142 * but if manual update is required this method will initiate it.
49144 autoSize : function(){
49146 this.view.layout();
49147 if(this.view.adjustForScroll){
49148 this.view.adjustForScroll();
49154 * Returns the grid's underlying element.
49155 * @return {Element} The element
49157 getGridEl : function(){
49158 return this.container;
49161 // private for compatibility, overridden by editor grid
49162 stopEditing : function(){},
49165 * Returns the grid's SelectionModel.
49166 * @return {SelectionModel}
49168 getSelectionModel : function(){
49169 if(!this.selModel){
49170 this.selModel = new Roo.grid.RowSelectionModel();
49172 return this.selModel;
49176 * Returns the grid's DataSource.
49177 * @return {DataSource}
49179 getDataSource : function(){
49180 return this.dataSource;
49184 * Returns the grid's ColumnModel.
49185 * @return {ColumnModel}
49187 getColumnModel : function(){
49188 return this.colModel;
49192 * Returns the grid's GridView object.
49193 * @return {GridView}
49195 getView : function(){
49197 this.view = new Roo.grid.GridView(this.viewConfig);
49202 * Called to get grid's drag proxy text, by default returns this.ddText.
49205 getDragDropText : function(){
49206 var count = this.selModel.getCount();
49207 return String.format(this.ddText, count, count == 1 ? '' : 's');
49211 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
49212 * %0 is replaced with the number of selected rows.
49215 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
49217 * Ext JS Library 1.1.1
49218 * Copyright(c) 2006-2007, Ext JS, LLC.
49220 * Originally Released Under LGPL - original licence link has changed is not relivant.
49223 * <script type="text/javascript">
49226 Roo.grid.AbstractGridView = function(){
49230 "beforerowremoved" : true,
49231 "beforerowsinserted" : true,
49232 "beforerefresh" : true,
49233 "rowremoved" : true,
49234 "rowsinserted" : true,
49235 "rowupdated" : true,
49238 Roo.grid.AbstractGridView.superclass.constructor.call(this);
49241 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
49242 rowClass : "x-grid-row",
49243 cellClass : "x-grid-cell",
49244 tdClass : "x-grid-td",
49245 hdClass : "x-grid-hd",
49246 splitClass : "x-grid-hd-split",
49248 init: function(grid){
49250 var cid = this.grid.getGridEl().id;
49251 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
49252 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
49253 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
49254 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
49257 getColumnRenderers : function(){
49258 var renderers = [];
49259 var cm = this.grid.colModel;
49260 var colCount = cm.getColumnCount();
49261 for(var i = 0; i < colCount; i++){
49262 renderers[i] = cm.getRenderer(i);
49267 getColumnIds : function(){
49269 var cm = this.grid.colModel;
49270 var colCount = cm.getColumnCount();
49271 for(var i = 0; i < colCount; i++){
49272 ids[i] = cm.getColumnId(i);
49277 getDataIndexes : function(){
49278 if(!this.indexMap){
49279 this.indexMap = this.buildIndexMap();
49281 return this.indexMap.colToData;
49284 getColumnIndexByDataIndex : function(dataIndex){
49285 if(!this.indexMap){
49286 this.indexMap = this.buildIndexMap();
49288 return this.indexMap.dataToCol[dataIndex];
49292 * Set a css style for a column dynamically.
49293 * @param {Number} colIndex The index of the column
49294 * @param {String} name The css property name
49295 * @param {String} value The css value
49297 setCSSStyle : function(colIndex, name, value){
49298 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
49299 Roo.util.CSS.updateRule(selector, name, value);
49302 generateRules : function(cm){
49303 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
49304 Roo.util.CSS.removeStyleSheet(rulesId);
49305 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49306 var cid = cm.getColumnId(i);
49307 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
49308 this.tdSelector, cid, " {\n}\n",
49309 this.hdSelector, cid, " {\n}\n",
49310 this.splitSelector, cid, " {\n}\n");
49312 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49316 * Ext JS Library 1.1.1
49317 * Copyright(c) 2006-2007, Ext JS, LLC.
49319 * Originally Released Under LGPL - original licence link has changed is not relivant.
49322 * <script type="text/javascript">
49326 // This is a support class used internally by the Grid components
49327 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
49329 this.view = grid.getView();
49330 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
49331 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
49333 this.setHandleElId(Roo.id(hd));
49334 this.setOuterHandleElId(Roo.id(hd2));
49336 this.scroll = false;
49338 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
49340 getDragData : function(e){
49341 var t = Roo.lib.Event.getTarget(e);
49342 var h = this.view.findHeaderCell(t);
49344 return {ddel: h.firstChild, header:h};
49349 onInitDrag : function(e){
49350 this.view.headersDisabled = true;
49351 var clone = this.dragData.ddel.cloneNode(true);
49352 clone.id = Roo.id();
49353 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
49354 this.proxy.update(clone);
49358 afterValidDrop : function(){
49360 setTimeout(function(){
49361 v.headersDisabled = false;
49365 afterInvalidDrop : function(){
49367 setTimeout(function(){
49368 v.headersDisabled = false;
49374 * Ext JS Library 1.1.1
49375 * Copyright(c) 2006-2007, Ext JS, LLC.
49377 * Originally Released Under LGPL - original licence link has changed is not relivant.
49380 * <script type="text/javascript">
49383 // This is a support class used internally by the Grid components
49384 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
49386 this.view = grid.getView();
49387 // split the proxies so they don't interfere with mouse events
49388 this.proxyTop = Roo.DomHelper.append(document.body, {
49389 cls:"col-move-top", html:" "
49391 this.proxyBottom = Roo.DomHelper.append(document.body, {
49392 cls:"col-move-bottom", html:" "
49394 this.proxyTop.hide = this.proxyBottom.hide = function(){
49395 this.setLeftTop(-100,-100);
49396 this.setStyle("visibility", "hidden");
49398 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
49399 // temporarily disabled
49400 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
49401 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
49403 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
49404 proxyOffsets : [-4, -9],
49405 fly: Roo.Element.fly,
49407 getTargetFromEvent : function(e){
49408 var t = Roo.lib.Event.getTarget(e);
49409 var cindex = this.view.findCellIndex(t);
49410 if(cindex !== false){
49411 return this.view.getHeaderCell(cindex);
49416 nextVisible : function(h){
49417 var v = this.view, cm = this.grid.colModel;
49420 if(!cm.isHidden(v.getCellIndex(h))){
49428 prevVisible : function(h){
49429 var v = this.view, cm = this.grid.colModel;
49432 if(!cm.isHidden(v.getCellIndex(h))){
49440 positionIndicator : function(h, n, e){
49441 var x = Roo.lib.Event.getPageX(e);
49442 var r = Roo.lib.Dom.getRegion(n.firstChild);
49443 var px, pt, py = r.top + this.proxyOffsets[1];
49444 if((r.right - x) <= (r.right-r.left)/2){
49445 px = r.right+this.view.borderWidth;
49451 var oldIndex = this.view.getCellIndex(h);
49452 var newIndex = this.view.getCellIndex(n);
49454 if(this.grid.colModel.isFixed(newIndex)){
49458 var locked = this.grid.colModel.isLocked(newIndex);
49463 if(oldIndex < newIndex){
49466 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
49469 px += this.proxyOffsets[0];
49470 this.proxyTop.setLeftTop(px, py);
49471 this.proxyTop.show();
49472 if(!this.bottomOffset){
49473 this.bottomOffset = this.view.mainHd.getHeight();
49475 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
49476 this.proxyBottom.show();
49480 onNodeEnter : function(n, dd, e, data){
49481 if(data.header != n){
49482 this.positionIndicator(data.header, n, e);
49486 onNodeOver : function(n, dd, e, data){
49487 var result = false;
49488 if(data.header != n){
49489 result = this.positionIndicator(data.header, n, e);
49492 this.proxyTop.hide();
49493 this.proxyBottom.hide();
49495 return result ? this.dropAllowed : this.dropNotAllowed;
49498 onNodeOut : function(n, dd, e, data){
49499 this.proxyTop.hide();
49500 this.proxyBottom.hide();
49503 onNodeDrop : function(n, dd, e, data){
49504 var h = data.header;
49506 var cm = this.grid.colModel;
49507 var x = Roo.lib.Event.getPageX(e);
49508 var r = Roo.lib.Dom.getRegion(n.firstChild);
49509 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
49510 var oldIndex = this.view.getCellIndex(h);
49511 var newIndex = this.view.getCellIndex(n);
49512 var locked = cm.isLocked(newIndex);
49516 if(oldIndex < newIndex){
49519 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
49522 cm.setLocked(oldIndex, locked, true);
49523 cm.moveColumn(oldIndex, newIndex);
49524 this.grid.fireEvent("columnmove", oldIndex, newIndex);
49532 * Ext JS Library 1.1.1
49533 * Copyright(c) 2006-2007, Ext JS, LLC.
49535 * Originally Released Under LGPL - original licence link has changed is not relivant.
49538 * <script type="text/javascript">
49542 * @class Roo.grid.GridView
49543 * @extends Roo.util.Observable
49546 * @param {Object} config
49548 Roo.grid.GridView = function(config){
49549 Roo.grid.GridView.superclass.constructor.call(this);
49552 Roo.apply(this, config);
49555 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
49558 rowClass : "x-grid-row",
49560 cellClass : "x-grid-col",
49562 tdClass : "x-grid-td",
49564 hdClass : "x-grid-hd",
49566 splitClass : "x-grid-split",
49568 sortClasses : ["sort-asc", "sort-desc"],
49570 enableMoveAnim : false,
49574 dh : Roo.DomHelper,
49576 fly : Roo.Element.fly,
49578 css : Roo.util.CSS,
49584 scrollIncrement : 22,
49586 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
49588 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
49590 bind : function(ds, cm){
49592 this.ds.un("load", this.onLoad, this);
49593 this.ds.un("datachanged", this.onDataChange, this);
49594 this.ds.un("add", this.onAdd, this);
49595 this.ds.un("remove", this.onRemove, this);
49596 this.ds.un("update", this.onUpdate, this);
49597 this.ds.un("clear", this.onClear, this);
49600 ds.on("load", this.onLoad, this);
49601 ds.on("datachanged", this.onDataChange, this);
49602 ds.on("add", this.onAdd, this);
49603 ds.on("remove", this.onRemove, this);
49604 ds.on("update", this.onUpdate, this);
49605 ds.on("clear", this.onClear, this);
49610 this.cm.un("widthchange", this.onColWidthChange, this);
49611 this.cm.un("headerchange", this.onHeaderChange, this);
49612 this.cm.un("hiddenchange", this.onHiddenChange, this);
49613 this.cm.un("columnmoved", this.onColumnMove, this);
49614 this.cm.un("columnlockchange", this.onColumnLock, this);
49617 this.generateRules(cm);
49618 cm.on("widthchange", this.onColWidthChange, this);
49619 cm.on("headerchange", this.onHeaderChange, this);
49620 cm.on("hiddenchange", this.onHiddenChange, this);
49621 cm.on("columnmoved", this.onColumnMove, this);
49622 cm.on("columnlockchange", this.onColumnLock, this);
49627 init: function(grid){
49628 Roo.grid.GridView.superclass.init.call(this, grid);
49630 this.bind(grid.dataSource, grid.colModel);
49632 grid.on("headerclick", this.handleHeaderClick, this);
49634 if(grid.trackMouseOver){
49635 grid.on("mouseover", this.onRowOver, this);
49636 grid.on("mouseout", this.onRowOut, this);
49638 grid.cancelTextSelection = function(){};
49639 this.gridId = grid.id;
49641 var tpls = this.templates || {};
49644 tpls.master = new Roo.Template(
49645 '<div class="x-grid" hidefocus="true">',
49646 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
49647 '<div class="x-grid-topbar"></div>',
49648 '<div class="x-grid-scroller"><div></div></div>',
49649 '<div class="x-grid-locked">',
49650 '<div class="x-grid-header">{lockedHeader}</div>',
49651 '<div class="x-grid-body">{lockedBody}</div>',
49653 '<div class="x-grid-viewport">',
49654 '<div class="x-grid-header">{header}</div>',
49655 '<div class="x-grid-body">{body}</div>',
49657 '<div class="x-grid-bottombar"></div>',
49659 '<div class="x-grid-resize-proxy"> </div>',
49662 tpls.master.disableformats = true;
49666 tpls.header = new Roo.Template(
49667 '<table border="0" cellspacing="0" cellpadding="0">',
49668 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
49671 tpls.header.disableformats = true;
49673 tpls.header.compile();
49676 tpls.hcell = new Roo.Template(
49677 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
49678 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
49681 tpls.hcell.disableFormats = true;
49683 tpls.hcell.compile();
49686 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
49687 tpls.hsplit.disableFormats = true;
49689 tpls.hsplit.compile();
49692 tpls.body = new Roo.Template(
49693 '<table border="0" cellspacing="0" cellpadding="0">',
49694 "<tbody>{rows}</tbody>",
49697 tpls.body.disableFormats = true;
49699 tpls.body.compile();
49702 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
49703 tpls.row.disableFormats = true;
49705 tpls.row.compile();
49708 tpls.cell = new Roo.Template(
49709 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
49710 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
49713 tpls.cell.disableFormats = true;
49715 tpls.cell.compile();
49717 this.templates = tpls;
49720 // remap these for backwards compat
49721 onColWidthChange : function(){
49722 this.updateColumns.apply(this, arguments);
49724 onHeaderChange : function(){
49725 this.updateHeaders.apply(this, arguments);
49727 onHiddenChange : function(){
49728 this.handleHiddenChange.apply(this, arguments);
49730 onColumnMove : function(){
49731 this.handleColumnMove.apply(this, arguments);
49733 onColumnLock : function(){
49734 this.handleLockChange.apply(this, arguments);
49737 onDataChange : function(){
49739 this.updateHeaderSortState();
49742 onClear : function(){
49746 onUpdate : function(ds, record){
49747 this.refreshRow(record);
49750 refreshRow : function(record){
49751 var ds = this.ds, index;
49752 if(typeof record == 'number'){
49754 record = ds.getAt(index);
49756 index = ds.indexOf(record);
49758 this.insertRows(ds, index, index, true);
49759 this.onRemove(ds, record, index+1, true);
49760 this.syncRowHeights(index, index);
49762 this.fireEvent("rowupdated", this, index, record);
49765 onAdd : function(ds, records, index){
49766 this.insertRows(ds, index, index + (records.length-1));
49769 onRemove : function(ds, record, index, isUpdate){
49770 if(isUpdate !== true){
49771 this.fireEvent("beforerowremoved", this, index, record);
49773 var bt = this.getBodyTable(), lt = this.getLockedTable();
49774 if(bt.rows[index]){
49775 bt.firstChild.removeChild(bt.rows[index]);
49777 if(lt.rows[index]){
49778 lt.firstChild.removeChild(lt.rows[index]);
49780 if(isUpdate !== true){
49781 this.stripeRows(index);
49782 this.syncRowHeights(index, index);
49784 this.fireEvent("rowremoved", this, index, record);
49788 onLoad : function(){
49789 this.scrollToTop();
49793 * Scrolls the grid to the top
49795 scrollToTop : function(){
49797 this.scroller.dom.scrollTop = 0;
49803 * Gets a panel in the header of the grid that can be used for toolbars etc.
49804 * After modifying the contents of this panel a call to grid.autoSize() may be
49805 * required to register any changes in size.
49806 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
49807 * @return Roo.Element
49809 getHeaderPanel : function(doShow){
49811 this.headerPanel.show();
49813 return this.headerPanel;
49817 * Gets a panel in the footer of the grid that can be used for toolbars etc.
49818 * After modifying the contents of this panel a call to grid.autoSize() may be
49819 * required to register any changes in size.
49820 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
49821 * @return Roo.Element
49823 getFooterPanel : function(doShow){
49825 this.footerPanel.show();
49827 return this.footerPanel;
49830 initElements : function(){
49831 var E = Roo.Element;
49832 var el = this.grid.getGridEl().dom.firstChild;
49833 var cs = el.childNodes;
49835 this.el = new E(el);
49837 this.focusEl = new E(el.firstChild);
49838 this.focusEl.swallowEvent("click", true);
49840 this.headerPanel = new E(cs[1]);
49841 this.headerPanel.enableDisplayMode("block");
49843 this.scroller = new E(cs[2]);
49844 this.scrollSizer = new E(this.scroller.dom.firstChild);
49846 this.lockedWrap = new E(cs[3]);
49847 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
49848 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
49850 this.mainWrap = new E(cs[4]);
49851 this.mainHd = new E(this.mainWrap.dom.firstChild);
49852 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
49854 this.footerPanel = new E(cs[5]);
49855 this.footerPanel.enableDisplayMode("block");
49857 this.resizeProxy = new E(cs[6]);
49859 this.headerSelector = String.format(
49860 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
49861 this.lockedHd.id, this.mainHd.id
49864 this.splitterSelector = String.format(
49865 '#{0} div.x-grid-split, #{1} div.x-grid-split',
49866 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
49869 idToCssName : function(s)
49871 return s.replace(/[^a-z0-9]+/ig, '-');
49874 getHeaderCell : function(index){
49875 return Roo.DomQuery.select(this.headerSelector)[index];
49878 getHeaderCellMeasure : function(index){
49879 return this.getHeaderCell(index).firstChild;
49882 getHeaderCellText : function(index){
49883 return this.getHeaderCell(index).firstChild.firstChild;
49886 getLockedTable : function(){
49887 return this.lockedBody.dom.firstChild;
49890 getBodyTable : function(){
49891 return this.mainBody.dom.firstChild;
49894 getLockedRow : function(index){
49895 return this.getLockedTable().rows[index];
49898 getRow : function(index){
49899 return this.getBodyTable().rows[index];
49902 getRowComposite : function(index){
49904 this.rowEl = new Roo.CompositeElementLite();
49906 var els = [], lrow, mrow;
49907 if(lrow = this.getLockedRow(index)){
49910 if(mrow = this.getRow(index)){
49913 this.rowEl.elements = els;
49917 * Gets the 'td' of the cell
49919 * @param {Integer} rowIndex row to select
49920 * @param {Integer} colIndex column to select
49924 getCell : function(rowIndex, colIndex){
49925 var locked = this.cm.getLockedCount();
49927 if(colIndex < locked){
49928 source = this.lockedBody.dom.firstChild;
49930 source = this.mainBody.dom.firstChild;
49931 colIndex -= locked;
49933 return source.rows[rowIndex].childNodes[colIndex];
49936 getCellText : function(rowIndex, colIndex){
49937 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
49940 getCellBox : function(cell){
49941 var b = this.fly(cell).getBox();
49942 if(Roo.isOpera){ // opera fails to report the Y
49943 b.y = cell.offsetTop + this.mainBody.getY();
49948 getCellIndex : function(cell){
49949 var id = String(cell.className).match(this.cellRE);
49951 return parseInt(id[1], 10);
49956 findHeaderIndex : function(n){
49957 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
49958 return r ? this.getCellIndex(r) : false;
49961 findHeaderCell : function(n){
49962 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
49963 return r ? r : false;
49966 findRowIndex : function(n){
49970 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
49971 return r ? r.rowIndex : false;
49974 findCellIndex : function(node){
49975 var stop = this.el.dom;
49976 while(node && node != stop){
49977 if(this.findRE.test(node.className)){
49978 return this.getCellIndex(node);
49980 node = node.parentNode;
49985 getColumnId : function(index){
49986 return this.cm.getColumnId(index);
49989 getSplitters : function()
49991 if(this.splitterSelector){
49992 return Roo.DomQuery.select(this.splitterSelector);
49998 getSplitter : function(index){
49999 return this.getSplitters()[index];
50002 onRowOver : function(e, t){
50004 if((row = this.findRowIndex(t)) !== false){
50005 this.getRowComposite(row).addClass("x-grid-row-over");
50009 onRowOut : function(e, t){
50011 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
50012 this.getRowComposite(row).removeClass("x-grid-row-over");
50016 renderHeaders : function(){
50018 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
50019 var cb = [], lb = [], sb = [], lsb = [], p = {};
50020 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50021 p.cellId = "x-grid-hd-0-" + i;
50022 p.splitId = "x-grid-csplit-0-" + i;
50023 p.id = cm.getColumnId(i);
50024 p.title = cm.getColumnTooltip(i) || "";
50025 p.value = cm.getColumnHeader(i) || "";
50026 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
50027 if(!cm.isLocked(i)){
50028 cb[cb.length] = ct.apply(p);
50029 sb[sb.length] = st.apply(p);
50031 lb[lb.length] = ct.apply(p);
50032 lsb[lsb.length] = st.apply(p);
50035 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
50036 ht.apply({cells: cb.join(""), splits:sb.join("")})];
50039 updateHeaders : function(){
50040 var html = this.renderHeaders();
50041 this.lockedHd.update(html[0]);
50042 this.mainHd.update(html[1]);
50046 * Focuses the specified row.
50047 * @param {Number} row The row index
50049 focusRow : function(row)
50051 //Roo.log('GridView.focusRow');
50052 var x = this.scroller.dom.scrollLeft;
50053 this.focusCell(row, 0, false);
50054 this.scroller.dom.scrollLeft = x;
50058 * Focuses the specified cell.
50059 * @param {Number} row The row index
50060 * @param {Number} col The column index
50061 * @param {Boolean} hscroll false to disable horizontal scrolling
50063 focusCell : function(row, col, hscroll)
50065 //Roo.log('GridView.focusCell');
50066 var el = this.ensureVisible(row, col, hscroll);
50067 this.focusEl.alignTo(el, "tl-tl");
50069 this.focusEl.focus();
50071 this.focusEl.focus.defer(1, this.focusEl);
50076 * Scrolls the specified cell into view
50077 * @param {Number} row The row index
50078 * @param {Number} col The column index
50079 * @param {Boolean} hscroll false to disable horizontal scrolling
50081 ensureVisible : function(row, col, hscroll)
50083 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
50084 //return null; //disable for testing.
50085 if(typeof row != "number"){
50086 row = row.rowIndex;
50088 if(row < 0 && row >= this.ds.getCount()){
50091 col = (col !== undefined ? col : 0);
50092 var cm = this.grid.colModel;
50093 while(cm.isHidden(col)){
50097 var el = this.getCell(row, col);
50101 var c = this.scroller.dom;
50103 var ctop = parseInt(el.offsetTop, 10);
50104 var cleft = parseInt(el.offsetLeft, 10);
50105 var cbot = ctop + el.offsetHeight;
50106 var cright = cleft + el.offsetWidth;
50108 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
50109 var stop = parseInt(c.scrollTop, 10);
50110 var sleft = parseInt(c.scrollLeft, 10);
50111 var sbot = stop + ch;
50112 var sright = sleft + c.clientWidth;
50114 Roo.log('GridView.ensureVisible:' +
50116 ' c.clientHeight:' + c.clientHeight +
50117 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
50125 c.scrollTop = ctop;
50126 //Roo.log("set scrolltop to ctop DISABLE?");
50127 }else if(cbot > sbot){
50128 //Roo.log("set scrolltop to cbot-ch");
50129 c.scrollTop = cbot-ch;
50132 if(hscroll !== false){
50134 c.scrollLeft = cleft;
50135 }else if(cright > sright){
50136 c.scrollLeft = cright-c.clientWidth;
50143 updateColumns : function(){
50144 this.grid.stopEditing();
50145 var cm = this.grid.colModel, colIds = this.getColumnIds();
50146 //var totalWidth = cm.getTotalWidth();
50148 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50149 //if(cm.isHidden(i)) continue;
50150 var w = cm.getColumnWidth(i);
50151 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50152 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50154 this.updateSplitters();
50157 generateRules : function(cm){
50158 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
50159 Roo.util.CSS.removeStyleSheet(rulesId);
50160 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50161 var cid = cm.getColumnId(i);
50163 if(cm.config[i].align){
50164 align = 'text-align:'+cm.config[i].align+';';
50167 if(cm.isHidden(i)){
50168 hidden = 'display:none;';
50170 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
50172 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
50173 this.hdSelector, cid, " {\n", align, width, "}\n",
50174 this.tdSelector, cid, " {\n",hidden,"\n}\n",
50175 this.splitSelector, cid, " {\n", hidden , "\n}\n");
50177 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
50180 updateSplitters : function(){
50181 var cm = this.cm, s = this.getSplitters();
50182 if(s){ // splitters not created yet
50183 var pos = 0, locked = true;
50184 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50185 if(cm.isHidden(i)) continue;
50186 var w = cm.getColumnWidth(i); // make sure it's a number
50187 if(!cm.isLocked(i) && locked){
50192 s[i].style.left = (pos-this.splitOffset) + "px";
50197 handleHiddenChange : function(colModel, colIndex, hidden){
50199 this.hideColumn(colIndex);
50201 this.unhideColumn(colIndex);
50205 hideColumn : function(colIndex){
50206 var cid = this.getColumnId(colIndex);
50207 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
50208 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
50210 this.updateHeaders();
50212 this.updateSplitters();
50216 unhideColumn : function(colIndex){
50217 var cid = this.getColumnId(colIndex);
50218 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
50219 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
50222 this.updateHeaders();
50224 this.updateSplitters();
50228 insertRows : function(dm, firstRow, lastRow, isUpdate){
50229 if(firstRow == 0 && lastRow == dm.getCount()-1){
50233 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
50235 var s = this.getScrollState();
50236 var markup = this.renderRows(firstRow, lastRow);
50237 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
50238 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
50239 this.restoreScroll(s);
50241 this.fireEvent("rowsinserted", this, firstRow, lastRow);
50242 this.syncRowHeights(firstRow, lastRow);
50243 this.stripeRows(firstRow);
50249 bufferRows : function(markup, target, index){
50250 var before = null, trows = target.rows, tbody = target.tBodies[0];
50251 if(index < trows.length){
50252 before = trows[index];
50254 var b = document.createElement("div");
50255 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
50256 var rows = b.firstChild.rows;
50257 for(var i = 0, len = rows.length; i < len; i++){
50259 tbody.insertBefore(rows[0], before);
50261 tbody.appendChild(rows[0]);
50268 deleteRows : function(dm, firstRow, lastRow){
50269 if(dm.getRowCount()<1){
50270 this.fireEvent("beforerefresh", this);
50271 this.mainBody.update("");
50272 this.lockedBody.update("");
50273 this.fireEvent("refresh", this);
50275 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
50276 var bt = this.getBodyTable();
50277 var tbody = bt.firstChild;
50278 var rows = bt.rows;
50279 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
50280 tbody.removeChild(rows[firstRow]);
50282 this.stripeRows(firstRow);
50283 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
50287 updateRows : function(dataSource, firstRow, lastRow){
50288 var s = this.getScrollState();
50290 this.restoreScroll(s);
50293 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
50297 this.updateHeaderSortState();
50300 getScrollState : function(){
50302 var sb = this.scroller.dom;
50303 return {left: sb.scrollLeft, top: sb.scrollTop};
50306 stripeRows : function(startRow){
50307 if(!this.grid.stripeRows || this.ds.getCount() < 1){
50310 startRow = startRow || 0;
50311 var rows = this.getBodyTable().rows;
50312 var lrows = this.getLockedTable().rows;
50313 var cls = ' x-grid-row-alt ';
50314 for(var i = startRow, len = rows.length; i < len; i++){
50315 var row = rows[i], lrow = lrows[i];
50316 var isAlt = ((i+1) % 2 == 0);
50317 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
50318 if(isAlt == hasAlt){
50322 row.className += " x-grid-row-alt";
50324 row.className = row.className.replace("x-grid-row-alt", "");
50327 lrow.className = row.className;
50332 restoreScroll : function(state){
50333 //Roo.log('GridView.restoreScroll');
50334 var sb = this.scroller.dom;
50335 sb.scrollLeft = state.left;
50336 sb.scrollTop = state.top;
50340 syncScroll : function(){
50341 //Roo.log('GridView.syncScroll');
50342 var sb = this.scroller.dom;
50343 var sh = this.mainHd.dom;
50344 var bs = this.mainBody.dom;
50345 var lv = this.lockedBody.dom;
50346 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
50347 lv.scrollTop = bs.scrollTop = sb.scrollTop;
50350 handleScroll : function(e){
50352 var sb = this.scroller.dom;
50353 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
50357 handleWheel : function(e){
50358 var d = e.getWheelDelta();
50359 this.scroller.dom.scrollTop -= d*22;
50360 // set this here to prevent jumpy scrolling on large tables
50361 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
50365 renderRows : function(startRow, endRow){
50366 // pull in all the crap needed to render rows
50367 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
50368 var colCount = cm.getColumnCount();
50370 if(ds.getCount() < 1){
50374 // build a map for all the columns
50376 for(var i = 0; i < colCount; i++){
50377 var name = cm.getDataIndex(i);
50379 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
50380 renderer : cm.getRenderer(i),
50381 id : cm.getColumnId(i),
50382 locked : cm.isLocked(i)
50386 startRow = startRow || 0;
50387 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
50389 // records to render
50390 var rs = ds.getRange(startRow, endRow);
50392 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
50395 // As much as I hate to duplicate code, this was branched because FireFox really hates
50396 // [].join("") on strings. The performance difference was substantial enough to
50397 // branch this function
50398 doRender : Roo.isGecko ?
50399 function(cs, rs, ds, startRow, colCount, stripe){
50400 var ts = this.templates, ct = ts.cell, rt = ts.row;
50402 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
50404 var hasListener = this.grid.hasListener('rowclass');
50406 for(var j = 0, len = rs.length; j < len; j++){
50407 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
50408 for(var i = 0; i < colCount; i++){
50410 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
50412 p.css = p.attr = "";
50413 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
50414 if(p.value == undefined || p.value === "") p.value = " ";
50415 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
50416 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
50418 var markup = ct.apply(p);
50426 if(stripe && ((rowIndex+1) % 2 == 0)){
50427 alt.push("x-grid-row-alt")
50430 alt.push( " x-grid-dirty-row");
50433 if(this.getRowClass){
50434 alt.push(this.getRowClass(r, rowIndex));
50440 rowIndex : rowIndex,
50443 this.grid.fireEvent('rowclass', this, rowcfg);
50444 alt.push(rowcfg.rowClass);
50446 rp.alt = alt.join(" ");
50447 lbuf+= rt.apply(rp);
50449 buf+= rt.apply(rp);
50451 return [lbuf, buf];
50453 function(cs, rs, ds, startRow, colCount, stripe){
50454 var ts = this.templates, ct = ts.cell, rt = ts.row;
50456 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
50457 var hasListener = this.grid.hasListener('rowclass');
50460 for(var j = 0, len = rs.length; j < len; j++){
50461 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
50462 for(var i = 0; i < colCount; i++){
50464 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
50466 p.css = p.attr = "";
50467 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
50468 if(p.value == undefined || p.value === "") p.value = " ";
50469 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
50470 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
50473 var markup = ct.apply(p);
50475 cb[cb.length] = markup;
50477 lcb[lcb.length] = markup;
50481 if(stripe && ((rowIndex+1) % 2 == 0)){
50482 alt.push( "x-grid-row-alt");
50485 alt.push(" x-grid-dirty-row");
50488 if(this.getRowClass){
50489 alt.push( this.getRowClass(r, rowIndex));
50495 rowIndex : rowIndex,
50498 this.grid.fireEvent('rowclass', this, rowcfg);
50499 alt.push(rowcfg.rowClass);
50501 rp.alt = alt.join(" ");
50502 rp.cells = lcb.join("");
50503 lbuf[lbuf.length] = rt.apply(rp);
50504 rp.cells = cb.join("");
50505 buf[buf.length] = rt.apply(rp);
50507 return [lbuf.join(""), buf.join("")];
50510 renderBody : function(){
50511 var markup = this.renderRows();
50512 var bt = this.templates.body;
50513 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
50517 * Refreshes the grid
50518 * @param {Boolean} headersToo
50520 refresh : function(headersToo){
50521 this.fireEvent("beforerefresh", this);
50522 this.grid.stopEditing();
50523 var result = this.renderBody();
50524 this.lockedBody.update(result[0]);
50525 this.mainBody.update(result[1]);
50526 if(headersToo === true){
50527 this.updateHeaders();
50528 this.updateColumns();
50529 this.updateSplitters();
50530 this.updateHeaderSortState();
50532 this.syncRowHeights();
50534 this.fireEvent("refresh", this);
50537 handleColumnMove : function(cm, oldIndex, newIndex){
50538 this.indexMap = null;
50539 var s = this.getScrollState();
50540 this.refresh(true);
50541 this.restoreScroll(s);
50542 this.afterMove(newIndex);
50545 afterMove : function(colIndex){
50546 if(this.enableMoveAnim && Roo.enableFx){
50547 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
50549 // if multisort - fix sortOrder, and reload..
50550 if (this.grid.dataSource.multiSort) {
50551 // the we can call sort again..
50552 var dm = this.grid.dataSource;
50553 var cm = this.grid.colModel;
50555 for(var i = 0; i < cm.config.length; i++ ) {
50557 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
50558 continue; // dont' bother, it's not in sort list or being set.
50561 so.push(cm.config[i].dataIndex);
50564 dm.load(dm.lastOptions);
50571 updateCell : function(dm, rowIndex, dataIndex){
50572 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
50573 if(typeof colIndex == "undefined"){ // not present in grid
50576 var cm = this.grid.colModel;
50577 var cell = this.getCell(rowIndex, colIndex);
50578 var cellText = this.getCellText(rowIndex, colIndex);
50581 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
50582 id : cm.getColumnId(colIndex),
50583 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
50585 var renderer = cm.getRenderer(colIndex);
50586 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
50587 if(typeof val == "undefined" || val === "") val = " ";
50588 cellText.innerHTML = val;
50589 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
50590 this.syncRowHeights(rowIndex, rowIndex);
50593 calcColumnWidth : function(colIndex, maxRowsToMeasure){
50595 if(this.grid.autoSizeHeaders){
50596 var h = this.getHeaderCellMeasure(colIndex);
50597 maxWidth = Math.max(maxWidth, h.scrollWidth);
50600 if(this.cm.isLocked(colIndex)){
50601 tb = this.getLockedTable();
50604 tb = this.getBodyTable();
50605 index = colIndex - this.cm.getLockedCount();
50608 var rows = tb.rows;
50609 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
50610 for(var i = 0; i < stopIndex; i++){
50611 var cell = rows[i].childNodes[index].firstChild;
50612 maxWidth = Math.max(maxWidth, cell.scrollWidth);
50615 return maxWidth + /*margin for error in IE*/ 5;
50618 * Autofit a column to its content.
50619 * @param {Number} colIndex
50620 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
50622 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
50623 if(this.cm.isHidden(colIndex)){
50624 return; // can't calc a hidden column
50627 var cid = this.cm.getColumnId(colIndex);
50628 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
50629 if(this.grid.autoSizeHeaders){
50630 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
50633 var newWidth = this.calcColumnWidth(colIndex);
50634 this.cm.setColumnWidth(colIndex,
50635 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
50636 if(!suppressEvent){
50637 this.grid.fireEvent("columnresize", colIndex, newWidth);
50642 * Autofits all columns to their content and then expands to fit any extra space in the grid
50644 autoSizeColumns : function(){
50645 var cm = this.grid.colModel;
50646 var colCount = cm.getColumnCount();
50647 for(var i = 0; i < colCount; i++){
50648 this.autoSizeColumn(i, true, true);
50650 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
50653 this.updateColumns();
50659 * Autofits all columns to the grid's width proportionate with their current size
50660 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
50662 fitColumns : function(reserveScrollSpace){
50663 var cm = this.grid.colModel;
50664 var colCount = cm.getColumnCount();
50668 for (i = 0; i < colCount; i++){
50669 if(!cm.isHidden(i) && !cm.isFixed(i)){
50670 w = cm.getColumnWidth(i);
50676 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
50677 if(reserveScrollSpace){
50680 var frac = (avail - cm.getTotalWidth())/width;
50681 while (cols.length){
50684 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
50686 this.updateColumns();
50690 onRowSelect : function(rowIndex){
50691 var row = this.getRowComposite(rowIndex);
50692 row.addClass("x-grid-row-selected");
50695 onRowDeselect : function(rowIndex){
50696 var row = this.getRowComposite(rowIndex);
50697 row.removeClass("x-grid-row-selected");
50700 onCellSelect : function(row, col){
50701 var cell = this.getCell(row, col);
50703 Roo.fly(cell).addClass("x-grid-cell-selected");
50707 onCellDeselect : function(row, col){
50708 var cell = this.getCell(row, col);
50710 Roo.fly(cell).removeClass("x-grid-cell-selected");
50714 updateHeaderSortState : function(){
50716 // sort state can be single { field: xxx, direction : yyy}
50717 // or { xxx=>ASC , yyy : DESC ..... }
50720 if (!this.ds.multiSort) {
50721 var state = this.ds.getSortState();
50725 mstate[state.field] = state.direction;
50726 // FIXME... - this is not used here.. but might be elsewhere..
50727 this.sortState = state;
50730 mstate = this.ds.sortToggle;
50732 //remove existing sort classes..
50734 var sc = this.sortClasses;
50735 var hds = this.el.select(this.headerSelector).removeClass(sc);
50737 for(var f in mstate) {
50739 var sortColumn = this.cm.findColumnIndex(f);
50741 if(sortColumn != -1){
50742 var sortDir = mstate[f];
50743 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
50752 handleHeaderClick : function(g, index){
50753 if(this.headersDisabled){
50756 var dm = g.dataSource, cm = g.colModel;
50757 if(!cm.isSortable(index)){
50762 if (dm.multiSort) {
50763 // update the sortOrder
50765 for(var i = 0; i < cm.config.length; i++ ) {
50767 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
50768 continue; // dont' bother, it's not in sort list or being set.
50771 so.push(cm.config[i].dataIndex);
50777 dm.sort(cm.getDataIndex(index));
50781 destroy : function(){
50783 this.colMenu.removeAll();
50784 Roo.menu.MenuMgr.unregister(this.colMenu);
50785 this.colMenu.getEl().remove();
50786 delete this.colMenu;
50789 this.hmenu.removeAll();
50790 Roo.menu.MenuMgr.unregister(this.hmenu);
50791 this.hmenu.getEl().remove();
50794 if(this.grid.enableColumnMove){
50795 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
50797 for(var dd in dds){
50798 if(!dds[dd].config.isTarget && dds[dd].dragElId){
50799 var elid = dds[dd].dragElId;
50801 Roo.get(elid).remove();
50802 } else if(dds[dd].config.isTarget){
50803 dds[dd].proxyTop.remove();
50804 dds[dd].proxyBottom.remove();
50807 if(Roo.dd.DDM.locationCache[dd]){
50808 delete Roo.dd.DDM.locationCache[dd];
50811 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
50814 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
50815 this.bind(null, null);
50816 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
50819 handleLockChange : function(){
50820 this.refresh(true);
50823 onDenyColumnLock : function(){
50827 onDenyColumnHide : function(){
50831 handleHdMenuClick : function(item){
50832 var index = this.hdCtxIndex;
50833 var cm = this.cm, ds = this.ds;
50836 ds.sort(cm.getDataIndex(index), "ASC");
50839 ds.sort(cm.getDataIndex(index), "DESC");
50842 var lc = cm.getLockedCount();
50843 if(cm.getColumnCount(true) <= lc+1){
50844 this.onDenyColumnLock();
50848 cm.setLocked(index, true, true);
50849 cm.moveColumn(index, lc);
50850 this.grid.fireEvent("columnmove", index, lc);
50852 cm.setLocked(index, true);
50856 var lc = cm.getLockedCount();
50857 if((lc-1) != index){
50858 cm.setLocked(index, false, true);
50859 cm.moveColumn(index, lc-1);
50860 this.grid.fireEvent("columnmove", index, lc-1);
50862 cm.setLocked(index, false);
50866 index = cm.getIndexById(item.id.substr(4));
50868 if(item.checked && cm.getColumnCount(true) <= 1){
50869 this.onDenyColumnHide();
50872 cm.setHidden(index, item.checked);
50878 beforeColMenuShow : function(){
50879 var cm = this.cm, colCount = cm.getColumnCount();
50880 this.colMenu.removeAll();
50881 for(var i = 0; i < colCount; i++){
50882 this.colMenu.add(new Roo.menu.CheckItem({
50883 id: "col-"+cm.getColumnId(i),
50884 text: cm.getColumnHeader(i),
50885 checked: !cm.isHidden(i),
50891 handleHdCtx : function(g, index, e){
50893 var hd = this.getHeaderCell(index);
50894 this.hdCtxIndex = index;
50895 var ms = this.hmenu.items, cm = this.cm;
50896 ms.get("asc").setDisabled(!cm.isSortable(index));
50897 ms.get("desc").setDisabled(!cm.isSortable(index));
50898 if(this.grid.enableColLock !== false){
50899 ms.get("lock").setDisabled(cm.isLocked(index));
50900 ms.get("unlock").setDisabled(!cm.isLocked(index));
50902 this.hmenu.show(hd, "tl-bl");
50905 handleHdOver : function(e){
50906 var hd = this.findHeaderCell(e.getTarget());
50907 if(hd && !this.headersDisabled){
50908 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
50909 this.fly(hd).addClass("x-grid-hd-over");
50914 handleHdOut : function(e){
50915 var hd = this.findHeaderCell(e.getTarget());
50917 this.fly(hd).removeClass("x-grid-hd-over");
50921 handleSplitDblClick : function(e, t){
50922 var i = this.getCellIndex(t);
50923 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
50924 this.autoSizeColumn(i, true);
50929 render : function(){
50932 var colCount = cm.getColumnCount();
50934 if(this.grid.monitorWindowResize === true){
50935 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50937 var header = this.renderHeaders();
50938 var body = this.templates.body.apply({rows:""});
50939 var html = this.templates.master.apply({
50942 lockedHeader: header[0],
50946 //this.updateColumns();
50948 this.grid.getGridEl().dom.innerHTML = html;
50950 this.initElements();
50952 // a kludge to fix the random scolling effect in webkit
50953 this.el.on("scroll", function() {
50954 this.el.dom.scrollTop=0; // hopefully not recursive..
50957 this.scroller.on("scroll", this.handleScroll, this);
50958 this.lockedBody.on("mousewheel", this.handleWheel, this);
50959 this.mainBody.on("mousewheel", this.handleWheel, this);
50961 this.mainHd.on("mouseover", this.handleHdOver, this);
50962 this.mainHd.on("mouseout", this.handleHdOut, this);
50963 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
50964 {delegate: "."+this.splitClass});
50966 this.lockedHd.on("mouseover", this.handleHdOver, this);
50967 this.lockedHd.on("mouseout", this.handleHdOut, this);
50968 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
50969 {delegate: "."+this.splitClass});
50971 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
50972 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50975 this.updateSplitters();
50977 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
50978 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50979 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
50982 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
50983 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
50985 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
50986 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
50988 if(this.grid.enableColLock !== false){
50989 this.hmenu.add('-',
50990 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
50991 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
50994 if(this.grid.enableColumnHide !== false){
50996 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
50997 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
50998 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
51000 this.hmenu.add('-',
51001 {id:"columns", text: this.columnsText, menu: this.colMenu}
51004 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
51006 this.grid.on("headercontextmenu", this.handleHdCtx, this);
51009 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
51010 this.dd = new Roo.grid.GridDragZone(this.grid, {
51011 ddGroup : this.grid.ddGroup || 'GridDD'
51016 for(var i = 0; i < colCount; i++){
51017 if(cm.isHidden(i)){
51018 this.hideColumn(i);
51020 if(cm.config[i].align){
51021 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
51022 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
51026 this.updateHeaderSortState();
51028 this.beforeInitialResize();
51031 // two part rendering gives faster view to the user
51032 this.renderPhase2.defer(1, this);
51035 renderPhase2 : function(){
51036 // render the rows now
51038 if(this.grid.autoSizeColumns){
51039 this.autoSizeColumns();
51043 beforeInitialResize : function(){
51047 onColumnSplitterMoved : function(i, w){
51048 this.userResized = true;
51049 var cm = this.grid.colModel;
51050 cm.setColumnWidth(i, w, true);
51051 var cid = cm.getColumnId(i);
51052 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51053 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51054 this.updateSplitters();
51056 this.grid.fireEvent("columnresize", i, w);
51059 syncRowHeights : function(startIndex, endIndex){
51060 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
51061 startIndex = startIndex || 0;
51062 var mrows = this.getBodyTable().rows;
51063 var lrows = this.getLockedTable().rows;
51064 var len = mrows.length-1;
51065 endIndex = Math.min(endIndex || len, len);
51066 for(var i = startIndex; i <= endIndex; i++){
51067 var m = mrows[i], l = lrows[i];
51068 var h = Math.max(m.offsetHeight, l.offsetHeight);
51069 m.style.height = l.style.height = h + "px";
51074 layout : function(initialRender, is2ndPass){
51076 var auto = g.autoHeight;
51077 var scrollOffset = 16;
51078 var c = g.getGridEl(), cm = this.cm,
51079 expandCol = g.autoExpandColumn,
51081 //c.beginMeasure();
51083 if(!c.dom.offsetWidth){ // display:none?
51085 this.lockedWrap.show();
51086 this.mainWrap.show();
51091 var hasLock = this.cm.isLocked(0);
51093 var tbh = this.headerPanel.getHeight();
51094 var bbh = this.footerPanel.getHeight();
51097 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
51098 var newHeight = ch + c.getBorderWidth("tb");
51100 newHeight = Math.min(g.maxHeight, newHeight);
51102 c.setHeight(newHeight);
51106 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
51109 var s = this.scroller;
51111 var csize = c.getSize(true);
51113 this.el.setSize(csize.width, csize.height);
51115 this.headerPanel.setWidth(csize.width);
51116 this.footerPanel.setWidth(csize.width);
51118 var hdHeight = this.mainHd.getHeight();
51119 var vw = csize.width;
51120 var vh = csize.height - (tbh + bbh);
51124 var bt = this.getBodyTable();
51125 var ltWidth = hasLock ?
51126 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
51128 var scrollHeight = bt.offsetHeight;
51129 var scrollWidth = ltWidth + bt.offsetWidth;
51130 var vscroll = false, hscroll = false;
51132 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
51134 var lw = this.lockedWrap, mw = this.mainWrap;
51135 var lb = this.lockedBody, mb = this.mainBody;
51137 setTimeout(function(){
51138 var t = s.dom.offsetTop;
51139 var w = s.dom.clientWidth,
51140 h = s.dom.clientHeight;
51143 lw.setSize(ltWidth, h);
51145 mw.setLeftTop(ltWidth, t);
51146 mw.setSize(w-ltWidth, h);
51148 lb.setHeight(h-hdHeight);
51149 mb.setHeight(h-hdHeight);
51151 if(is2ndPass !== true && !gv.userResized && expandCol){
51152 // high speed resize without full column calculation
51154 var ci = cm.getIndexById(expandCol);
51156 ci = cm.findColumnIndex(expandCol);
51158 ci = Math.max(0, ci); // make sure it's got at least the first col.
51159 var expandId = cm.getColumnId(ci);
51160 var tw = cm.getTotalWidth(false);
51161 var currentWidth = cm.getColumnWidth(ci);
51162 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
51163 if(currentWidth != cw){
51164 cm.setColumnWidth(ci, cw, true);
51165 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51166 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51167 gv.updateSplitters();
51168 gv.layout(false, true);
51180 onWindowResize : function(){
51181 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
51187 appendFooter : function(parentEl){
51191 sortAscText : "Sort Ascending",
51192 sortDescText : "Sort Descending",
51193 lockText : "Lock Column",
51194 unlockText : "Unlock Column",
51195 columnsText : "Columns"
51199 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
51200 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
51201 this.proxy.el.addClass('x-grid3-col-dd');
51204 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
51205 handleMouseDown : function(e){
51209 callHandleMouseDown : function(e){
51210 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
51215 * Ext JS Library 1.1.1
51216 * Copyright(c) 2006-2007, Ext JS, LLC.
51218 * Originally Released Under LGPL - original licence link has changed is not relivant.
51221 * <script type="text/javascript">
51225 // This is a support class used internally by the Grid components
51226 Roo.grid.SplitDragZone = function(grid, hd, hd2){
51228 this.view = grid.getView();
51229 this.proxy = this.view.resizeProxy;
51230 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
51231 "gridSplitters" + this.grid.getGridEl().id, {
51232 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
51234 this.setHandleElId(Roo.id(hd));
51235 this.setOuterHandleElId(Roo.id(hd2));
51236 this.scroll = false;
51238 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
51239 fly: Roo.Element.fly,
51241 b4StartDrag : function(x, y){
51242 this.view.headersDisabled = true;
51243 this.proxy.setHeight(this.view.mainWrap.getHeight());
51244 var w = this.cm.getColumnWidth(this.cellIndex);
51245 var minw = Math.max(w-this.grid.minColumnWidth, 0);
51246 this.resetConstraints();
51247 this.setXConstraint(minw, 1000);
51248 this.setYConstraint(0, 0);
51249 this.minX = x - minw;
51250 this.maxX = x + 1000;
51252 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
51256 handleMouseDown : function(e){
51257 ev = Roo.EventObject.setEvent(e);
51258 var t = this.fly(ev.getTarget());
51259 if(t.hasClass("x-grid-split")){
51260 this.cellIndex = this.view.getCellIndex(t.dom);
51261 this.split = t.dom;
51262 this.cm = this.grid.colModel;
51263 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
51264 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
51269 endDrag : function(e){
51270 this.view.headersDisabled = false;
51271 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
51272 var diff = endX - this.startPos;
51273 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
51276 autoOffset : function(){
51277 this.setDelta(0,0);
51281 * Ext JS Library 1.1.1
51282 * Copyright(c) 2006-2007, Ext JS, LLC.
51284 * Originally Released Under LGPL - original licence link has changed is not relivant.
51287 * <script type="text/javascript">
51291 // This is a support class used internally by the Grid components
51292 Roo.grid.GridDragZone = function(grid, config){
51293 this.view = grid.getView();
51294 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
51295 if(this.view.lockedBody){
51296 this.setHandleElId(Roo.id(this.view.mainBody.dom));
51297 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
51299 this.scroll = false;
51301 this.ddel = document.createElement('div');
51302 this.ddel.className = 'x-grid-dd-wrap';
51305 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
51306 ddGroup : "GridDD",
51308 getDragData : function(e){
51309 var t = Roo.lib.Event.getTarget(e);
51310 var rowIndex = this.view.findRowIndex(t);
51311 if(rowIndex !== false){
51312 var sm = this.grid.selModel;
51313 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
51314 // sm.mouseDown(e, t);
51316 if (e.hasModifier()){
51317 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
51319 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
51324 onInitDrag : function(e){
51325 var data = this.dragData;
51326 this.ddel.innerHTML = this.grid.getDragDropText();
51327 this.proxy.update(this.ddel);
51328 // fire start drag?
51331 afterRepair : function(){
51332 this.dragging = false;
51335 getRepairXY : function(e, data){
51339 onEndDrag : function(data, e){
51343 onValidDrop : function(dd, e, id){
51348 beforeInvalidDrop : function(e, id){
51353 * Ext JS Library 1.1.1
51354 * Copyright(c) 2006-2007, Ext JS, LLC.
51356 * Originally Released Under LGPL - original licence link has changed is not relivant.
51359 * <script type="text/javascript">
51364 * @class Roo.grid.ColumnModel
51365 * @extends Roo.util.Observable
51366 * This is the default implementation of a ColumnModel used by the Grid. It defines
51367 * the columns in the grid.
51370 var colModel = new Roo.grid.ColumnModel([
51371 {header: "Ticker", width: 60, sortable: true, locked: true},
51372 {header: "Company Name", width: 150, sortable: true},
51373 {header: "Market Cap.", width: 100, sortable: true},
51374 {header: "$ Sales", width: 100, sortable: true, renderer: money},
51375 {header: "Employees", width: 100, sortable: true, resizable: false}
51380 * The config options listed for this class are options which may appear in each
51381 * individual column definition.
51382 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
51384 * @param {Object} config An Array of column config objects. See this class's
51385 * config objects for details.
51387 Roo.grid.ColumnModel = function(config){
51389 * The config passed into the constructor
51391 this.config = config;
51394 // if no id, create one
51395 // if the column does not have a dataIndex mapping,
51396 // map it to the order it is in the config
51397 for(var i = 0, len = config.length; i < len; i++){
51399 if(typeof c.dataIndex == "undefined"){
51402 if(typeof c.renderer == "string"){
51403 c.renderer = Roo.util.Format[c.renderer];
51405 if(typeof c.id == "undefined"){
51408 if(c.editor && c.editor.xtype){
51409 c.editor = Roo.factory(c.editor, Roo.grid);
51411 if(c.editor && c.editor.isFormField){
51412 c.editor = new Roo.grid.GridEditor(c.editor);
51414 this.lookup[c.id] = c;
51418 * The width of columns which have no width specified (defaults to 100)
51421 this.defaultWidth = 100;
51424 * Default sortable of columns which have no sortable specified (defaults to false)
51427 this.defaultSortable = false;
51431 * @event widthchange
51432 * Fires when the width of a column changes.
51433 * @param {ColumnModel} this
51434 * @param {Number} columnIndex The column index
51435 * @param {Number} newWidth The new width
51437 "widthchange": true,
51439 * @event headerchange
51440 * Fires when the text of a header changes.
51441 * @param {ColumnModel} this
51442 * @param {Number} columnIndex The column index
51443 * @param {Number} newText The new header text
51445 "headerchange": true,
51447 * @event hiddenchange
51448 * Fires when a column is hidden or "unhidden".
51449 * @param {ColumnModel} this
51450 * @param {Number} columnIndex The column index
51451 * @param {Boolean} hidden true if hidden, false otherwise
51453 "hiddenchange": true,
51455 * @event columnmoved
51456 * Fires when a column is moved.
51457 * @param {ColumnModel} this
51458 * @param {Number} oldIndex
51459 * @param {Number} newIndex
51461 "columnmoved" : true,
51463 * @event columlockchange
51464 * Fires when a column's locked state is changed
51465 * @param {ColumnModel} this
51466 * @param {Number} colIndex
51467 * @param {Boolean} locked true if locked
51469 "columnlockchange" : true
51471 Roo.grid.ColumnModel.superclass.constructor.call(this);
51473 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
51475 * @cfg {String} header The header text to display in the Grid view.
51478 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
51479 * {@link Roo.data.Record} definition from which to draw the column's value. If not
51480 * specified, the column's index is used as an index into the Record's data Array.
51483 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
51484 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
51487 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
51488 * Defaults to the value of the {@link #defaultSortable} property.
51489 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
51492 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
51495 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
51498 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
51501 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
51504 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
51505 * given the cell's data value. See {@link #setRenderer}. If not specified, the
51506 * default renderer uses the raw data value.
51509 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
51512 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
51516 * Returns the id of the column at the specified index.
51517 * @param {Number} index The column index
51518 * @return {String} the id
51520 getColumnId : function(index){
51521 return this.config[index].id;
51525 * Returns the column for a specified id.
51526 * @param {String} id The column id
51527 * @return {Object} the column
51529 getColumnById : function(id){
51530 return this.lookup[id];
51535 * Returns the column for a specified dataIndex.
51536 * @param {String} dataIndex The column dataIndex
51537 * @return {Object|Boolean} the column or false if not found
51539 getColumnByDataIndex: function(dataIndex){
51540 var index = this.findColumnIndex(dataIndex);
51541 return index > -1 ? this.config[index] : false;
51545 * Returns the index for a specified column id.
51546 * @param {String} id The column id
51547 * @return {Number} the index, or -1 if not found
51549 getIndexById : function(id){
51550 for(var i = 0, len = this.config.length; i < len; i++){
51551 if(this.config[i].id == id){
51559 * Returns the index for a specified column dataIndex.
51560 * @param {String} dataIndex The column dataIndex
51561 * @return {Number} the index, or -1 if not found
51564 findColumnIndex : function(dataIndex){
51565 for(var i = 0, len = this.config.length; i < len; i++){
51566 if(this.config[i].dataIndex == dataIndex){
51574 moveColumn : function(oldIndex, newIndex){
51575 var c = this.config[oldIndex];
51576 this.config.splice(oldIndex, 1);
51577 this.config.splice(newIndex, 0, c);
51578 this.dataMap = null;
51579 this.fireEvent("columnmoved", this, oldIndex, newIndex);
51582 isLocked : function(colIndex){
51583 return this.config[colIndex].locked === true;
51586 setLocked : function(colIndex, value, suppressEvent){
51587 if(this.isLocked(colIndex) == value){
51590 this.config[colIndex].locked = value;
51591 if(!suppressEvent){
51592 this.fireEvent("columnlockchange", this, colIndex, value);
51596 getTotalLockedWidth : function(){
51597 var totalWidth = 0;
51598 for(var i = 0; i < this.config.length; i++){
51599 if(this.isLocked(i) && !this.isHidden(i)){
51600 this.totalWidth += this.getColumnWidth(i);
51606 getLockedCount : function(){
51607 for(var i = 0, len = this.config.length; i < len; i++){
51608 if(!this.isLocked(i)){
51615 * Returns the number of columns.
51618 getColumnCount : function(visibleOnly){
51619 if(visibleOnly === true){
51621 for(var i = 0, len = this.config.length; i < len; i++){
51622 if(!this.isHidden(i)){
51628 return this.config.length;
51632 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
51633 * @param {Function} fn
51634 * @param {Object} scope (optional)
51635 * @return {Array} result
51637 getColumnsBy : function(fn, scope){
51639 for(var i = 0, len = this.config.length; i < len; i++){
51640 var c = this.config[i];
51641 if(fn.call(scope||this, c, i) === true){
51649 * Returns true if the specified column is sortable.
51650 * @param {Number} col The column index
51651 * @return {Boolean}
51653 isSortable : function(col){
51654 if(typeof this.config[col].sortable == "undefined"){
51655 return this.defaultSortable;
51657 return this.config[col].sortable;
51661 * Returns the rendering (formatting) function defined for the column.
51662 * @param {Number} col The column index.
51663 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
51665 getRenderer : function(col){
51666 if(!this.config[col].renderer){
51667 return Roo.grid.ColumnModel.defaultRenderer;
51669 return this.config[col].renderer;
51673 * Sets the rendering (formatting) function for a column.
51674 * @param {Number} col The column index
51675 * @param {Function} fn The function to use to process the cell's raw data
51676 * to return HTML markup for the grid view. The render function is called with
51677 * the following parameters:<ul>
51678 * <li>Data value.</li>
51679 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
51680 * <li>css A CSS style string to apply to the table cell.</li>
51681 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
51682 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
51683 * <li>Row index</li>
51684 * <li>Column index</li>
51685 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
51687 setRenderer : function(col, fn){
51688 this.config[col].renderer = fn;
51692 * Returns the width for the specified column.
51693 * @param {Number} col The column index
51696 getColumnWidth : function(col){
51697 return this.config[col].width * 1 || this.defaultWidth;
51701 * Sets the width for a column.
51702 * @param {Number} col The column index
51703 * @param {Number} width The new width
51705 setColumnWidth : function(col, width, suppressEvent){
51706 this.config[col].width = width;
51707 this.totalWidth = null;
51708 if(!suppressEvent){
51709 this.fireEvent("widthchange", this, col, width);
51714 * Returns the total width of all columns.
51715 * @param {Boolean} includeHidden True to include hidden column widths
51718 getTotalWidth : function(includeHidden){
51719 if(!this.totalWidth){
51720 this.totalWidth = 0;
51721 for(var i = 0, len = this.config.length; i < len; i++){
51722 if(includeHidden || !this.isHidden(i)){
51723 this.totalWidth += this.getColumnWidth(i);
51727 return this.totalWidth;
51731 * Returns the header for the specified column.
51732 * @param {Number} col The column index
51735 getColumnHeader : function(col){
51736 return this.config[col].header;
51740 * Sets the header for a column.
51741 * @param {Number} col The column index
51742 * @param {String} header The new header
51744 setColumnHeader : function(col, header){
51745 this.config[col].header = header;
51746 this.fireEvent("headerchange", this, col, header);
51750 * Returns the tooltip for the specified column.
51751 * @param {Number} col The column index
51754 getColumnTooltip : function(col){
51755 return this.config[col].tooltip;
51758 * Sets the tooltip for a column.
51759 * @param {Number} col The column index
51760 * @param {String} tooltip The new tooltip
51762 setColumnTooltip : function(col, tooltip){
51763 this.config[col].tooltip = tooltip;
51767 * Returns the dataIndex for the specified column.
51768 * @param {Number} col The column index
51771 getDataIndex : function(col){
51772 return this.config[col].dataIndex;
51776 * Sets the dataIndex for a column.
51777 * @param {Number} col The column index
51778 * @param {Number} dataIndex The new dataIndex
51780 setDataIndex : function(col, dataIndex){
51781 this.config[col].dataIndex = dataIndex;
51787 * Returns true if the cell is editable.
51788 * @param {Number} colIndex The column index
51789 * @param {Number} rowIndex The row index
51790 * @return {Boolean}
51792 isCellEditable : function(colIndex, rowIndex){
51793 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
51797 * Returns the editor defined for the cell/column.
51798 * return false or null to disable editing.
51799 * @param {Number} colIndex The column index
51800 * @param {Number} rowIndex The row index
51803 getCellEditor : function(colIndex, rowIndex){
51804 return this.config[colIndex].editor;
51808 * Sets if a column is editable.
51809 * @param {Number} col The column index
51810 * @param {Boolean} editable True if the column is editable
51812 setEditable : function(col, editable){
51813 this.config[col].editable = editable;
51818 * Returns true if the column is hidden.
51819 * @param {Number} colIndex The column index
51820 * @return {Boolean}
51822 isHidden : function(colIndex){
51823 return this.config[colIndex].hidden;
51828 * Returns true if the column width cannot be changed
51830 isFixed : function(colIndex){
51831 return this.config[colIndex].fixed;
51835 * Returns true if the column can be resized
51836 * @return {Boolean}
51838 isResizable : function(colIndex){
51839 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
51842 * Sets if a column is hidden.
51843 * @param {Number} colIndex The column index
51844 * @param {Boolean} hidden True if the column is hidden
51846 setHidden : function(colIndex, hidden){
51847 this.config[colIndex].hidden = hidden;
51848 this.totalWidth = null;
51849 this.fireEvent("hiddenchange", this, colIndex, hidden);
51853 * Sets the editor for a column.
51854 * @param {Number} col The column index
51855 * @param {Object} editor The editor object
51857 setEditor : function(col, editor){
51858 this.config[col].editor = editor;
51862 Roo.grid.ColumnModel.defaultRenderer = function(value){
51863 if(typeof value == "string" && value.length < 1){
51869 // Alias for backwards compatibility
51870 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
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">
51883 * @class Roo.grid.AbstractSelectionModel
51884 * @extends Roo.util.Observable
51885 * Abstract base class for grid SelectionModels. It provides the interface that should be
51886 * implemented by descendant classes. This class should not be directly instantiated.
51889 Roo.grid.AbstractSelectionModel = function(){
51890 this.locked = false;
51891 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
51894 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
51895 /** @ignore Called by the grid automatically. Do not call directly. */
51896 init : function(grid){
51902 * Locks the selections.
51905 this.locked = true;
51909 * Unlocks the selections.
51911 unlock : function(){
51912 this.locked = false;
51916 * Returns true if the selections are locked.
51917 * @return {Boolean}
51919 isLocked : function(){
51920 return this.locked;
51924 * Ext JS Library 1.1.1
51925 * Copyright(c) 2006-2007, Ext JS, LLC.
51927 * Originally Released Under LGPL - original licence link has changed is not relivant.
51930 * <script type="text/javascript">
51933 * @extends Roo.grid.AbstractSelectionModel
51934 * @class Roo.grid.RowSelectionModel
51935 * The default SelectionModel used by {@link Roo.grid.Grid}.
51936 * It supports multiple selections and keyboard selection/navigation.
51938 * @param {Object} config
51940 Roo.grid.RowSelectionModel = function(config){
51941 Roo.apply(this, config);
51942 this.selections = new Roo.util.MixedCollection(false, function(o){
51947 this.lastActive = false;
51951 * @event selectionchange
51952 * Fires when the selection changes
51953 * @param {SelectionModel} this
51955 "selectionchange" : true,
51957 * @event afterselectionchange
51958 * Fires after the selection changes (eg. by key press or clicking)
51959 * @param {SelectionModel} this
51961 "afterselectionchange" : true,
51963 * @event beforerowselect
51964 * Fires when a row is selected being selected, return false to cancel.
51965 * @param {SelectionModel} this
51966 * @param {Number} rowIndex The selected index
51967 * @param {Boolean} keepExisting False if other selections will be cleared
51969 "beforerowselect" : true,
51972 * Fires when a row is selected.
51973 * @param {SelectionModel} this
51974 * @param {Number} rowIndex The selected index
51975 * @param {Roo.data.Record} r The record
51977 "rowselect" : true,
51979 * @event rowdeselect
51980 * Fires when a row is deselected.
51981 * @param {SelectionModel} this
51982 * @param {Number} rowIndex The selected index
51984 "rowdeselect" : true
51986 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
51987 this.locked = false;
51990 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
51992 * @cfg {Boolean} singleSelect
51993 * True to allow selection of only one row at a time (defaults to false)
51995 singleSelect : false,
51998 initEvents : function(){
52000 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
52001 this.grid.on("mousedown", this.handleMouseDown, this);
52002 }else{ // allow click to work like normal
52003 this.grid.on("rowclick", this.handleDragableRowClick, this);
52006 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
52007 "up" : function(e){
52009 this.selectPrevious(e.shiftKey);
52010 }else if(this.last !== false && this.lastActive !== false){
52011 var last = this.last;
52012 this.selectRange(this.last, this.lastActive-1);
52013 this.grid.getView().focusRow(this.lastActive);
52014 if(last !== false){
52018 this.selectFirstRow();
52020 this.fireEvent("afterselectionchange", this);
52022 "down" : function(e){
52024 this.selectNext(e.shiftKey);
52025 }else if(this.last !== false && this.lastActive !== false){
52026 var last = this.last;
52027 this.selectRange(this.last, this.lastActive+1);
52028 this.grid.getView().focusRow(this.lastActive);
52029 if(last !== false){
52033 this.selectFirstRow();
52035 this.fireEvent("afterselectionchange", this);
52040 var view = this.grid.view;
52041 view.on("refresh", this.onRefresh, this);
52042 view.on("rowupdated", this.onRowUpdated, this);
52043 view.on("rowremoved", this.onRemove, this);
52047 onRefresh : function(){
52048 var ds = this.grid.dataSource, i, v = this.grid.view;
52049 var s = this.selections;
52050 s.each(function(r){
52051 if((i = ds.indexOfId(r.id)) != -1){
52060 onRemove : function(v, index, r){
52061 this.selections.remove(r);
52065 onRowUpdated : function(v, index, r){
52066 if(this.isSelected(r)){
52067 v.onRowSelect(index);
52073 * @param {Array} records The records to select
52074 * @param {Boolean} keepExisting (optional) True to keep existing selections
52076 selectRecords : function(records, keepExisting){
52078 this.clearSelections();
52080 var ds = this.grid.dataSource;
52081 for(var i = 0, len = records.length; i < len; i++){
52082 this.selectRow(ds.indexOf(records[i]), true);
52087 * Gets the number of selected rows.
52090 getCount : function(){
52091 return this.selections.length;
52095 * Selects the first row in the grid.
52097 selectFirstRow : function(){
52102 * Select the last row.
52103 * @param {Boolean} keepExisting (optional) True to keep existing selections
52105 selectLastRow : function(keepExisting){
52106 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
52110 * Selects the row immediately following the last selected row.
52111 * @param {Boolean} keepExisting (optional) True to keep existing selections
52113 selectNext : function(keepExisting){
52114 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
52115 this.selectRow(this.last+1, keepExisting);
52116 this.grid.getView().focusRow(this.last);
52121 * Selects the row that precedes the last selected row.
52122 * @param {Boolean} keepExisting (optional) True to keep existing selections
52124 selectPrevious : function(keepExisting){
52126 this.selectRow(this.last-1, keepExisting);
52127 this.grid.getView().focusRow(this.last);
52132 * Returns the selected records
52133 * @return {Array} Array of selected records
52135 getSelections : function(){
52136 return [].concat(this.selections.items);
52140 * Returns the first selected record.
52143 getSelected : function(){
52144 return this.selections.itemAt(0);
52149 * Clears all selections.
52151 clearSelections : function(fast){
52152 if(this.locked) return;
52154 var ds = this.grid.dataSource;
52155 var s = this.selections;
52156 s.each(function(r){
52157 this.deselectRow(ds.indexOfId(r.id));
52161 this.selections.clear();
52168 * Selects all rows.
52170 selectAll : function(){
52171 if(this.locked) return;
52172 this.selections.clear();
52173 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
52174 this.selectRow(i, true);
52179 * Returns True if there is a selection.
52180 * @return {Boolean}
52182 hasSelection : function(){
52183 return this.selections.length > 0;
52187 * Returns True if the specified row is selected.
52188 * @param {Number/Record} record The record or index of the record to check
52189 * @return {Boolean}
52191 isSelected : function(index){
52192 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
52193 return (r && this.selections.key(r.id) ? true : false);
52197 * Returns True if the specified record id is selected.
52198 * @param {String} id The id of record to check
52199 * @return {Boolean}
52201 isIdSelected : function(id){
52202 return (this.selections.key(id) ? true : false);
52206 handleMouseDown : function(e, t){
52207 var view = this.grid.getView(), rowIndex;
52208 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
52211 if(e.shiftKey && this.last !== false){
52212 var last = this.last;
52213 this.selectRange(last, rowIndex, e.ctrlKey);
52214 this.last = last; // reset the last
52215 view.focusRow(rowIndex);
52217 var isSelected = this.isSelected(rowIndex);
52218 if(e.button !== 0 && isSelected){
52219 view.focusRow(rowIndex);
52220 }else if(e.ctrlKey && isSelected){
52221 this.deselectRow(rowIndex);
52222 }else if(!isSelected){
52223 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
52224 view.focusRow(rowIndex);
52227 this.fireEvent("afterselectionchange", this);
52230 handleDragableRowClick : function(grid, rowIndex, e)
52232 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
52233 this.selectRow(rowIndex, false);
52234 grid.view.focusRow(rowIndex);
52235 this.fireEvent("afterselectionchange", this);
52240 * Selects multiple rows.
52241 * @param {Array} rows Array of the indexes of the row to select
52242 * @param {Boolean} keepExisting (optional) True to keep existing selections
52244 selectRows : function(rows, keepExisting){
52246 this.clearSelections();
52248 for(var i = 0, len = rows.length; i < len; i++){
52249 this.selectRow(rows[i], true);
52254 * Selects a range of rows. All rows in between startRow and endRow are also selected.
52255 * @param {Number} startRow The index of the first row in the range
52256 * @param {Number} endRow The index of the last row in the range
52257 * @param {Boolean} keepExisting (optional) True to retain existing selections
52259 selectRange : function(startRow, endRow, keepExisting){
52260 if(this.locked) return;
52262 this.clearSelections();
52264 if(startRow <= endRow){
52265 for(var i = startRow; i <= endRow; i++){
52266 this.selectRow(i, true);
52269 for(var i = startRow; i >= endRow; i--){
52270 this.selectRow(i, true);
52276 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
52277 * @param {Number} startRow The index of the first row in the range
52278 * @param {Number} endRow The index of the last row in the range
52280 deselectRange : function(startRow, endRow, preventViewNotify){
52281 if(this.locked) return;
52282 for(var i = startRow; i <= endRow; i++){
52283 this.deselectRow(i, preventViewNotify);
52289 * @param {Number} row The index of the row to select
52290 * @param {Boolean} keepExisting (optional) True to keep existing selections
52292 selectRow : function(index, keepExisting, preventViewNotify){
52293 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
52294 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
52295 if(!keepExisting || this.singleSelect){
52296 this.clearSelections();
52298 var r = this.grid.dataSource.getAt(index);
52299 this.selections.add(r);
52300 this.last = this.lastActive = index;
52301 if(!preventViewNotify){
52302 this.grid.getView().onRowSelect(index);
52304 this.fireEvent("rowselect", this, index, r);
52305 this.fireEvent("selectionchange", this);
52311 * @param {Number} row The index of the row to deselect
52313 deselectRow : function(index, preventViewNotify){
52314 if(this.locked) return;
52315 if(this.last == index){
52318 if(this.lastActive == index){
52319 this.lastActive = false;
52321 var r = this.grid.dataSource.getAt(index);
52322 this.selections.remove(r);
52323 if(!preventViewNotify){
52324 this.grid.getView().onRowDeselect(index);
52326 this.fireEvent("rowdeselect", this, index);
52327 this.fireEvent("selectionchange", this);
52331 restoreLast : function(){
52333 this.last = this._last;
52338 acceptsNav : function(row, col, cm){
52339 return !cm.isHidden(col) && cm.isCellEditable(col, row);
52343 onEditorKey : function(field, e){
52344 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
52349 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
52351 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
52353 }else if(k == e.ENTER && !e.ctrlKey){
52357 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
52359 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
52361 }else if(k == e.ESC){
52365 g.startEditing(newCell[0], newCell[1]);
52370 * Ext JS Library 1.1.1
52371 * Copyright(c) 2006-2007, Ext JS, LLC.
52373 * Originally Released Under LGPL - original licence link has changed is not relivant.
52376 * <script type="text/javascript">
52379 * @class Roo.grid.CellSelectionModel
52380 * @extends Roo.grid.AbstractSelectionModel
52381 * This class provides the basic implementation for cell selection in a grid.
52383 * @param {Object} config The object containing the configuration of this model.
52384 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
52386 Roo.grid.CellSelectionModel = function(config){
52387 Roo.apply(this, config);
52389 this.selection = null;
52393 * @event beforerowselect
52394 * Fires before a cell is selected.
52395 * @param {SelectionModel} this
52396 * @param {Number} rowIndex The selected row index
52397 * @param {Number} colIndex The selected cell index
52399 "beforecellselect" : true,
52401 * @event cellselect
52402 * Fires when a cell is selected.
52403 * @param {SelectionModel} this
52404 * @param {Number} rowIndex The selected row index
52405 * @param {Number} colIndex The selected cell index
52407 "cellselect" : true,
52409 * @event selectionchange
52410 * Fires when the active selection changes.
52411 * @param {SelectionModel} this
52412 * @param {Object} selection null for no selection or an object (o) with two properties
52414 <li>o.record: the record object for the row the selection is in</li>
52415 <li>o.cell: An array of [rowIndex, columnIndex]</li>
52418 "selectionchange" : true,
52421 * Fires when the tab (or enter) was pressed on the last editable cell
52422 * You can use this to trigger add new row.
52423 * @param {SelectionModel} this
52427 * @event beforeeditnext
52428 * Fires before the next editable sell is made active
52429 * You can use this to skip to another cell or fire the tabend
52430 * if you set cell to false
52431 * @param {Object} eventdata object : { cell : [ row, col ] }
52433 "beforeeditnext" : true
52435 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
52438 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
52440 enter_is_tab: false,
52443 initEvents : function(){
52444 this.grid.on("mousedown", this.handleMouseDown, this);
52445 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
52446 var view = this.grid.view;
52447 view.on("refresh", this.onViewChange, this);
52448 view.on("rowupdated", this.onRowUpdated, this);
52449 view.on("beforerowremoved", this.clearSelections, this);
52450 view.on("beforerowsinserted", this.clearSelections, this);
52451 if(this.grid.isEditor){
52452 this.grid.on("beforeedit", this.beforeEdit, this);
52457 beforeEdit : function(e){
52458 this.select(e.row, e.column, false, true, e.record);
52462 onRowUpdated : function(v, index, r){
52463 if(this.selection && this.selection.record == r){
52464 v.onCellSelect(index, this.selection.cell[1]);
52469 onViewChange : function(){
52470 this.clearSelections(true);
52474 * Returns the currently selected cell,.
52475 * @return {Array} The selected cell (row, column) or null if none selected.
52477 getSelectedCell : function(){
52478 return this.selection ? this.selection.cell : null;
52482 * Clears all selections.
52483 * @param {Boolean} true to prevent the gridview from being notified about the change.
52485 clearSelections : function(preventNotify){
52486 var s = this.selection;
52488 if(preventNotify !== true){
52489 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
52491 this.selection = null;
52492 this.fireEvent("selectionchange", this, null);
52497 * Returns true if there is a selection.
52498 * @return {Boolean}
52500 hasSelection : function(){
52501 return this.selection ? true : false;
52505 handleMouseDown : function(e, t){
52506 var v = this.grid.getView();
52507 if(this.isLocked()){
52510 var row = v.findRowIndex(t);
52511 var cell = v.findCellIndex(t);
52512 if(row !== false && cell !== false){
52513 this.select(row, cell);
52519 * @param {Number} rowIndex
52520 * @param {Number} collIndex
52522 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
52523 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
52524 this.clearSelections();
52525 r = r || this.grid.dataSource.getAt(rowIndex);
52528 cell : [rowIndex, colIndex]
52530 if(!preventViewNotify){
52531 var v = this.grid.getView();
52532 v.onCellSelect(rowIndex, colIndex);
52533 if(preventFocus !== true){
52534 v.focusCell(rowIndex, colIndex);
52537 this.fireEvent("cellselect", this, rowIndex, colIndex);
52538 this.fireEvent("selectionchange", this, this.selection);
52543 isSelectable : function(rowIndex, colIndex, cm){
52544 return !cm.isHidden(colIndex);
52548 handleKeyDown : function(e){
52549 //Roo.log('Cell Sel Model handleKeyDown');
52550 if(!e.isNavKeyPress()){
52553 var g = this.grid, s = this.selection;
52556 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
52558 this.select(cell[0], cell[1]);
52563 var walk = function(row, col, step){
52564 return g.walkCells(row, col, step, sm.isSelectable, sm);
52566 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
52573 // handled by onEditorKey
52574 if (g.isEditor && g.editing) {
52578 newCell = walk(r, c-1, -1);
52580 newCell = walk(r, c+1, 1);
52585 newCell = walk(r+1, c, 1);
52589 newCell = walk(r-1, c, -1);
52593 newCell = walk(r, c+1, 1);
52597 newCell = walk(r, c-1, -1);
52602 if(g.isEditor && !g.editing){
52603 g.startEditing(r, c);
52612 this.select(newCell[0], newCell[1]);
52618 acceptsNav : function(row, col, cm){
52619 return !cm.isHidden(col) && cm.isCellEditable(col, row);
52623 * @param {Number} field (not used) - as it's normally used as a listener
52624 * @param {Number} e - event - fake it by using
52626 * var e = Roo.EventObjectImpl.prototype;
52627 * e.keyCode = e.TAB
52631 onEditorKey : function(field, e){
52633 var k = e.getKey(),
52636 ed = g.activeEditor,
52638 ///Roo.log('onEditorKey' + k);
52641 if (this.enter_is_tab && k == e.ENTER) {
52647 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
52649 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
52655 } else if(k == e.ENTER && !e.ctrlKey){
52658 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
52660 } else if(k == e.ESC){
52665 var ecall = { cell : newCell, forward : forward };
52666 this.fireEvent('beforeeditnext', ecall );
52667 newCell = ecall.cell;
52668 forward = ecall.forward;
52672 //Roo.log('next cell after edit');
52673 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
52674 } else if (forward) {
52675 // tabbed past last
52676 this.fireEvent.defer(100, this, ['tabend',this]);
52681 * Ext JS Library 1.1.1
52682 * Copyright(c) 2006-2007, Ext JS, LLC.
52684 * Originally Released Under LGPL - original licence link has changed is not relivant.
52687 * <script type="text/javascript">
52691 * @class Roo.grid.EditorGrid
52692 * @extends Roo.grid.Grid
52693 * Class for creating and editable grid.
52694 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52695 * The container MUST have some type of size defined for the grid to fill. The container will be
52696 * automatically set to position relative if it isn't already.
52697 * @param {Object} dataSource The data model to bind to
52698 * @param {Object} colModel The column model with info about this grid's columns
52700 Roo.grid.EditorGrid = function(container, config){
52701 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
52702 this.getGridEl().addClass("xedit-grid");
52704 if(!this.selModel){
52705 this.selModel = new Roo.grid.CellSelectionModel();
52708 this.activeEditor = null;
52712 * @event beforeedit
52713 * Fires before cell editing is triggered. The edit event object has the following properties <br />
52714 * <ul style="padding:5px;padding-left:16px;">
52715 * <li>grid - This grid</li>
52716 * <li>record - The record being edited</li>
52717 * <li>field - The field name being edited</li>
52718 * <li>value - The value for the field being edited.</li>
52719 * <li>row - The grid row index</li>
52720 * <li>column - The grid column index</li>
52721 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
52723 * @param {Object} e An edit event (see above for description)
52725 "beforeedit" : true,
52728 * Fires after a cell is edited. <br />
52729 * <ul style="padding:5px;padding-left:16px;">
52730 * <li>grid - This grid</li>
52731 * <li>record - The record being edited</li>
52732 * <li>field - The field name being edited</li>
52733 * <li>value - The value being set</li>
52734 * <li>originalValue - The original value for the field, before the edit.</li>
52735 * <li>row - The grid row index</li>
52736 * <li>column - The grid column index</li>
52738 * @param {Object} e An edit event (see above for description)
52740 "afteredit" : true,
52742 * @event validateedit
52743 * Fires after a cell is edited, but before the value is set in the record.
52744 * You can use this to modify the value being set in the field, Return false
52745 * to cancel the change. The edit event object has the following properties <br />
52746 * <ul style="padding:5px;padding-left:16px;">
52747 * <li>editor - This editor</li>
52748 * <li>grid - This grid</li>
52749 * <li>record - The record being edited</li>
52750 * <li>field - The field name being edited</li>
52751 * <li>value - The value being set</li>
52752 * <li>originalValue - The original value for the field, before the edit.</li>
52753 * <li>row - The grid row index</li>
52754 * <li>column - The grid column index</li>
52755 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
52757 * @param {Object} e An edit event (see above for description)
52759 "validateedit" : true
52761 this.on("bodyscroll", this.stopEditing, this);
52762 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
52765 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
52767 * @cfg {Number} clicksToEdit
52768 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
52775 trackMouseOver: false, // causes very odd FF errors
52777 onCellDblClick : function(g, row, col){
52778 this.startEditing(row, col);
52781 onEditComplete : function(ed, value, startValue){
52782 this.editing = false;
52783 this.activeEditor = null;
52784 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
52786 var field = this.colModel.getDataIndex(ed.col);
52791 originalValue: startValue,
52798 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
52801 if(String(value) !== String(startValue)){
52803 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
52804 r.set(field, e.value);
52805 // if we are dealing with a combo box..
52806 // then we also set the 'name' colum to be the displayField
52807 if (ed.field.displayField && ed.field.name) {
52808 r.set(ed.field.name, ed.field.el.dom.value);
52811 delete e.cancel; //?? why!!!
52812 this.fireEvent("afteredit", e);
52815 this.fireEvent("afteredit", e); // always fire it!
52817 this.view.focusCell(ed.row, ed.col);
52821 * Starts editing the specified for the specified row/column
52822 * @param {Number} rowIndex
52823 * @param {Number} colIndex
52825 startEditing : function(row, col){
52826 this.stopEditing();
52827 if(this.colModel.isCellEditable(col, row)){
52828 this.view.ensureVisible(row, col, true);
52830 var r = this.dataSource.getAt(row);
52831 var field = this.colModel.getDataIndex(col);
52832 var cell = Roo.get(this.view.getCell(row,col));
52837 value: r.data[field],
52842 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
52843 this.editing = true;
52844 var ed = this.colModel.getCellEditor(col, row);
52850 ed.render(ed.parentEl || document.body);
52856 (function(){ // complex but required for focus issues in safari, ie and opera
52860 ed.on("complete", this.onEditComplete, this, {single: true});
52861 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
52862 this.activeEditor = ed;
52863 var v = r.data[field];
52864 ed.startEdit(this.view.getCell(row, col), v);
52865 // combo's with 'displayField and name set
52866 if (ed.field.displayField && ed.field.name) {
52867 ed.field.el.dom.value = r.data[ed.field.name];
52871 }).defer(50, this);
52877 * Stops any active editing
52879 stopEditing : function(){
52880 if(this.activeEditor){
52881 this.activeEditor.completeEdit();
52883 this.activeEditor = null;
52887 * Ext JS Library 1.1.1
52888 * Copyright(c) 2006-2007, Ext JS, LLC.
52890 * Originally Released Under LGPL - original licence link has changed is not relivant.
52893 * <script type="text/javascript">
52896 // private - not really -- you end up using it !
52897 // This is a support class used internally by the Grid components
52900 * @class Roo.grid.GridEditor
52901 * @extends Roo.Editor
52902 * Class for creating and editable grid elements.
52903 * @param {Object} config any settings (must include field)
52905 Roo.grid.GridEditor = function(field, config){
52906 if (!config && field.field) {
52908 field = Roo.factory(config.field, Roo.form);
52910 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
52911 field.monitorTab = false;
52914 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
52917 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
52920 alignment: "tl-tl",
52923 cls: "x-small-editor x-grid-editor",
52928 * Ext JS Library 1.1.1
52929 * Copyright(c) 2006-2007, Ext JS, LLC.
52931 * Originally Released Under LGPL - original licence link has changed is not relivant.
52934 * <script type="text/javascript">
52939 Roo.grid.PropertyRecord = Roo.data.Record.create([
52940 {name:'name',type:'string'}, 'value'
52944 Roo.grid.PropertyStore = function(grid, source){
52946 this.store = new Roo.data.Store({
52947 recordType : Roo.grid.PropertyRecord
52949 this.store.on('update', this.onUpdate, this);
52951 this.setSource(source);
52953 Roo.grid.PropertyStore.superclass.constructor.call(this);
52958 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
52959 setSource : function(o){
52961 this.store.removeAll();
52964 if(this.isEditableValue(o[k])){
52965 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
52968 this.store.loadRecords({records: data}, {}, true);
52971 onUpdate : function(ds, record, type){
52972 if(type == Roo.data.Record.EDIT){
52973 var v = record.data['value'];
52974 var oldValue = record.modified['value'];
52975 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
52976 this.source[record.id] = v;
52978 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
52985 getProperty : function(row){
52986 return this.store.getAt(row);
52989 isEditableValue: function(val){
52990 if(val && val instanceof Date){
52992 }else if(typeof val == 'object' || typeof val == 'function'){
52998 setValue : function(prop, value){
52999 this.source[prop] = value;
53000 this.store.getById(prop).set('value', value);
53003 getSource : function(){
53004 return this.source;
53008 Roo.grid.PropertyColumnModel = function(grid, store){
53011 g.PropertyColumnModel.superclass.constructor.call(this, [
53012 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
53013 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
53015 this.store = store;
53016 this.bselect = Roo.DomHelper.append(document.body, {
53017 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
53018 {tag: 'option', value: 'true', html: 'true'},
53019 {tag: 'option', value: 'false', html: 'false'}
53022 Roo.id(this.bselect);
53025 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
53026 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
53027 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
53028 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
53029 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
53031 this.renderCellDelegate = this.renderCell.createDelegate(this);
53032 this.renderPropDelegate = this.renderProp.createDelegate(this);
53035 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
53039 valueText : 'Value',
53041 dateFormat : 'm/j/Y',
53044 renderDate : function(dateVal){
53045 return dateVal.dateFormat(this.dateFormat);
53048 renderBool : function(bVal){
53049 return bVal ? 'true' : 'false';
53052 isCellEditable : function(colIndex, rowIndex){
53053 return colIndex == 1;
53056 getRenderer : function(col){
53058 this.renderCellDelegate : this.renderPropDelegate;
53061 renderProp : function(v){
53062 return this.getPropertyName(v);
53065 renderCell : function(val){
53067 if(val instanceof Date){
53068 rv = this.renderDate(val);
53069 }else if(typeof val == 'boolean'){
53070 rv = this.renderBool(val);
53072 return Roo.util.Format.htmlEncode(rv);
53075 getPropertyName : function(name){
53076 var pn = this.grid.propertyNames;
53077 return pn && pn[name] ? pn[name] : name;
53080 getCellEditor : function(colIndex, rowIndex){
53081 var p = this.store.getProperty(rowIndex);
53082 var n = p.data['name'], val = p.data['value'];
53084 if(typeof(this.grid.customEditors[n]) == 'string'){
53085 return this.editors[this.grid.customEditors[n]];
53087 if(typeof(this.grid.customEditors[n]) != 'undefined'){
53088 return this.grid.customEditors[n];
53090 if(val instanceof Date){
53091 return this.editors['date'];
53092 }else if(typeof val == 'number'){
53093 return this.editors['number'];
53094 }else if(typeof val == 'boolean'){
53095 return this.editors['boolean'];
53097 return this.editors['string'];
53103 * @class Roo.grid.PropertyGrid
53104 * @extends Roo.grid.EditorGrid
53105 * This class represents the interface of a component based property grid control.
53106 * <br><br>Usage:<pre><code>
53107 var grid = new Roo.grid.PropertyGrid("my-container-id", {
53115 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53116 * The container MUST have some type of size defined for the grid to fill. The container will be
53117 * automatically set to position relative if it isn't already.
53118 * @param {Object} config A config object that sets properties on this grid.
53120 Roo.grid.PropertyGrid = function(container, config){
53121 config = config || {};
53122 var store = new Roo.grid.PropertyStore(this);
53123 this.store = store;
53124 var cm = new Roo.grid.PropertyColumnModel(this, store);
53125 store.store.sort('name', 'ASC');
53126 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
53129 enableColLock:false,
53130 enableColumnMove:false,
53132 trackMouseOver: false,
53135 this.getGridEl().addClass('x-props-grid');
53136 this.lastEditRow = null;
53137 this.on('columnresize', this.onColumnResize, this);
53140 * @event beforepropertychange
53141 * Fires before a property changes (return false to stop?)
53142 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53143 * @param {String} id Record Id
53144 * @param {String} newval New Value
53145 * @param {String} oldval Old Value
53147 "beforepropertychange": true,
53149 * @event propertychange
53150 * Fires after a property changes
53151 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53152 * @param {String} id Record Id
53153 * @param {String} newval New Value
53154 * @param {String} oldval Old Value
53156 "propertychange": true
53158 this.customEditors = this.customEditors || {};
53160 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
53163 * @cfg {Object} customEditors map of colnames=> custom editors.
53164 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
53165 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
53166 * false disables editing of the field.
53170 * @cfg {Object} propertyNames map of property Names to their displayed value
53173 render : function(){
53174 Roo.grid.PropertyGrid.superclass.render.call(this);
53175 this.autoSize.defer(100, this);
53178 autoSize : function(){
53179 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
53181 this.view.fitColumns();
53185 onColumnResize : function(){
53186 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
53190 * Sets the data for the Grid
53191 * accepts a Key => Value object of all the elements avaiable.
53192 * @param {Object} data to appear in grid.
53194 setSource : function(source){
53195 this.store.setSource(source);
53199 * Gets all the data from the grid.
53200 * @return {Object} data data stored in grid
53202 getSource : function(){
53203 return this.store.getSource();
53207 * Ext JS Library 1.1.1
53208 * Copyright(c) 2006-2007, Ext JS, LLC.
53210 * Originally Released Under LGPL - original licence link has changed is not relivant.
53213 * <script type="text/javascript">
53217 * @class Roo.LoadMask
53218 * A simple utility class for generically masking elements while loading data. If the element being masked has
53219 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
53220 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
53221 * element's UpdateManager load indicator and will be destroyed after the initial load.
53223 * Create a new LoadMask
53224 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
53225 * @param {Object} config The config object
53227 Roo.LoadMask = function(el, config){
53228 this.el = Roo.get(el);
53229 Roo.apply(this, config);
53231 this.store.on('beforeload', this.onBeforeLoad, this);
53232 this.store.on('load', this.onLoad, this);
53233 this.store.on('loadexception', this.onLoadException, this);
53234 this.removeMask = false;
53236 var um = this.el.getUpdateManager();
53237 um.showLoadIndicator = false; // disable the default indicator
53238 um.on('beforeupdate', this.onBeforeLoad, this);
53239 um.on('update', this.onLoad, this);
53240 um.on('failure', this.onLoad, this);
53241 this.removeMask = true;
53245 Roo.LoadMask.prototype = {
53247 * @cfg {Boolean} removeMask
53248 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
53249 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
53252 * @cfg {String} msg
53253 * The text to display in a centered loading message box (defaults to 'Loading...')
53255 msg : 'Loading...',
53257 * @cfg {String} msgCls
53258 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
53260 msgCls : 'x-mask-loading',
53263 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
53269 * Disables the mask to prevent it from being displayed
53271 disable : function(){
53272 this.disabled = true;
53276 * Enables the mask so that it can be displayed
53278 enable : function(){
53279 this.disabled = false;
53282 onLoadException : function()
53284 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
53285 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
53287 this.el.unmask(this.removeMask);
53290 onLoad : function()
53292 this.el.unmask(this.removeMask);
53296 onBeforeLoad : function(){
53297 if(!this.disabled){
53298 this.el.mask(this.msg, this.msgCls);
53303 destroy : function(){
53305 this.store.un('beforeload', this.onBeforeLoad, this);
53306 this.store.un('load', this.onLoad, this);
53307 this.store.un('loadexception', this.onLoadException, this);
53309 var um = this.el.getUpdateManager();
53310 um.un('beforeupdate', this.onBeforeLoad, this);
53311 um.un('update', this.onLoad, this);
53312 um.un('failure', this.onLoad, this);
53317 * Ext JS Library 1.1.1
53318 * Copyright(c) 2006-2007, Ext JS, LLC.
53320 * Originally Released Under LGPL - original licence link has changed is not relivant.
53323 * <script type="text/javascript">
53328 * @class Roo.XTemplate
53329 * @extends Roo.Template
53330 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
53332 var t = new Roo.XTemplate(
53333 '<select name="{name}">',
53334 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
53338 // then append, applying the master template values
53341 * Supported features:
53346 {a_variable} - output encoded.
53347 {a_variable.format:("Y-m-d")} - call a method on the variable
53348 {a_variable:raw} - unencoded output
53349 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
53350 {a_variable:this.method_on_template(...)} - call a method on the template object.
53355 <tpl for="a_variable or condition.."></tpl>
53356 <tpl if="a_variable or condition"></tpl>
53357 <tpl exec="some javascript"></tpl>
53358 <tpl name="named_template"></tpl> (experimental)
53360 <tpl for="."></tpl> - just iterate the property..
53361 <tpl for=".."></tpl> - iterates with the parent (probably the template)
53365 Roo.XTemplate = function()
53367 Roo.XTemplate.superclass.constructor.apply(this, arguments);
53374 Roo.extend(Roo.XTemplate, Roo.Template, {
53377 * The various sub templates
53382 * basic tag replacing syntax
53385 * // you can fake an object call by doing this
53389 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
53392 * compile the template
53394 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
53397 compile: function()
53401 s = ['<tpl>', s, '</tpl>'].join('');
53403 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
53404 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
53405 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
53406 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
53407 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
53412 while(true == !!(m = s.match(re))){
53413 var forMatch = m[0].match(nameRe),
53414 ifMatch = m[0].match(ifRe),
53415 execMatch = m[0].match(execRe),
53416 namedMatch = m[0].match(namedRe),
53421 name = forMatch && forMatch[1] ? forMatch[1] : '';
53424 // if - puts fn into test..
53425 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
53427 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
53432 // exec - calls a function... returns empty if true is returned.
53433 exp = execMatch && execMatch[1] ? execMatch[1] : null;
53435 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
53443 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
53444 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
53445 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
53448 var uid = namedMatch ? namedMatch[1] : id;
53452 id: namedMatch ? namedMatch[1] : id,
53459 s = s.replace(m[0], '');
53461 s = s.replace(m[0], '{xtpl'+ id + '}');
53466 for(var i = tpls.length-1; i >= 0; --i){
53467 this.compileTpl(tpls[i]);
53468 this.tpls[tpls[i].id] = tpls[i];
53470 this.master = tpls[tpls.length-1];
53474 * same as applyTemplate, except it's done to one of the subTemplates
53475 * when using named templates, you can do:
53477 * var str = pl.applySubTemplate('your-name', values);
53480 * @param {Number} id of the template
53481 * @param {Object} values to apply to template
53482 * @param {Object} parent (normaly the instance of this object)
53484 applySubTemplate : function(id, values, parent)
53488 var t = this.tpls[id];
53492 if(t.test && !t.test.call(this, values, parent)){
53496 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
53497 Roo.log(e.toString());
53503 if(t.exec && t.exec.call(this, values, parent)){
53507 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
53508 Roo.log(e.toString());
53513 var vs = t.target ? t.target.call(this, values, parent) : values;
53514 parent = t.target ? values : parent;
53515 if(t.target && vs instanceof Array){
53517 for(var i = 0, len = vs.length; i < len; i++){
53518 buf[buf.length] = t.compiled.call(this, vs[i], parent);
53520 return buf.join('');
53522 return t.compiled.call(this, vs, parent);
53524 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
53525 Roo.log(e.toString());
53526 Roo.log(t.compiled);
53531 compileTpl : function(tpl)
53533 var fm = Roo.util.Format;
53534 var useF = this.disableFormats !== true;
53535 var sep = Roo.isGecko ? "+" : ",";
53536 var undef = function(str) {
53537 Roo.log("Property not found :" + str);
53541 var fn = function(m, name, format, args)
53543 //Roo.log(arguments);
53544 args = args ? args.replace(/\\'/g,"'") : args;
53545 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
53546 if (typeof(format) == 'undefined') {
53547 format= 'htmlEncode';
53549 if (format == 'raw' ) {
53553 if(name.substr(0, 4) == 'xtpl'){
53554 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
53557 // build an array of options to determine if value is undefined..
53559 // basically get 'xxxx.yyyy' then do
53560 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
53561 // (function () { Roo.log("Property not found"); return ''; })() :
53566 Roo.each(name.split('.'), function(st) {
53567 lookfor += (lookfor.length ? '.': '') + st;
53568 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
53571 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
53574 if(format && useF){
53576 args = args ? ',' + args : "";
53578 if(format.substr(0, 5) != "this."){
53579 format = "fm." + format + '(';
53581 format = 'this.call("'+ format.substr(5) + '", ';
53585 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
53589 // called with xxyx.yuu:(test,test)
53591 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
53593 // raw.. - :raw modifier..
53594 return "'"+ sep + udef_st + name + ")"+sep+"'";
53598 // branched to use + in gecko and [].join() in others
53600 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
53601 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
53604 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
53605 body.push(tpl.body.replace(/(\r\n|\n)/g,
53606 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
53607 body.push("'].join('');};};");
53608 body = body.join('');
53611 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
53613 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
53619 applyTemplate : function(values){
53620 return this.master.compiled.call(this, values, {});
53621 //var s = this.subs;
53624 apply : function(){
53625 return this.applyTemplate.apply(this, arguments);
53630 Roo.XTemplate.from = function(el){
53631 el = Roo.getDom(el);
53632 return new Roo.XTemplate(el.value || el.innerHTML);
53634 * Original code for Roojs - LGPL
53635 * <script type="text/javascript">
53639 * @class Roo.XComponent
53640 * A delayed Element creator...
53641 * Or a way to group chunks of interface together.
53643 * Mypart.xyx = new Roo.XComponent({
53645 parent : 'Mypart.xyz', // empty == document.element.!!
53649 disabled : function() {}
53651 tree : function() { // return an tree of xtype declared components
53655 xtype : 'NestedLayoutPanel',
53662 * It can be used to build a big heiracy, with parent etc.
53663 * or you can just use this to render a single compoent to a dom element
53664 * MYPART.render(Roo.Element | String(id) | dom_element )
53666 * @extends Roo.util.Observable
53668 * @param cfg {Object} configuration of component
53671 Roo.XComponent = function(cfg) {
53672 Roo.apply(this, cfg);
53676 * Fires when this the componnt is built
53677 * @param {Roo.XComponent} c the component
53682 this.region = this.region || 'center'; // default..
53683 Roo.XComponent.register(this);
53684 this.modules = false;
53685 this.el = false; // where the layout goes..
53689 Roo.extend(Roo.XComponent, Roo.util.Observable, {
53692 * The created element (with Roo.factory())
53693 * @type {Roo.Layout}
53699 * for BC - use el in new code
53700 * @type {Roo.Layout}
53706 * for BC - use el in new code
53707 * @type {Roo.Layout}
53712 * @cfg {Function|boolean} disabled
53713 * If this module is disabled by some rule, return true from the funtion
53718 * @cfg {String} parent
53719 * Name of parent element which it get xtype added to..
53724 * @cfg {String} order
53725 * Used to set the order in which elements are created (usefull for multiple tabs)
53730 * @cfg {String} name
53731 * String to display while loading.
53735 * @cfg {String} region
53736 * Region to render component to (defaults to center)
53741 * @cfg {Array} items
53742 * A single item array - the first element is the root of the tree..
53743 * It's done this way to stay compatible with the Xtype system...
53749 * The method that retuns the tree of parts that make up this compoennt
53756 * render element to dom or tree
53757 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
53760 render : function(el)
53764 var hp = this.parent ? 1 : 0;
53766 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
53767 // if parent is a '#.....' string, then let's use that..
53768 var ename = this.parent.substr(1)
53769 this.parent = false;
53770 el = Roo.get(ename);
53772 Roo.log("Warning - element can not be found :#" + ename );
53778 if (!this.parent) {
53780 el = el ? Roo.get(el) : false;
53782 // it's a top level one..
53784 el : new Roo.BorderLayout(el || document.body, {
53790 tabPosition: 'top',
53791 //resizeTabs: true,
53792 alwaysShowTabs: el && hp? false : true,
53793 hideTabs: el || !hp ? true : false,
53800 if (!this.parent.el) {
53801 // probably an old style ctor, which has been disabled.
53805 // The 'tree' method is '_tree now'
53807 var tree = this._tree ? this._tree() : this.tree();
53808 tree.region = tree.region || this.region;
53809 this.el = this.parent.el.addxtype(tree);
53810 this.fireEvent('built', this);
53812 this.panel = this.el;
53813 this.layout = this.panel.layout;
53814 this.parentLayout = this.parent.layout || false;
53820 Roo.apply(Roo.XComponent, {
53822 * @property hideProgress
53823 * true to disable the building progress bar.. usefull on single page renders.
53826 hideProgress : false,
53828 * @property buildCompleted
53829 * True when the builder has completed building the interface.
53832 buildCompleted : false,
53835 * @property topModule
53836 * the upper most module - uses document.element as it's constructor.
53843 * @property modules
53844 * array of modules to be created by registration system.
53845 * @type {Array} of Roo.XComponent
53850 * @property elmodules
53851 * array of modules to be created by which use #ID
53852 * @type {Array} of Roo.XComponent
53859 * Register components to be built later.
53861 * This solves the following issues
53862 * - Building is not done on page load, but after an authentication process has occured.
53863 * - Interface elements are registered on page load
53864 * - Parent Interface elements may not be loaded before child, so this handles that..
53871 module : 'Pman.Tab.projectMgr',
53873 parent : 'Pman.layout',
53874 disabled : false, // or use a function..
53877 * * @param {Object} details about module
53879 register : function(obj) {
53881 Roo.XComponent.event.fireEvent('register', obj);
53882 switch(typeof(obj.disabled) ) {
53888 if ( obj.disabled() ) {
53894 if (obj.disabled) {
53900 this.modules.push(obj);
53904 * convert a string to an object..
53905 * eg. 'AAA.BBB' -> finds AAA.BBB
53909 toObject : function(str)
53911 if (!str || typeof(str) == 'object') {
53914 if (str.substring(0,1) == '#') {
53918 var ar = str.split('.');
53923 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
53925 throw "Module not found : " + str;
53929 throw "Module not found : " + str;
53931 Roo.each(ar, function(e) {
53932 if (typeof(o[e]) == 'undefined') {
53933 throw "Module not found : " + str;
53944 * move modules into their correct place in the tree..
53947 preBuild : function ()
53950 Roo.each(this.modules , function (obj)
53952 Roo.XComponent.event.fireEvent('beforebuild', obj);
53954 var opar = obj.parent;
53956 obj.parent = this.toObject(opar);
53958 Roo.log("parent:toObject failed: " + e.toString());
53963 Roo.debug && Roo.log("GOT top level module");
53964 Roo.debug && Roo.log(obj);
53965 obj.modules = new Roo.util.MixedCollection(false,
53966 function(o) { return o.order + '' }
53968 this.topModule = obj;
53971 // parent is a string (usually a dom element name..)
53972 if (typeof(obj.parent) == 'string') {
53973 this.elmodules.push(obj);
53976 if (obj.parent.constructor != Roo.XComponent) {
53977 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
53979 if (!obj.parent.modules) {
53980 obj.parent.modules = new Roo.util.MixedCollection(false,
53981 function(o) { return o.order + '' }
53984 if (obj.parent.disabled) {
53985 obj.disabled = true;
53987 obj.parent.modules.add(obj);
53992 * make a list of modules to build.
53993 * @return {Array} list of modules.
53996 buildOrder : function()
53999 var cmp = function(a,b) {
54000 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
54002 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
54003 throw "No top level modules to build";
54006 // make a flat list in order of modules to build.
54007 var mods = this.topModule ? [ this.topModule ] : [];
54009 // elmodules (is a list of DOM based modules )
54010 Roo.each(this.elmodules, function(e) {
54015 // add modules to their parents..
54016 var addMod = function(m) {
54017 Roo.debug && Roo.log("build Order: add: " + m.name);
54020 if (m.modules && !m.disabled) {
54021 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
54022 m.modules.keySort('ASC', cmp );
54023 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
54025 m.modules.each(addMod);
54027 Roo.debug && Roo.log("build Order: no child modules");
54029 // not sure if this is used any more..
54031 m.finalize.name = m.name + " (clean up) ";
54032 mods.push(m.finalize);
54036 if (this.topModule) {
54037 this.topModule.modules.keySort('ASC', cmp );
54038 this.topModule.modules.each(addMod);
54044 * Build the registered modules.
54045 * @param {Object} parent element.
54046 * @param {Function} optional method to call after module has been added.
54054 var mods = this.buildOrder();
54056 //this.allmods = mods;
54057 //Roo.debug && Roo.log(mods);
54059 if (!mods.length) { // should not happen
54060 throw "NO modules!!!";
54064 var msg = "Building Interface...";
54065 // flash it up as modal - so we store the mask!?
54066 if (!this.hideProgress) {
54067 Roo.MessageBox.show({ title: 'loading' });
54068 Roo.MessageBox.show({
54069 title: "Please wait...",
54078 var total = mods.length;
54081 var progressRun = function() {
54082 if (!mods.length) {
54083 Roo.debug && Roo.log('hide?');
54084 if (!this.hideProgress) {
54085 Roo.MessageBox.hide();
54087 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
54093 var m = mods.shift();
54096 Roo.debug && Roo.log(m);
54097 // not sure if this is supported any more.. - modules that are are just function
54098 if (typeof(m) == 'function') {
54100 return progressRun.defer(10, _this);
54104 msg = "Building Interface " + (total - mods.length) +
54106 (m.name ? (' - ' + m.name) : '');
54107 Roo.debug && Roo.log(msg);
54108 if (!this.hideProgress) {
54109 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
54113 // is the module disabled?
54114 var disabled = (typeof(m.disabled) == 'function') ?
54115 m.disabled.call(m.module.disabled) : m.disabled;
54119 return progressRun(); // we do not update the display!
54127 // it's 10 on top level, and 1 on others??? why...
54128 return progressRun.defer(10, _this);
54131 progressRun.defer(1, _this);
54145 * wrapper for event.on - aliased later..
54146 * Typically use to register a event handler for register:
54148 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
54157 Roo.XComponent.event = new Roo.util.Observable({
54161 * Fires when an Component is registered,
54162 * set the disable property on the Component to stop registration.
54163 * @param {Roo.XComponent} c the component being registerd.
54168 * @event beforebuild
54169 * Fires before each Component is built
54170 * can be used to apply permissions.
54171 * @param {Roo.XComponent} c the component being registerd.
54174 'beforebuild' : true,
54176 * @event buildcomplete
54177 * Fires on the top level element when all elements have been built
54178 * @param {Roo.XComponent} the top level component.
54180 'buildcomplete' : true
54185 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
54186 //<script type="text/javascript">
54191 * @extends Roo.LayoutDialog
54192 * A generic Login Dialog..... - only one needed in theory!?!?
54194 * Fires XComponent builder on success...
54197 * username,password, lang = for login actions.
54198 * check = 1 for periodic checking that sesion is valid.
54199 * passwordRequest = email request password
54200 * logout = 1 = to logout
54202 * Affects: (this id="????" elements)
54203 * loading (removed) (used to indicate application is loading)
54204 * loading-mask (hides) (used to hide application when it's building loading)
54210 * Myapp.login = Roo.Login({
54226 Roo.Login = function(cfg)
54232 Roo.apply(this,cfg);
54234 Roo.onReady(function() {
54240 Roo.Login.superclass.constructor.call(this, this);
54241 //this.addxtype(this.items[0]);
54247 Roo.extend(Roo.Login, Roo.LayoutDialog, {
54250 * @cfg {String} method
54251 * Method used to query for login details.
54256 * @cfg {String} url
54257 * URL to query login data. - eg. baseURL + '/Login.php'
54263 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
54268 * @property checkFails
54269 * Number of times we have attempted to get authentication check, and failed.
54274 * @property intervalID
54275 * The window interval that does the constant login checking.
54281 onLoad : function() // called on page load...
54285 if (Roo.get('loading')) { // clear any loading indicator..
54286 Roo.get('loading').remove();
54289 //this.switchLang('en'); // set the language to english..
54292 success: function(response, opts) { // check successfull...
54294 var res = this.processResponse(response);
54295 this.checkFails =0;
54296 if (!res.success) { // error!
54297 this.checkFails = 5;
54298 //console.log('call failure');
54299 return this.failure(response,opts);
54302 if (!res.data.id) { // id=0 == login failure.
54303 return this.show();
54307 //console.log(success);
54308 this.fillAuth(res.data);
54309 this.checkFails =0;
54310 Roo.XComponent.build();
54312 failure : this.show
54318 check: function(cfg) // called every so often to refresh cookie etc..
54320 if (cfg.again) { // could be undefined..
54323 this.checkFails = 0;
54326 if (this.sending) {
54327 if ( this.checkFails > 4) {
54328 Roo.MessageBox.alert("Error",
54329 "Error getting authentication status. - try reloading, or wait a while", function() {
54330 _this.sending = false;
54335 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
54338 this.sending = true;
54345 method: this.method,
54346 success: cfg.success || this.success,
54347 failure : cfg.failure || this.failure,
54357 window.onbeforeunload = function() { }; // false does not work for IE..
54367 failure : function() {
54368 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
54369 document.location = document.location.toString() + '?ts=' + Math.random();
54373 success : function() {
54374 _this.user = false;
54375 this.checkFails =0;
54377 document.location = document.location.toString() + '?ts=' + Math.random();
54384 processResponse : function (response)
54388 res = Roo.decode(response.responseText);
54390 if (typeof(res) != 'object') {
54391 res = { success : false, errorMsg : res, errors : true };
54393 if (typeof(res.success) == 'undefined') {
54394 res.success = false;
54398 res = { success : false, errorMsg : response.responseText, errors : true };
54403 success : function(response, opts) // check successfull...
54405 this.sending = false;
54406 var res = this.processResponse(response);
54407 if (!res.success) {
54408 return this.failure(response, opts);
54410 if (!res.data || !res.data.id) {
54411 return this.failure(response,opts);
54413 //console.log(res);
54414 this.fillAuth(res.data);
54416 this.checkFails =0;
54421 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
54423 this.authUser = -1;
54424 this.sending = false;
54425 var res = this.processResponse(response);
54426 //console.log(res);
54427 if ( this.checkFails > 2) {
54429 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
54430 "Error getting authentication status. - try reloading");
54433 opts.callCfg.again = true;
54434 this.check.defer(1000, this, [ opts.callCfg ]);
54440 fillAuth: function(au) {
54441 this.startAuthCheck();
54442 this.authUserId = au.id;
54443 this.authUser = au;
54444 this.lastChecked = new Date();
54445 this.fireEvent('refreshed', au);
54446 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
54447 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
54448 au.lang = au.lang || 'en';
54449 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
54450 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
54451 this.switchLang(au.lang );
54454 // open system... - -on setyp..
54455 if (this.authUserId < 0) {
54456 Roo.MessageBox.alert("Warning",
54457 "This is an open system - please set up a admin user with a password.");
54460 //Pman.onload(); // which should do nothing if it's a re-auth result...
54465 startAuthCheck : function() // starter for timeout checking..
54467 if (this.intervalID) { // timer already in place...
54471 this.intervalID = window.setInterval(function() {
54472 _this.check(false);
54473 }, 120000); // every 120 secs = 2mins..
54479 switchLang : function (lang)
54481 _T = typeof(_T) == 'undefined' ? false : _T;
54482 if (!_T || !lang.length) {
54486 if (!_T && lang != 'en') {
54487 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
54491 if (typeof(_T.en) == 'undefined') {
54493 Roo.apply(_T.en, _T);
54496 if (typeof(_T[lang]) == 'undefined') {
54497 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
54502 Roo.apply(_T, _T[lang]);
54503 // just need to set the text values for everything...
54505 /* this will not work ...
54509 function formLabel(name, val) {
54510 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
54513 formLabel('password', "Password"+':');
54514 formLabel('username', "Email Address"+':');
54515 formLabel('lang', "Language"+':');
54516 this.dialog.setTitle("Login");
54517 this.dialog.buttons[0].setText("Forgot Password");
54518 this.dialog.buttons[1].setText("Login");
54537 collapsible: false,
54539 center: { // needed??
54542 // tabPosition: 'top',
54545 alwaysShowTabs: false
54549 show : function(dlg)
54551 //console.log(this);
54552 this.form = this.layout.getRegion('center').activePanel.form;
54553 this.form.dialog = dlg;
54554 this.buttons[0].form = this.form;
54555 this.buttons[0].dialog = dlg;
54556 this.buttons[1].form = this.form;
54557 this.buttons[1].dialog = dlg;
54559 //this.resizeToLogo.defer(1000,this);
54560 // this is all related to resizing for logos..
54561 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
54563 // this.resizeToLogo.defer(1000,this);
54566 //var w = Ext.lib.Dom.getViewWidth() - 100;
54567 //var h = Ext.lib.Dom.getViewHeight() - 100;
54568 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
54570 if (this.disabled) {
54575 if (this.user.id < 0) { // used for inital setup situations.
54579 if (this.intervalID) {
54580 // remove the timer
54581 window.clearInterval(this.intervalID);
54582 this.intervalID = false;
54586 if (Roo.get('loading')) {
54587 Roo.get('loading').remove();
54589 if (Roo.get('loading-mask')) {
54590 Roo.get('loading-mask').hide();
54593 //incomming._node = tnode;
54595 //this.dialog.modal = !modal;
54596 //this.dialog.show();
54600 this.form.setValues({
54601 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
54602 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
54605 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
54606 if (this.form.findField('username').getValue().length > 0 ){
54607 this.form.findField('password').focus();
54609 this.form.findField('username').focus();
54617 xtype : 'ContentPanel',
54629 style : 'margin: 10px;',
54632 actionfailed : function(f, act) {
54633 // form can return { errors: .... }
54635 //act.result.errors // invalid form element list...
54636 //act.result.errorMsg// invalid form element list...
54638 this.dialog.el.unmask();
54639 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
54640 "Login failed - communication error - try again.");
54643 actioncomplete: function(re, act) {
54645 Roo.state.Manager.set(
54646 this.dialog.realm + '.username',
54647 this.findField('username').getValue()
54649 Roo.state.Manager.set(
54650 this.dialog.realm + '.lang',
54651 this.findField('lang').getValue()
54654 this.dialog.fillAuth(act.result.data);
54656 this.dialog.hide();
54658 if (Roo.get('loading-mask')) {
54659 Roo.get('loading-mask').show();
54661 Roo.XComponent.build();
54669 xtype : 'TextField',
54671 fieldLabel: "Email Address",
54674 autoCreate : {tag: "input", type: "text", size: "20"}
54677 xtype : 'TextField',
54679 fieldLabel: "Password",
54680 inputType: 'password',
54683 autoCreate : {tag: "input", type: "text", size: "20"},
54685 specialkey : function(e,ev) {
54686 if (ev.keyCode == 13) {
54687 this.form.dialog.el.mask("Logging in");
54688 this.form.doAction('submit', {
54689 url: this.form.dialog.url,
54690 method: this.form.dialog.method
54697 xtype : 'ComboBox',
54699 fieldLabel: "Language",
54702 xtype : 'SimpleStore',
54703 fields: ['lang', 'ldisp'],
54705 [ 'en', 'English' ],
54706 [ 'zh_HK' , '\u7E41\u4E2D' ],
54707 [ 'zh_CN', '\u7C21\u4E2D' ]
54711 valueField : 'lang',
54712 hiddenName: 'lang',
54714 displayField:'ldisp',
54718 triggerAction: 'all',
54719 emptyText:'Select a Language...',
54720 selectOnFocus:true,
54722 select : function(cb, rec, ix) {
54723 this.form.switchLang(rec.data.lang);
54739 text : "Forgot Password",
54741 click : function() {
54742 //console.log(this);
54743 var n = this.form.findField('username').getValue();
54745 Roo.MessageBox.alert("Error", "Fill in your email address");
54749 url: this.dialog.url,
54753 method: this.dialog.method,
54754 success: function(response, opts) { // check successfull...
54756 var res = this.dialog.processResponse(response);
54757 if (!res.success) { // error!
54758 Roo.MessageBox.alert("Error" ,
54759 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
54762 Roo.MessageBox.alert("Notice" ,
54763 "Please check you email for the Password Reset message");
54765 failure : function() {
54766 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
54779 click : function () {
54781 this.dialog.el.mask("Logging in");
54782 this.form.doAction('submit', {
54783 url: this.dialog.url,
54784 method: this.dialog.method