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(){},
129 clone : function(obj){
130 if (obj === null || typeof obj !== 'object') {
134 var temp = obj.constructor(); // give temp the original obj's constructor
135 for (var key in obj) {
136 temp[key] = this.clone(obj[key]);
143 * Copies all the properties of config to obj if they don't already exist.
144 * @param {Object} obj The receiver of the properties
145 * @param {Object} config The source of the properties
146 * @return {Object} returns obj
148 applyIf : function(o, c){
151 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
158 * Applies event listeners to elements by selectors when the document is ready.
159 * The event name is specified with an @ suffix.
162 // add a listener for click on all anchors in element with id foo
163 '#foo a@click' : function(e, t){
167 // add the same listener to multiple selectors (separated by comma BEFORE the @)
168 '#foo a, #bar span.some-class@mouseover' : function(){
173 * @param {Object} obj The list of behaviors to apply
175 addBehaviors : function(o){
177 Roo.onReady(function(){
182 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
184 var parts = b.split('@');
185 if(parts[1]){ // for Object prototype breakers
188 cache[s] = Roo.select(s);
190 cache[s].on(parts[1], o[b]);
197 * Generates unique ids. If the element already has an id, it is unchanged
198 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200 * @return {String} The generated Id.
202 id : function(el, prefix){
203 prefix = prefix || "roo-gen";
205 var id = prefix + (++idSeed);
206 return el ? (el.id ? el.id : (el.id = id)) : id;
211 * Extends one class with another class and optionally overrides members with the passed literal. This class
212 * also adds the function "override()" to the class that can be used to override
213 * members on an instance.
214 * @param {Object} subclass The class inheriting the functionality
215 * @param {Object} superclass The class being extended
216 * @param {Object} overrides (optional) A literal with members
221 var io = function(o){
226 return function(sb, sp, overrides){
227 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230 sb = function(){sp.apply(this, arguments);};
232 var F = function(){}, sbp, spp = sp.prototype;
234 sbp = sb.prototype = new F();
238 if(spp.constructor == Object.prototype.constructor){
243 sb.override = function(o){
247 Roo.override(sb, overrides);
253 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
255 Roo.override(MyClass, {
256 newMethod1: function(){
259 newMethod2: function(foo){
264 * @param {Object} origclass The class to override
265 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
266 * containing one or more methods.
269 override : function(origclass, overrides){
271 var p = origclass.prototype;
272 for(var method in overrides){
273 p[method] = overrides[method];
278 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
284 * @param {String} namespace1
285 * @param {String} namespace2
286 * @param {String} etc
289 namespace : function(){
290 var a=arguments, o=null, i, j, d, rt;
291 for (i=0; i<a.length; ++i) {
295 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296 for (j=1; j<d.length; ++j) {
297 o[d[j]]=o[d[j]] || {};
303 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
308 * @param {String} classname
309 * @param {String} namespace (optional)
313 factory : function(c, ns)
315 // no xtype, no ns or c.xns - or forced off by c.xns
316 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
319 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320 if (c.constructor == ns[c.xtype]) {// already created...
324 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
325 var ret = new ns[c.xtype](c);
329 c.xns = false; // prevent recursion..
333 * Logs to console if it can.
335 * @param {String|Object} string
340 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
347 * 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.
351 urlEncode : function(o){
357 var ov = o[key], k = Roo.encodeURIComponent(key);
358 var type = typeof ov;
359 if(type == 'undefined'){
361 }else if(type != "function" && type != "object"){
362 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363 }else if(ov instanceof Array){
365 for(var i = 0, len = ov.length; i < len; i++) {
366 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
377 * Safe version of encodeURIComponent
378 * @param {String} data
382 encodeURIComponent : function (data)
385 return encodeURIComponent(data);
386 } catch(e) {} // should be an uri encode error.
388 if (data == '' || data == null){
391 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392 function nibble_to_hex(nibble){
393 var chars = '0123456789ABCDEF';
394 return chars.charAt(nibble);
396 data = data.toString();
398 for(var i=0; i<data.length; i++){
399 var c = data.charCodeAt(i);
400 var bs = new Array();
403 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406 bs[3] = 0x80 | (c & 0x3F);
407 }else if (c > 0x800){
409 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411 bs[2] = 0x80 | (c & 0x3F);
414 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415 bs[1] = 0x80 | (c & 0x3F);
420 for(var j=0; j<bs.length; j++){
422 var hex = nibble_to_hex((b & 0xF0) >>> 4)
423 + nibble_to_hex(b &0x0F);
432 * 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]}.
433 * @param {String} string
434 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435 * @return {Object} A literal with members
437 urlDecode : function(string, overwrite){
438 if(!string || !string.length){
442 var pairs = string.split('&');
443 var pair, name, value;
444 for(var i = 0, len = pairs.length; i < len; i++){
445 pair = pairs[i].split('=');
446 name = decodeURIComponent(pair[0]);
447 value = decodeURIComponent(pair[1]);
448 if(overwrite !== true){
449 if(typeof obj[name] == "undefined"){
451 }else if(typeof obj[name] == "string"){
452 obj[name] = [obj[name]];
453 obj[name].push(value);
455 obj[name].push(value);
465 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466 * passed array is not really an array, your function is called once with it.
467 * The supplied function is called with (Object item, Number index, Array allItems).
468 * @param {Array/NodeList/Mixed} array
469 * @param {Function} fn
470 * @param {Object} scope
472 each : function(array, fn, scope){
473 if(typeof array.length == "undefined" || typeof array == "string"){
476 for(var i = 0, len = array.length; i < len; i++){
477 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
482 combine : function(){
483 var as = arguments, l = as.length, r = [];
484 for(var i = 0; i < l; i++){
486 if(a instanceof Array){
488 }else if(a.length !== undefined && !a.substr){
489 r = r.concat(Array.prototype.slice.call(a, 0));
498 * Escapes the passed string for use in a regular expression
499 * @param {String} str
502 escapeRe : function(s) {
503 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
507 callback : function(cb, scope, args, delay){
508 if(typeof cb == "function"){
510 cb.defer(delay, scope, args || []);
512 cb.apply(scope, args || []);
518 * Return the dom node for the passed string (id), dom node, or Roo.Element
519 * @param {String/HTMLElement/Roo.Element} el
520 * @return HTMLElement
522 getDom : function(el){
526 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
530 * Shorthand for {@link Roo.ComponentMgr#get}
532 * @return Roo.Component
534 getCmp : function(id){
535 return Roo.ComponentMgr.get(id);
538 num : function(v, defaultValue){
539 if(typeof v != 'number'){
545 destroy : function(){
546 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
550 as.removeAllListeners();
554 if(typeof as.purgeListeners == 'function'){
557 if(typeof as.destroy == 'function'){
564 // inpired by a similar function in mootools library
566 * Returns the type of object that is passed in. If the object passed in is null or undefined it
567 * return false otherwise it returns one of the following values:<ul>
568 * <li><b>string</b>: If the object passed is a string</li>
569 * <li><b>number</b>: If the object passed is a number</li>
570 * <li><b>boolean</b>: If the object passed is a boolean value</li>
571 * <li><b>function</b>: If the object passed is a function reference</li>
572 * <li><b>object</b>: If the object passed is an object</li>
573 * <li><b>array</b>: If the object passed is an array</li>
574 * <li><b>regexp</b>: If the object passed is a regular expression</li>
575 * <li><b>element</b>: If the object passed is a DOM Element</li>
576 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579 * @param {Mixed} object
583 if(o === undefined || o === null){
590 if(t == 'object' && o.nodeName) {
592 case 1: return 'element';
593 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596 if(t == 'object' || t == 'function') {
597 switch(o.constructor) {
598 case Array: return 'array';
599 case RegExp: return 'regexp';
601 if(typeof o.length == 'number' && typeof o.item == 'function') {
609 * Returns true if the passed value is null, undefined or an empty string (optional).
610 * @param {Mixed} value The value to test
611 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614 isEmpty : function(v, allowBlank){
615 return v === null || v === undefined || (!allowBlank ? v === '' : false);
629 isBorderBox : isBorderBox,
631 isWindows : isWindows,
638 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
639 * you may want to set this to true.
642 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
647 * Selects a single element as a Roo Element
648 * This is about as close as you can get to jQuery's $('do crazy stuff')
649 * @param {String} selector The selector/xpath query
650 * @param {Node} root (optional) The start of the query (defaults to document).
651 * @return {Roo.Element}
653 selectNode : function(selector, root)
655 var node = Roo.DomQuery.selectNode(selector,root);
656 return node ? Roo.get(node) : new Roo.Element(false);
664 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
665 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
668 * Ext JS Library 1.1.1
669 * Copyright(c) 2006-2007, Ext JS, LLC.
671 * Originally Released Under LGPL - original licence link has changed is not relivant.
674 * <script type="text/javascript">
678 // wrappedn so fnCleanup is not in global scope...
680 function fnCleanUp() {
681 var p = Function.prototype;
682 delete p.createSequence;
684 delete p.createDelegate;
685 delete p.createCallback;
686 delete p.createInterceptor;
688 window.detachEvent("onunload", fnCleanUp);
690 window.attachEvent("onunload", fnCleanUp);
697 * These functions are available on every Function object (any JavaScript function).
699 Roo.apply(Function.prototype, {
701 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
702 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
703 * Will create a function that is bound to those 2 args.
704 * @return {Function} The new function
706 createCallback : function(/*args...*/){
707 // make args available, in function below
708 var args = arguments;
711 return method.apply(window, args);
716 * Creates a delegate (callback) that sets the scope to obj.
717 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
718 * Will create a function that is automatically scoped to this.
719 * @param {Object} obj (optional) The object for which the scope is set
720 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
721 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
722 * if a number the args are inserted at the specified position
723 * @return {Function} The new function
725 createDelegate : function(obj, args, appendArgs){
728 var callArgs = args || arguments;
729 if(appendArgs === true){
730 callArgs = Array.prototype.slice.call(arguments, 0);
731 callArgs = callArgs.concat(args);
732 }else if(typeof appendArgs == "number"){
733 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
734 var applyArgs = [appendArgs, 0].concat(args); // create method call params
735 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
737 return method.apply(obj || window, callArgs);
742 * Calls this function after the number of millseconds specified.
743 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
744 * @param {Object} obj (optional) The object for which the scope is set
745 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
746 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
747 * if a number the args are inserted at the specified position
748 * @return {Number} The timeout id that can be used with clearTimeout
750 defer : function(millis, obj, args, appendArgs){
751 var fn = this.createDelegate(obj, args, appendArgs);
753 return setTimeout(fn, millis);
759 * Create a combined function call sequence of the original function + the passed function.
760 * The resulting function returns the results of the original function.
761 * The passed fcn is called with the parameters of the original function
762 * @param {Function} fcn The function to sequence
763 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
764 * @return {Function} The new function
766 createSequence : function(fcn, scope){
767 if(typeof fcn != "function"){
772 var retval = method.apply(this || window, arguments);
773 fcn.apply(scope || this || window, arguments);
779 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
780 * The resulting function returns the results of the original function.
781 * The passed fcn is called with the parameters of the original function.
783 * @param {Function} fcn The function to call before the original
784 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
785 * @return {Function} The new function
787 createInterceptor : function(fcn, scope){
788 if(typeof fcn != "function"){
795 if(fcn.apply(scope || this || window, arguments) === false){
798 return method.apply(this || window, arguments);
804 * Ext JS Library 1.1.1
805 * Copyright(c) 2006-2007, Ext JS, LLC.
807 * Originally Released Under LGPL - original licence link has changed is not relivant.
810 * <script type="text/javascript">
813 Roo.applyIf(String, {
818 * Escapes the passed string for ' and \
819 * @param {String} string The string to escape
820 * @return {String} The escaped string
823 escape : function(string) {
824 return string.replace(/('|\\)/g, "\\$1");
828 * Pads the left side of a string with a specified character. This is especially useful
829 * for normalizing number and date strings. Example usage:
831 var s = String.leftPad('123', 5, '0');
832 // s now contains the string: '00123'
834 * @param {String} string The original string
835 * @param {Number} size The total length of the output string
836 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
837 * @return {String} The padded string
840 leftPad : function (val, size, ch) {
841 var result = new String(val);
842 if(ch === null || ch === undefined || ch === '') {
845 while (result.length < size) {
846 result = ch + result;
852 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
853 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
855 var cls = 'my-class', text = 'Some text';
856 var s = String.format('<div class="{0}">{1}</div>', cls, text);
857 // s now contains the string: '<div class="my-class">Some text</div>'
859 * @param {String} string The tokenized string to be formatted
860 * @param {String} value1 The value to replace token {0}
861 * @param {String} value2 Etc...
862 * @return {String} The formatted string
865 format : function(format){
866 var args = Array.prototype.slice.call(arguments, 1);
867 return format.replace(/\{(\d+)\}/g, function(m, i){
868 return Roo.util.Format.htmlEncode(args[i]);
874 * Utility function that allows you to easily switch a string between two alternating values. The passed value
875 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
876 * they are already different, the first value passed in is returned. Note that this method returns the new value
877 * but does not change the current string.
879 // alternate sort directions
880 sort = sort.toggle('ASC', 'DESC');
882 // instead of conditional logic:
883 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
885 * @param {String} value The value to compare to the current string
886 * @param {String} other The new value to use if the string already equals the first value passed in
887 * @return {String} The new value
890 String.prototype.toggle = function(value, other){
891 return this == value ? other : value;
894 * Ext JS Library 1.1.1
895 * Copyright(c) 2006-2007, Ext JS, LLC.
897 * Originally Released Under LGPL - original licence link has changed is not relivant.
900 * <script type="text/javascript">
906 Roo.applyIf(Number.prototype, {
908 * Checks whether or not the current number is within a desired range. If the number is already within the
909 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
910 * exceeded. Note that this method returns the constrained value but does not change the current number.
911 * @param {Number} min The minimum number in the range
912 * @param {Number} max The maximum number in the range
913 * @return {Number} The constrained value if outside the range, otherwise the current value
915 constrain : function(min, max){
916 return Math.min(Math.max(this, min), max);
920 * Ext JS Library 1.1.1
921 * Copyright(c) 2006-2007, Ext JS, LLC.
923 * Originally Released Under LGPL - original licence link has changed is not relivant.
926 * <script type="text/javascript">
931 Roo.applyIf(Array.prototype, {
933 * Checks whether or not the specified object exists in the array.
934 * @param {Object} o The object to check for
935 * @return {Number} The index of o in the array (or -1 if it is not found)
937 indexOf : function(o){
938 for (var i = 0, len = this.length; i < len; i++){
939 if(this[i] == o) return i;
945 * Removes the specified object from the array. If the object is not found nothing happens.
946 * @param {Object} o The object to remove
948 remove : function(o){
949 var index = this.indexOf(o);
951 this.splice(index, 1);
955 * Map (JS 1.6 compatibility)
956 * @param {Function} function to call
960 var len = this.length >>> 0;
961 if (typeof fun != "function")
962 throw new TypeError();
964 var res = new Array(len);
965 var thisp = arguments[1];
966 for (var i = 0; i < len; i++)
969 res[i] = fun.call(thisp, this[i], i, this);
980 * Ext JS Library 1.1.1
981 * Copyright(c) 2006-2007, Ext JS, LLC.
983 * Originally Released Under LGPL - original licence link has changed is not relivant.
986 * <script type="text/javascript">
992 * The date parsing and format syntax is a subset of
993 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
994 * supported will provide results equivalent to their PHP versions.
996 * Following is the list of all currently supported formats:
999 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1001 Format Output Description
1002 ------ ---------- --------------------------------------------------------------
1003 d 10 Day of the month, 2 digits with leading zeros
1004 D Wed A textual representation of a day, three letters
1005 j 10 Day of the month without leading zeros
1006 l Wednesday A full textual representation of the day of the week
1007 S th English ordinal day of month suffix, 2 chars (use with j)
1008 w 3 Numeric representation of the day of the week
1009 z 9 The julian date, or day of the year (0-365)
1010 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1011 F January A full textual representation of the month
1012 m 01 Numeric representation of a month, with leading zeros
1013 M Jan Month name abbreviation, three letters
1014 n 1 Numeric representation of a month, without leading zeros
1015 t 31 Number of days in the given month
1016 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1017 Y 2007 A full numeric representation of a year, 4 digits
1018 y 07 A two digit representation of a year
1019 a pm Lowercase Ante meridiem and Post meridiem
1020 A PM Uppercase Ante meridiem and Post meridiem
1021 g 3 12-hour format of an hour without leading zeros
1022 G 15 24-hour format of an hour without leading zeros
1023 h 03 12-hour format of an hour with leading zeros
1024 H 15 24-hour format of an hour with leading zeros
1025 i 05 Minutes with leading zeros
1026 s 01 Seconds, with leading zeros
1027 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1028 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1029 T CST Timezone setting of the machine running the code
1030 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1033 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1035 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1036 document.write(dt.format('Y-m-d')); //2007-01-10
1037 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1038 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
1041 * Here are some standard date/time patterns that you might find helpful. They
1042 * are not part of the source of Date.js, but to use them you can simply copy this
1043 * block of code into any script that is included after Date.js and they will also become
1044 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1047 ISO8601Long:"Y-m-d H:i:s",
1048 ISO8601Short:"Y-m-d",
1050 LongDate: "l, F d, Y",
1051 FullDateTime: "l, F d, Y g:i:s A",
1054 LongTime: "g:i:s A",
1055 SortableDateTime: "Y-m-d\\TH:i:s",
1056 UniversalSortableDateTime: "Y-m-d H:i:sO",
1063 var dt = new Date();
1064 document.write(dt.format(Date.patterns.ShortDate));
1069 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1070 * They generate precompiled functions from date formats instead of parsing and
1071 * processing the pattern every time you format a date. These functions are available
1072 * on every Date object (any javascript function).
1074 * The original article and download are here:
1075 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1082 Returns the number of milliseconds between this date and date
1083 @param {Date} date (optional) Defaults to now
1084 @return {Number} The diff in milliseconds
1085 @member Date getElapsed
1087 Date.prototype.getElapsed = function(date) {
1088 return Math.abs((date || new Date()).getTime()-this.getTime());
1090 // was in date file..
1094 Date.parseFunctions = {count:0};
1096 Date.parseRegexes = [];
1098 Date.formatFunctions = {count:0};
1101 Date.prototype.dateFormat = function(format) {
1102 if (Date.formatFunctions[format] == null) {
1103 Date.createNewFormat(format);
1105 var func = Date.formatFunctions[format];
1106 return this[func]();
1111 * Formats a date given the supplied format string
1112 * @param {String} format The format string
1113 * @return {String} The formatted date
1116 Date.prototype.format = Date.prototype.dateFormat;
1119 Date.createNewFormat = function(format) {
1120 var funcName = "format" + Date.formatFunctions.count++;
1121 Date.formatFunctions[format] = funcName;
1122 var code = "Date.prototype." + funcName + " = function(){return ";
1123 var special = false;
1125 for (var i = 0; i < format.length; ++i) {
1126 ch = format.charAt(i);
1127 if (!special && ch == "\\") {
1132 code += "'" + String.escape(ch) + "' + ";
1135 code += Date.getFormatCode(ch);
1138 /** eval:var:zzzzzzzzzzzzz */
1139 eval(code.substring(0, code.length - 3) + ";}");
1143 Date.getFormatCode = function(character) {
1144 switch (character) {
1146 return "String.leftPad(this.getDate(), 2, '0') + ";
1148 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1150 return "this.getDate() + ";
1152 return "Date.dayNames[this.getDay()] + ";
1154 return "this.getSuffix() + ";
1156 return "this.getDay() + ";
1158 return "this.getDayOfYear() + ";
1160 return "this.getWeekOfYear() + ";
1162 return "Date.monthNames[this.getMonth()] + ";
1164 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1166 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1168 return "(this.getMonth() + 1) + ";
1170 return "this.getDaysInMonth() + ";
1172 return "(this.isLeapYear() ? 1 : 0) + ";
1174 return "this.getFullYear() + ";
1176 return "('' + this.getFullYear()).substring(2, 4) + ";
1178 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1180 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1182 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1184 return "this.getHours() + ";
1186 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1188 return "String.leftPad(this.getHours(), 2, '0') + ";
1190 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1192 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1194 return "this.getGMTOffset() + ";
1196 return "this.getGMTColonOffset() + ";
1198 return "this.getTimezone() + ";
1200 return "(this.getTimezoneOffset() * -60) + ";
1202 return "'" + String.escape(character) + "' + ";
1207 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1208 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1209 * the date format that is not specified will default to the current date value for that part. Time parts can also
1210 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1211 * string or the parse operation will fail.
1214 //dt = Fri May 25 2007 (current date)
1215 var dt = new Date();
1217 //dt = Thu May 25 2006 (today's month/day in 2006)
1218 dt = Date.parseDate("2006", "Y");
1220 //dt = Sun Jan 15 2006 (all date parts specified)
1221 dt = Date.parseDate("2006-1-15", "Y-m-d");
1223 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1224 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1226 * @param {String} input The unparsed date as a string
1227 * @param {String} format The format the date is in
1228 * @return {Date} The parsed date
1231 Date.parseDate = function(input, format) {
1232 if (Date.parseFunctions[format] == null) {
1233 Date.createParser(format);
1235 var func = Date.parseFunctions[format];
1236 return Date[func](input);
1241 Date.createParser = function(format) {
1242 var funcName = "parse" + Date.parseFunctions.count++;
1243 var regexNum = Date.parseRegexes.length;
1244 var currentGroup = 1;
1245 Date.parseFunctions[format] = funcName;
1247 var code = "Date." + funcName + " = function(input){\n"
1248 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1249 + "var d = new Date();\n"
1250 + "y = d.getFullYear();\n"
1251 + "m = d.getMonth();\n"
1252 + "d = d.getDate();\n"
1253 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1254 + "if (results && results.length > 0) {";
1257 var special = false;
1259 for (var i = 0; i < format.length; ++i) {
1260 ch = format.charAt(i);
1261 if (!special && ch == "\\") {
1266 regex += String.escape(ch);
1269 var obj = Date.formatCodeToRegex(ch, currentGroup);
1270 currentGroup += obj.g;
1272 if (obj.g && obj.c) {
1278 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1279 + "{v = new Date(y, m, d, h, i, s);}\n"
1280 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1281 + "{v = new Date(y, m, d, h, i);}\n"
1282 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1283 + "{v = new Date(y, m, d, h);}\n"
1284 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1285 + "{v = new Date(y, m, d);}\n"
1286 + "else if (y >= 0 && m >= 0)\n"
1287 + "{v = new Date(y, m);}\n"
1288 + "else if (y >= 0)\n"
1289 + "{v = new Date(y);}\n"
1290 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1291 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1292 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1295 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1296 /** eval:var:zzzzzzzzzzzzz */
1301 Date.formatCodeToRegex = function(character, currentGroup) {
1302 switch (character) {
1306 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1309 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1310 s:"(\\d{1,2})"}; // day of month without leading zeroes
1313 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1314 s:"(\\d{2})"}; // day of month with leading zeroes
1318 s:"(?:" + Date.dayNames.join("|") + ")"};
1322 s:"(?:st|nd|rd|th)"};
1337 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1338 s:"(" + Date.monthNames.join("|") + ")"};
1341 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1342 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1345 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1346 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1349 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1350 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1361 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1365 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1366 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1370 c:"if (results[" + currentGroup + "] == 'am') {\n"
1371 + "if (h == 12) { h = 0; }\n"
1372 + "} else { if (h < 12) { h += 12; }}",
1376 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1377 + "if (h == 12) { h = 0; }\n"
1378 + "} else { if (h < 12) { h += 12; }}",
1383 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1384 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1388 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1389 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1392 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1396 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1401 "o = results[", currentGroup, "];\n",
1402 "var sn = o.substring(0,1);\n", // get + / - sign
1403 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1404 "var mn = o.substring(3,5) % 60;\n", // get minutes
1405 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1406 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1408 s:"([+\-]\\d{2,4})"};
1414 "o = results[", currentGroup, "];\n",
1415 "var sn = o.substring(0,1);\n",
1416 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1417 "var mn = o.substring(4,6) % 60;\n",
1418 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1419 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1425 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1428 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1429 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1430 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1434 s:String.escape(character)};
1439 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1440 * @return {String} The abbreviated timezone name (e.g. 'CST')
1442 Date.prototype.getTimezone = function() {
1443 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1447 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1448 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1450 Date.prototype.getGMTOffset = function() {
1451 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1452 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1453 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1457 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1458 * @return {String} 2-characters representing hours and 2-characters representing minutes
1459 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1461 Date.prototype.getGMTColonOffset = function() {
1462 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1463 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1465 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1469 * Get the numeric day number of the year, adjusted for leap year.
1470 * @return {Number} 0 through 364 (365 in leap years)
1472 Date.prototype.getDayOfYear = function() {
1474 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1475 for (var i = 0; i < this.getMonth(); ++i) {
1476 num += Date.daysInMonth[i];
1478 return num + this.getDate() - 1;
1482 * Get the string representation of the numeric week number of the year
1483 * (equivalent to the format specifier 'W').
1484 * @return {String} '00' through '52'
1486 Date.prototype.getWeekOfYear = function() {
1487 // Skip to Thursday of this week
1488 var now = this.getDayOfYear() + (4 - this.getDay());
1489 // Find the first Thursday of the year
1490 var jan1 = new Date(this.getFullYear(), 0, 1);
1491 var then = (7 - jan1.getDay() + 4);
1492 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1496 * Whether or not the current date is in a leap year.
1497 * @return {Boolean} True if the current date is in a leap year, else false
1499 Date.prototype.isLeapYear = function() {
1500 var year = this.getFullYear();
1501 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1505 * Get the first day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getFirstDayOfMonth = function() {
1516 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1517 return (day < 0) ? (day + 7) : day;
1521 * Get the last day of the current month, adjusted for leap year. The returned value
1522 * is the numeric day index within the week (0-6) which can be used in conjunction with
1523 * the {@link #monthNames} array to retrieve the textual day name.
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1529 * @return {Number} The day number (0-6)
1531 Date.prototype.getLastDayOfMonth = function() {
1532 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1533 return (day < 0) ? (day + 7) : day;
1538 * Get the first date of this date's month
1541 Date.prototype.getFirstDateOfMonth = function() {
1542 return new Date(this.getFullYear(), this.getMonth(), 1);
1546 * Get the last date of this date's month
1549 Date.prototype.getLastDateOfMonth = function() {
1550 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1553 * Get the number of days in the current month, adjusted for leap year.
1554 * @return {Number} The number of days in the month
1556 Date.prototype.getDaysInMonth = function() {
1557 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1558 return Date.daysInMonth[this.getMonth()];
1562 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1563 * @return {String} 'st, 'nd', 'rd' or 'th'
1565 Date.prototype.getSuffix = function() {
1566 switch (this.getDate()) {
1583 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1586 * An array of textual month names.
1587 * Override these values for international dates, for example...
1588 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1607 * An array of textual day names.
1608 * Override these values for international dates, for example...
1609 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1625 Date.monthNumbers = {
1640 * Creates and returns a new Date instance with the exact same date value as the called instance.
1641 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1642 * variable will also be changed. When the intention is to create a new variable that will not
1643 * modify the original instance, you should create a clone.
1645 * Example of correctly cloning a date:
1648 var orig = new Date('10/1/2006');
1651 document.write(orig); //returns 'Thu Oct 05 2006'!
1654 var orig = new Date('10/1/2006');
1655 var copy = orig.clone();
1657 document.write(orig); //returns 'Thu Oct 01 2006'
1659 * @return {Date} The new Date instance
1661 Date.prototype.clone = function() {
1662 return new Date(this.getTime());
1666 * Clears any time information from this date
1667 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1668 @return {Date} this or the clone
1670 Date.prototype.clearTime = function(clone){
1672 return this.clone().clearTime();
1677 this.setMilliseconds(0);
1682 // safari setMonth is broken
1684 Date.brokenSetMonth = Date.prototype.setMonth;
1685 Date.prototype.setMonth = function(num){
1687 var n = Math.ceil(-num);
1688 var back_year = Math.ceil(n/12);
1689 var month = (n % 12) ? 12 - n % 12 : 0 ;
1690 this.setFullYear(this.getFullYear() - back_year);
1691 return Date.brokenSetMonth.call(this, month);
1693 return Date.brokenSetMonth.apply(this, arguments);
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1710 /** Date interval constant
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1728 * Provides a convenient method of performing basic date arithmetic. This method
1729 * does not modify the Date instance being called - it creates and returns
1730 * a new Date instance containing the resulting date value.
1735 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1736 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1738 //Negative values will subtract correctly:
1739 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1740 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1742 //You can even chain several calls together in one line!
1743 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1744 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1747 * @param {String} interval A valid date interval enum value
1748 * @param {Number} value The amount to add to the current date
1749 * @return {Date} The new Date instance
1751 Date.prototype.add = function(interval, value){
1752 var d = this.clone();
1753 if (!interval || value === 0) return d;
1754 switch(interval.toLowerCase()){
1756 d.setMilliseconds(this.getMilliseconds() + value);
1759 d.setSeconds(this.getSeconds() + value);
1762 d.setMinutes(this.getMinutes() + value);
1765 d.setHours(this.getHours() + value);
1768 d.setDate(this.getDate() + value);
1771 var day = this.getDate();
1773 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1776 d.setMonth(this.getMonth() + value);
1779 d.setFullYear(this.getFullYear() + value);
1786 * Ext JS Library 1.1.1
1787 * Copyright(c) 2006-2007, Ext JS, LLC.
1789 * Originally Released Under LGPL - original licence link has changed is not relivant.
1792 * <script type="text/javascript">
1796 * @class Roo.lib.Dom
1799 * Dom utils (from YIU afaik)
1804 * Get the view width
1805 * @param {Boolean} full True will get the full document, otherwise it's the view width
1806 * @return {Number} The width
1809 getViewWidth : function(full) {
1810 return full ? this.getDocumentWidth() : this.getViewportWidth();
1813 * Get the view height
1814 * @param {Boolean} full True will get the full document, otherwise it's the view height
1815 * @return {Number} The height
1817 getViewHeight : function(full) {
1818 return full ? this.getDocumentHeight() : this.getViewportHeight();
1821 getDocumentHeight: function() {
1822 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1823 return Math.max(scrollHeight, this.getViewportHeight());
1826 getDocumentWidth: function() {
1827 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1828 return Math.max(scrollWidth, this.getViewportWidth());
1831 getViewportHeight: function() {
1832 var height = self.innerHeight;
1833 var mode = document.compatMode;
1835 if ((mode || Roo.isIE) && !Roo.isOpera) {
1836 height = (mode == "CSS1Compat") ?
1837 document.documentElement.clientHeight :
1838 document.body.clientHeight;
1844 getViewportWidth: function() {
1845 var width = self.innerWidth;
1846 var mode = document.compatMode;
1848 if (mode || Roo.isIE) {
1849 width = (mode == "CSS1Compat") ?
1850 document.documentElement.clientWidth :
1851 document.body.clientWidth;
1856 isAncestor : function(p, c) {
1863 if (p.contains && !Roo.isSafari) {
1864 return p.contains(c);
1865 } else if (p.compareDocumentPosition) {
1866 return !!(p.compareDocumentPosition(c) & 16);
1868 var parent = c.parentNode;
1873 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1876 parent = parent.parentNode;
1882 getRegion : function(el) {
1883 return Roo.lib.Region.getRegion(el);
1886 getY : function(el) {
1887 return this.getXY(el)[1];
1890 getX : function(el) {
1891 return this.getXY(el)[0];
1894 getXY : function(el) {
1895 var p, pe, b, scroll, bd = document.body;
1896 el = Roo.getDom(el);
1897 var fly = Roo.lib.AnimBase.fly;
1898 if (el.getBoundingClientRect) {
1899 b = el.getBoundingClientRect();
1900 scroll = fly(document).getScroll();
1901 return [b.left + scroll.left, b.top + scroll.top];
1907 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1914 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1921 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1922 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1929 if (p != el && pe.getStyle('overflow') != 'visible') {
1937 if (Roo.isSafari && hasAbsolute) {
1942 if (Roo.isGecko && !hasAbsolute) {
1944 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1945 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1949 while (p && p != bd) {
1950 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1962 setXY : function(el, xy) {
1963 el = Roo.fly(el, '_setXY');
1965 var pts = el.translatePoints(xy);
1966 if (xy[0] !== false) {
1967 el.dom.style.left = pts.left + "px";
1969 if (xy[1] !== false) {
1970 el.dom.style.top = pts.top + "px";
1974 setX : function(el, x) {
1975 this.setXY(el, [x, false]);
1978 setY : function(el, y) {
1979 this.setXY(el, [false, y]);
1983 * Portions of this file are based on pieces of Yahoo User Interface Library
1984 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1985 * YUI licensed under the BSD License:
1986 * http://developer.yahoo.net/yui/license.txt
1987 * <script type="text/javascript">
1991 Roo.lib.Event = function() {
1992 var loadComplete = false;
1994 var unloadListeners = [];
1996 var onAvailStack = [];
1998 var lastError = null;
2011 startInterval: function() {
2012 if (!this._interval) {
2014 var callback = function() {
2015 self._tryPreloadAttach();
2017 this._interval = setInterval(callback, this.POLL_INTERVAL);
2022 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2023 onAvailStack.push({ id: p_id,
2026 override: p_override,
2027 checkReady: false });
2029 retryCount = this.POLL_RETRYS;
2030 this.startInterval();
2034 addListener: function(el, eventName, fn) {
2035 el = Roo.getDom(el);
2040 if ("unload" == eventName) {
2041 unloadListeners[unloadListeners.length] =
2042 [el, eventName, fn];
2046 var wrappedFn = function(e) {
2047 return fn(Roo.lib.Event.getEvent(e));
2050 var li = [el, eventName, fn, wrappedFn];
2052 var index = listeners.length;
2053 listeners[index] = li;
2055 this.doAdd(el, eventName, wrappedFn, false);
2061 removeListener: function(el, eventName, fn) {
2064 el = Roo.getDom(el);
2067 return this.purgeElement(el, false, eventName);
2071 if ("unload" == eventName) {
2073 for (i = 0,len = unloadListeners.length; i < len; i++) {
2074 var li = unloadListeners[i];
2077 li[1] == eventName &&
2079 unloadListeners.splice(i, 1);
2087 var cacheItem = null;
2090 var index = arguments[3];
2092 if ("undefined" == typeof index) {
2093 index = this._getCacheIndex(el, eventName, fn);
2097 cacheItem = listeners[index];
2100 if (!el || !cacheItem) {
2104 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2106 delete listeners[index][this.WFN];
2107 delete listeners[index][this.FN];
2108 listeners.splice(index, 1);
2115 getTarget: function(ev, resolveTextNode) {
2116 ev = ev.browserEvent || ev;
2117 var t = ev.target || ev.srcElement;
2118 return this.resolveTextNode(t);
2122 resolveTextNode: function(node) {
2123 if (Roo.isSafari && node && 3 == node.nodeType) {
2124 return node.parentNode;
2131 getPageX: function(ev) {
2132 ev = ev.browserEvent || ev;
2134 if (!x && 0 !== x) {
2135 x = ev.clientX || 0;
2138 x += this.getScroll()[1];
2146 getPageY: function(ev) {
2147 ev = ev.browserEvent || ev;
2149 if (!y && 0 !== y) {
2150 y = ev.clientY || 0;
2153 y += this.getScroll()[0];
2162 getXY: function(ev) {
2163 ev = ev.browserEvent || ev;
2164 return [this.getPageX(ev), this.getPageY(ev)];
2168 getRelatedTarget: function(ev) {
2169 ev = ev.browserEvent || ev;
2170 var t = ev.relatedTarget;
2172 if (ev.type == "mouseout") {
2174 } else if (ev.type == "mouseover") {
2179 return this.resolveTextNode(t);
2183 getTime: function(ev) {
2184 ev = ev.browserEvent || ev;
2186 var t = new Date().getTime();
2190 this.lastError = ex;
2199 stopEvent: function(ev) {
2200 this.stopPropagation(ev);
2201 this.preventDefault(ev);
2205 stopPropagation: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if (ev.stopPropagation) {
2208 ev.stopPropagation();
2210 ev.cancelBubble = true;
2215 preventDefault: function(ev) {
2216 ev = ev.browserEvent || ev;
2217 if(ev.preventDefault) {
2218 ev.preventDefault();
2220 ev.returnValue = false;
2225 getEvent: function(e) {
2226 var ev = e || window.event;
2228 var c = this.getEvent.caller;
2230 ev = c.arguments[0];
2231 if (ev && Event == ev.constructor) {
2241 getCharCode: function(ev) {
2242 ev = ev.browserEvent || ev;
2243 return ev.charCode || ev.keyCode || 0;
2247 _getCacheIndex: function(el, eventName, fn) {
2248 for (var i = 0,len = listeners.length; i < len; ++i) {
2249 var li = listeners[i];
2251 li[this.FN] == fn &&
2252 li[this.EL] == el &&
2253 li[this.TYPE] == eventName) {
2265 getEl: function(id) {
2266 return document.getElementById(id);
2270 clearCache: function() {
2274 _load: function(e) {
2275 loadComplete = true;
2276 var EU = Roo.lib.Event;
2280 EU.doRemove(window, "load", EU._load);
2285 _tryPreloadAttach: function() {
2294 var tryAgain = !loadComplete;
2296 tryAgain = (retryCount > 0);
2301 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2302 var item = onAvailStack[i];
2304 var el = this.getEl(item.id);
2307 if (!item.checkReady ||
2310 (document && document.body)) {
2313 if (item.override) {
2314 if (item.override === true) {
2317 scope = item.override;
2320 item.fn.call(scope, item.obj);
2321 onAvailStack[i] = null;
2324 notAvail.push(item);
2329 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2333 this.startInterval();
2335 clearInterval(this._interval);
2336 this._interval = null;
2339 this.locked = false;
2346 purgeElement: function(el, recurse, eventName) {
2347 var elListeners = this.getListeners(el, eventName);
2349 for (var i = 0,len = elListeners.length; i < len; ++i) {
2350 var l = elListeners[i];
2351 this.removeListener(el, l.type, l.fn);
2355 if (recurse && el && el.childNodes) {
2356 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2357 this.purgeElement(el.childNodes[i], recurse, eventName);
2363 getListeners: function(el, eventName) {
2364 var results = [], searchLists;
2366 searchLists = [listeners, unloadListeners];
2367 } else if (eventName == "unload") {
2368 searchLists = [unloadListeners];
2370 searchLists = [listeners];
2373 for (var j = 0; j < searchLists.length; ++j) {
2374 var searchList = searchLists[j];
2375 if (searchList && searchList.length > 0) {
2376 for (var i = 0,len = searchList.length; i < len; ++i) {
2377 var l = searchList[i];
2378 if (l && l[this.EL] === el &&
2379 (!eventName || eventName === l[this.TYPE])) {
2384 adjust: l[this.ADJ_SCOPE],
2392 return (results.length) ? results : null;
2396 _unload: function(e) {
2398 var EU = Roo.lib.Event, i, j, l, len, index;
2400 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2401 l = unloadListeners[i];
2404 if (l[EU.ADJ_SCOPE]) {
2405 if (l[EU.ADJ_SCOPE] === true) {
2408 scope = l[EU.ADJ_SCOPE];
2411 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2412 unloadListeners[i] = null;
2418 unloadListeners = null;
2420 if (listeners && listeners.length > 0) {
2421 j = listeners.length;
2424 l = listeners[index];
2426 EU.removeListener(l[EU.EL], l[EU.TYPE],
2436 EU.doRemove(window, "unload", EU._unload);
2441 getScroll: function() {
2442 var dd = document.documentElement, db = document.body;
2443 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2444 return [dd.scrollTop, dd.scrollLeft];
2446 return [db.scrollTop, db.scrollLeft];
2453 doAdd: function () {
2454 if (window.addEventListener) {
2455 return function(el, eventName, fn, capture) {
2456 el.addEventListener(eventName, fn, (capture));
2458 } else if (window.attachEvent) {
2459 return function(el, eventName, fn, capture) {
2460 el.attachEvent("on" + eventName, fn);
2469 doRemove: function() {
2470 if (window.removeEventListener) {
2471 return function (el, eventName, fn, capture) {
2472 el.removeEventListener(eventName, fn, (capture));
2474 } else if (window.detachEvent) {
2475 return function (el, eventName, fn) {
2476 el.detachEvent("on" + eventName, fn);
2488 var E = Roo.lib.Event;
2489 E.on = E.addListener;
2490 E.un = E.removeListener;
2492 if (document && document.body) {
2495 E.doAdd(window, "load", E._load);
2497 E.doAdd(window, "unload", E._unload);
2498 E._tryPreloadAttach();
2502 * Portions of this file are based on pieces of Yahoo User Interface Library
2503 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2504 * YUI licensed under the BSD License:
2505 * http://developer.yahoo.net/yui/license.txt
2506 * <script type="text/javascript">
2512 * @class Roo.lib.Ajax
2519 request : function(method, uri, cb, data, options) {
2521 var hs = options.headers;
2524 if(hs.hasOwnProperty(h)){
2525 this.initHeader(h, hs[h], false);
2529 if(options.xmlData){
2530 this.initHeader('Content-Type', 'text/xml', false);
2532 data = options.xmlData;
2536 return this.asyncRequest(method, uri, cb, data);
2539 serializeForm : function(form) {
2540 if(typeof form == 'string') {
2541 form = (document.getElementById(form) || document.forms[form]);
2544 var el, name, val, disabled, data = '', hasSubmit = false;
2545 for (var i = 0; i < form.elements.length; i++) {
2546 el = form.elements[i];
2547 disabled = form.elements[i].disabled;
2548 name = form.elements[i].name;
2549 val = form.elements[i].value;
2551 if (!disabled && name){
2555 case 'select-multiple':
2556 for (var j = 0; j < el.options.length; j++) {
2557 if (el.options[j].selected) {
2559 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2562 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2570 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2583 if(hasSubmit == false) {
2584 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2589 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2594 data = data.substr(0, data.length - 1);
2602 useDefaultHeader:true,
2604 defaultPostHeader:'application/x-www-form-urlencoded',
2606 useDefaultXhrHeader:true,
2608 defaultXhrHeader:'XMLHttpRequest',
2610 hasDefaultHeaders:true,
2622 setProgId:function(id)
2624 this.activeX.unshift(id);
2627 setDefaultPostHeader:function(b)
2629 this.useDefaultHeader = b;
2632 setDefaultXhrHeader:function(b)
2634 this.useDefaultXhrHeader = b;
2637 setPollingInterval:function(i)
2639 if (typeof i == 'number' && isFinite(i)) {
2640 this.pollInterval = i;
2644 createXhrObject:function(transactionId)
2650 http = new XMLHttpRequest();
2652 obj = { conn:http, tId:transactionId };
2656 for (var i = 0; i < this.activeX.length; ++i) {
2660 http = new ActiveXObject(this.activeX[i]);
2662 obj = { conn:http, tId:transactionId };
2675 getConnectionObject:function()
2678 var tId = this.transactionId;
2682 o = this.createXhrObject(tId);
2684 this.transactionId++;
2695 asyncRequest:function(method, uri, callback, postData)
2697 var o = this.getConnectionObject();
2703 o.conn.open(method, uri, true);
2705 if (this.useDefaultXhrHeader) {
2706 if (!this.defaultHeaders['X-Requested-With']) {
2707 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2711 if(postData && this.useDefaultHeader){
2712 this.initHeader('Content-Type', this.defaultPostHeader);
2715 if (this.hasDefaultHeaders || this.hasHeaders) {
2719 this.handleReadyState(o, callback);
2720 o.conn.send(postData || null);
2726 handleReadyState:function(o, callback)
2730 if (callback && callback.timeout) {
2732 this.timeout[o.tId] = window.setTimeout(function() {
2733 oConn.abort(o, callback, true);
2734 }, callback.timeout);
2737 this.poll[o.tId] = window.setInterval(
2739 if (o.conn && o.conn.readyState == 4) {
2740 window.clearInterval(oConn.poll[o.tId]);
2741 delete oConn.poll[o.tId];
2743 if(callback && callback.timeout) {
2744 window.clearTimeout(oConn.timeout[o.tId]);
2745 delete oConn.timeout[o.tId];
2748 oConn.handleTransactionResponse(o, callback);
2751 , this.pollInterval);
2754 handleTransactionResponse:function(o, callback, isAbort)
2758 this.releaseObject(o);
2762 var httpStatus, responseObject;
2766 if (o.conn.status !== undefined && o.conn.status != 0) {
2767 httpStatus = o.conn.status;
2779 if (httpStatus >= 200 && httpStatus < 300) {
2780 responseObject = this.createResponseObject(o, callback.argument);
2781 if (callback.success) {
2782 if (!callback.scope) {
2783 callback.success(responseObject);
2788 callback.success.apply(callback.scope, [responseObject]);
2793 switch (httpStatus) {
2801 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2802 if (callback.failure) {
2803 if (!callback.scope) {
2804 callback.failure(responseObject);
2807 callback.failure.apply(callback.scope, [responseObject]);
2812 responseObject = this.createResponseObject(o, callback.argument);
2813 if (callback.failure) {
2814 if (!callback.scope) {
2815 callback.failure(responseObject);
2818 callback.failure.apply(callback.scope, [responseObject]);
2824 this.releaseObject(o);
2825 responseObject = null;
2828 createResponseObject:function(o, callbackArg)
2835 var headerStr = o.conn.getAllResponseHeaders();
2836 var header = headerStr.split('\n');
2837 for (var i = 0; i < header.length; i++) {
2838 var delimitPos = header[i].indexOf(':');
2839 if (delimitPos != -1) {
2840 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2848 obj.status = o.conn.status;
2849 obj.statusText = o.conn.statusText;
2850 obj.getResponseHeader = headerObj;
2851 obj.getAllResponseHeaders = headerStr;
2852 obj.responseText = o.conn.responseText;
2853 obj.responseXML = o.conn.responseXML;
2855 if (typeof callbackArg !== undefined) {
2856 obj.argument = callbackArg;
2862 createExceptionObject:function(tId, callbackArg, isAbort)
2865 var COMM_ERROR = 'communication failure';
2866 var ABORT_CODE = -1;
2867 var ABORT_ERROR = 'transaction aborted';
2873 obj.status = ABORT_CODE;
2874 obj.statusText = ABORT_ERROR;
2877 obj.status = COMM_CODE;
2878 obj.statusText = COMM_ERROR;
2882 obj.argument = callbackArg;
2888 initHeader:function(label, value, isDefault)
2890 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2892 if (headerObj[label] === undefined) {
2893 headerObj[label] = value;
2898 headerObj[label] = value + "," + headerObj[label];
2902 this.hasDefaultHeaders = true;
2905 this.hasHeaders = true;
2910 setHeader:function(o)
2912 if (this.hasDefaultHeaders) {
2913 for (var prop in this.defaultHeaders) {
2914 if (this.defaultHeaders.hasOwnProperty(prop)) {
2915 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2920 if (this.hasHeaders) {
2921 for (var prop in this.headers) {
2922 if (this.headers.hasOwnProperty(prop)) {
2923 o.conn.setRequestHeader(prop, this.headers[prop]);
2927 this.hasHeaders = false;
2931 resetDefaultHeaders:function() {
2932 delete this.defaultHeaders;
2933 this.defaultHeaders = {};
2934 this.hasDefaultHeaders = false;
2937 abort:function(o, callback, isTimeout)
2939 if(this.isCallInProgress(o)) {
2941 window.clearInterval(this.poll[o.tId]);
2942 delete this.poll[o.tId];
2944 delete this.timeout[o.tId];
2947 this.handleTransactionResponse(o, callback, true);
2957 isCallInProgress:function(o)
2960 return o.conn.readyState != 4 && o.conn.readyState != 0;
2969 releaseObject:function(o)
2978 'MSXML2.XMLHTTP.3.0',
2986 * Portions of this file are based on pieces of Yahoo User Interface Library
2987 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2988 * YUI licensed under the BSD License:
2989 * http://developer.yahoo.net/yui/license.txt
2990 * <script type="text/javascript">
2994 Roo.lib.Region = function(t, r, b, l) {
3004 Roo.lib.Region.prototype = {
3005 contains : function(region) {
3006 return ( region.left >= this.left &&
3007 region.right <= this.right &&
3008 region.top >= this.top &&
3009 region.bottom <= this.bottom );
3013 getArea : function() {
3014 return ( (this.bottom - this.top) * (this.right - this.left) );
3017 intersect : function(region) {
3018 var t = Math.max(this.top, region.top);
3019 var r = Math.min(this.right, region.right);
3020 var b = Math.min(this.bottom, region.bottom);
3021 var l = Math.max(this.left, region.left);
3023 if (b >= t && r >= l) {
3024 return new Roo.lib.Region(t, r, b, l);
3029 union : function(region) {
3030 var t = Math.min(this.top, region.top);
3031 var r = Math.max(this.right, region.right);
3032 var b = Math.max(this.bottom, region.bottom);
3033 var l = Math.min(this.left, region.left);
3035 return new Roo.lib.Region(t, r, b, l);
3038 adjust : function(t, l, b, r) {
3047 Roo.lib.Region.getRegion = function(el) {
3048 var p = Roo.lib.Dom.getXY(el);
3051 var r = p[0] + el.offsetWidth;
3052 var b = p[1] + el.offsetHeight;
3055 return new Roo.lib.Region(t, r, b, l);
3058 * Portions of this file are based on pieces of Yahoo User Interface Library
3059 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3060 * YUI licensed under the BSD License:
3061 * http://developer.yahoo.net/yui/license.txt
3062 * <script type="text/javascript">
3065 //@@dep Roo.lib.Region
3068 Roo.lib.Point = function(x, y) {
3069 if (x instanceof Array) {
3073 this.x = this.right = this.left = this[0] = x;
3074 this.y = this.top = this.bottom = this[1] = y;
3077 Roo.lib.Point.prototype = new Roo.lib.Region();
3079 * Portions of this file are based on pieces of Yahoo User Interface Library
3080 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3081 * YUI licensed under the BSD License:
3082 * http://developer.yahoo.net/yui/license.txt
3083 * <script type="text/javascript">
3090 scroll : function(el, args, duration, easing, cb, scope) {
3091 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3094 motion : function(el, args, duration, easing, cb, scope) {
3095 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3098 color : function(el, args, duration, easing, cb, scope) {
3099 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3102 run : function(el, args, duration, easing, cb, scope, type) {
3103 type = type || Roo.lib.AnimBase;
3104 if (typeof easing == "string") {
3105 easing = Roo.lib.Easing[easing];
3107 var anim = new type(el, args, duration, easing);
3108 anim.animateX(function() {
3109 Roo.callback(cb, scope);
3115 * Portions of this file are based on pieces of Yahoo User Interface Library
3116 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3117 * YUI licensed under the BSD License:
3118 * http://developer.yahoo.net/yui/license.txt
3119 * <script type="text/javascript">
3127 if (!libFlyweight) {
3128 libFlyweight = new Roo.Element.Flyweight();
3130 libFlyweight.dom = el;
3131 return libFlyweight;
3134 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3138 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3140 this.init(el, attributes, duration, method);
3144 Roo.lib.AnimBase.fly = fly;
3148 Roo.lib.AnimBase.prototype = {
3150 toString: function() {
3151 var el = this.getEl();
3152 var id = el.id || el.tagName;
3153 return ("Anim " + id);
3157 noNegatives: /width|height|opacity|padding/i,
3158 offsetAttribute: /^((width|height)|(top|left))$/,
3159 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3160 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3164 doMethod: function(attr, start, end) {
3165 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3169 setAttribute: function(attr, val, unit) {
3170 if (this.patterns.noNegatives.test(attr)) {
3171 val = (val > 0) ? val : 0;
3174 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3178 getAttribute: function(attr) {
3179 var el = this.getEl();
3180 var val = fly(el).getStyle(attr);
3182 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3183 return parseFloat(val);
3186 var a = this.patterns.offsetAttribute.exec(attr) || [];
3187 var pos = !!( a[3] );
3188 var box = !!( a[2] );
3191 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3192 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3201 getDefaultUnit: function(attr) {
3202 if (this.patterns.defaultUnit.test(attr)) {
3209 animateX : function(callback, scope) {
3210 var f = function() {
3211 this.onComplete.removeListener(f);
3212 if (typeof callback == "function") {
3213 callback.call(scope || this, this);
3216 this.onComplete.addListener(f, this);
3221 setRuntimeAttribute: function(attr) {
3224 var attributes = this.attributes;
3226 this.runtimeAttributes[attr] = {};
3228 var isset = function(prop) {
3229 return (typeof prop !== 'undefined');
3232 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3236 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3239 if (isset(attributes[attr]['to'])) {
3240 end = attributes[attr]['to'];
3241 } else if (isset(attributes[attr]['by'])) {
3242 if (start.constructor == Array) {
3244 for (var i = 0, len = start.length; i < len; ++i) {
3245 end[i] = start[i] + attributes[attr]['by'][i];
3248 end = start + attributes[attr]['by'];
3252 this.runtimeAttributes[attr].start = start;
3253 this.runtimeAttributes[attr].end = end;
3256 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3260 init: function(el, attributes, duration, method) {
3262 var isAnimated = false;
3265 var startTime = null;
3268 var actualFrames = 0;
3271 el = Roo.getDom(el);
3274 this.attributes = attributes || {};
3277 this.duration = duration || 1;
3280 this.method = method || Roo.lib.Easing.easeNone;
3283 this.useSeconds = true;
3286 this.currentFrame = 0;
3289 this.totalFrames = Roo.lib.AnimMgr.fps;
3292 this.getEl = function() {
3297 this.isAnimated = function() {
3302 this.getStartTime = function() {
3306 this.runtimeAttributes = {};
3309 this.animate = function() {
3310 if (this.isAnimated()) {
3314 this.currentFrame = 0;
3316 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3318 Roo.lib.AnimMgr.registerElement(this);
3322 this.stop = function(finish) {
3324 this.currentFrame = this.totalFrames;
3325 this._onTween.fire();
3327 Roo.lib.AnimMgr.stop(this);
3330 var onStart = function() {
3331 this.onStart.fire();
3333 this.runtimeAttributes = {};
3334 for (var attr in this.attributes) {
3335 this.setRuntimeAttribute(attr);
3340 startTime = new Date();
3344 var onTween = function() {
3346 duration: new Date() - this.getStartTime(),
3347 currentFrame: this.currentFrame
3350 data.toString = function() {
3352 'duration: ' + data.duration +
3353 ', currentFrame: ' + data.currentFrame
3357 this.onTween.fire(data);
3359 var runtimeAttributes = this.runtimeAttributes;
3361 for (var attr in runtimeAttributes) {
3362 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3368 var onComplete = function() {
3369 var actual_duration = (new Date() - startTime) / 1000 ;
3372 duration: actual_duration,
3373 frames: actualFrames,
3374 fps: actualFrames / actual_duration
3377 data.toString = function() {
3379 'duration: ' + data.duration +
3380 ', frames: ' + data.frames +
3381 ', fps: ' + data.fps
3387 this.onComplete.fire(data);
3391 this._onStart = new Roo.util.Event(this);
3392 this.onStart = new Roo.util.Event(this);
3393 this.onTween = new Roo.util.Event(this);
3394 this._onTween = new Roo.util.Event(this);
3395 this.onComplete = new Roo.util.Event(this);
3396 this._onComplete = new Roo.util.Event(this);
3397 this._onStart.addListener(onStart);
3398 this._onTween.addListener(onTween);
3399 this._onComplete.addListener(onComplete);
3404 * Portions of this file are based on pieces of Yahoo User Interface Library
3405 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3406 * YUI licensed under the BSD License:
3407 * http://developer.yahoo.net/yui/license.txt
3408 * <script type="text/javascript">
3412 Roo.lib.AnimMgr = new function() {
3429 this.registerElement = function(tween) {
3430 queue[queue.length] = tween;
3432 tween._onStart.fire();
3437 this.unRegister = function(tween, index) {
3438 tween._onComplete.fire();
3439 index = index || getIndex(tween);
3441 queue.splice(index, 1);
3445 if (tweenCount <= 0) {
3451 this.start = function() {
3452 if (thread === null) {
3453 thread = setInterval(this.run, this.delay);
3458 this.stop = function(tween) {
3460 clearInterval(thread);
3462 for (var i = 0, len = queue.length; i < len; ++i) {
3463 if (queue[0].isAnimated()) {
3464 this.unRegister(queue[0], 0);
3473 this.unRegister(tween);
3478 this.run = function() {
3479 for (var i = 0, len = queue.length; i < len; ++i) {
3480 var tween = queue[i];
3481 if (!tween || !tween.isAnimated()) {
3485 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3487 tween.currentFrame += 1;
3489 if (tween.useSeconds) {
3490 correctFrame(tween);
3492 tween._onTween.fire();
3495 Roo.lib.AnimMgr.stop(tween, i);
3500 var getIndex = function(anim) {
3501 for (var i = 0, len = queue.length; i < len; ++i) {
3502 if (queue[i] == anim) {
3510 var correctFrame = function(tween) {
3511 var frames = tween.totalFrames;
3512 var frame = tween.currentFrame;
3513 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3514 var elapsed = (new Date() - tween.getStartTime());
3517 if (elapsed < tween.duration * 1000) {
3518 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3520 tweak = frames - (frame + 1);
3522 if (tweak > 0 && isFinite(tweak)) {
3523 if (tween.currentFrame + tweak >= frames) {
3524 tweak = frames - (frame + 1);
3527 tween.currentFrame += tweak;
3531 * Portions of this file are based on pieces of Yahoo User Interface Library
3532 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3533 * YUI licensed under the BSD License:
3534 * http://developer.yahoo.net/yui/license.txt
3535 * <script type="text/javascript">
3538 Roo.lib.Bezier = new function() {
3540 this.getPosition = function(points, t) {
3541 var n = points.length;
3544 for (var i = 0; i < n; ++i) {
3545 tmp[i] = [points[i][0], points[i][1]];
3548 for (var j = 1; j < n; ++j) {
3549 for (i = 0; i < n - j; ++i) {
3550 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3551 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3555 return [ tmp[0][0], tmp[0][1] ];
3559 * Portions of this file are based on pieces of Yahoo User Interface Library
3560 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3561 * YUI licensed under the BSD License:
3562 * http://developer.yahoo.net/yui/license.txt
3563 * <script type="text/javascript">
3568 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3569 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3572 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3574 var fly = Roo.lib.AnimBase.fly;
3576 var superclass = Y.ColorAnim.superclass;
3577 var proto = Y.ColorAnim.prototype;
3579 proto.toString = function() {
3580 var el = this.getEl();
3581 var id = el.id || el.tagName;
3582 return ("ColorAnim " + id);
3585 proto.patterns.color = /color$/i;
3586 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3587 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3588 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3589 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3592 proto.parseColor = function(s) {
3593 if (s.length == 3) {
3597 var c = this.patterns.hex.exec(s);
3598 if (c && c.length == 4) {
3599 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3602 c = this.patterns.rgb.exec(s);
3603 if (c && c.length == 4) {
3604 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3607 c = this.patterns.hex3.exec(s);
3608 if (c && c.length == 4) {
3609 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3614 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3615 proto.getAttribute = function(attr) {
3616 var el = this.getEl();
3617 if (this.patterns.color.test(attr)) {
3618 var val = fly(el).getStyle(attr);
3620 if (this.patterns.transparent.test(val)) {
3621 var parent = el.parentNode;
3622 val = fly(parent).getStyle(attr);
3624 while (parent && this.patterns.transparent.test(val)) {
3625 parent = parent.parentNode;
3626 val = fly(parent).getStyle(attr);
3627 if (parent.tagName.toUpperCase() == 'HTML') {
3633 val = superclass.getAttribute.call(this, attr);
3638 proto.getAttribute = function(attr) {
3639 var el = this.getEl();
3640 if (this.patterns.color.test(attr)) {
3641 var val = fly(el).getStyle(attr);
3643 if (this.patterns.transparent.test(val)) {
3644 var parent = el.parentNode;
3645 val = fly(parent).getStyle(attr);
3647 while (parent && this.patterns.transparent.test(val)) {
3648 parent = parent.parentNode;
3649 val = fly(parent).getStyle(attr);
3650 if (parent.tagName.toUpperCase() == 'HTML') {
3656 val = superclass.getAttribute.call(this, attr);
3662 proto.doMethod = function(attr, start, end) {
3665 if (this.patterns.color.test(attr)) {
3667 for (var i = 0, len = start.length; i < len; ++i) {
3668 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3671 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3674 val = superclass.doMethod.call(this, attr, start, end);
3680 proto.setRuntimeAttribute = function(attr) {
3681 superclass.setRuntimeAttribute.call(this, attr);
3683 if (this.patterns.color.test(attr)) {
3684 var attributes = this.attributes;
3685 var start = this.parseColor(this.runtimeAttributes[attr].start);
3686 var end = this.parseColor(this.runtimeAttributes[attr].end);
3688 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3689 end = this.parseColor(attributes[attr].by);
3691 for (var i = 0, len = start.length; i < len; ++i) {
3692 end[i] = start[i] + end[i];
3696 this.runtimeAttributes[attr].start = start;
3697 this.runtimeAttributes[attr].end = end;
3703 * Portions of this file are based on pieces of Yahoo User Interface Library
3704 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3705 * YUI licensed under the BSD License:
3706 * http://developer.yahoo.net/yui/license.txt
3707 * <script type="text/javascript">
3713 easeNone: function (t, b, c, d) {
3714 return c * t / d + b;
3718 easeIn: function (t, b, c, d) {
3719 return c * (t /= d) * t + b;
3723 easeOut: function (t, b, c, d) {
3724 return -c * (t /= d) * (t - 2) + b;
3728 easeBoth: function (t, b, c, d) {
3729 if ((t /= d / 2) < 1) {
3730 return c / 2 * t * t + b;
3733 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3737 easeInStrong: function (t, b, c, d) {
3738 return c * (t /= d) * t * t * t + b;
3742 easeOutStrong: function (t, b, c, d) {
3743 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3747 easeBothStrong: function (t, b, c, d) {
3748 if ((t /= d / 2) < 1) {
3749 return c / 2 * t * t * t * t + b;
3752 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3757 elasticIn: function (t, b, c, d, a, p) {
3761 if ((t /= d) == 1) {
3768 if (!a || a < Math.abs(c)) {
3773 var s = p / (2 * Math.PI) * Math.asin(c / a);
3776 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3780 elasticOut: function (t, b, c, d, a, p) {
3784 if ((t /= d) == 1) {
3791 if (!a || a < Math.abs(c)) {
3796 var s = p / (2 * Math.PI) * Math.asin(c / a);
3799 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3803 elasticBoth: function (t, b, c, d, a, p) {
3808 if ((t /= d / 2) == 2) {
3816 if (!a || a < Math.abs(c)) {
3821 var s = p / (2 * Math.PI) * Math.asin(c / a);
3825 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3826 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3828 return a * Math.pow(2, -10 * (t -= 1)) *
3829 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3834 backIn: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3842 backOut: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3846 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3850 backBoth: function (t, b, c, d, s) {
3851 if (typeof s == 'undefined') {
3855 if ((t /= d / 2 ) < 1) {
3856 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3858 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3862 bounceIn: function (t, b, c, d) {
3863 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3867 bounceOut: function (t, b, c, d) {
3868 if ((t /= d) < (1 / 2.75)) {
3869 return c * (7.5625 * t * t) + b;
3870 } else if (t < (2 / 2.75)) {
3871 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3872 } else if (t < (2.5 / 2.75)) {
3873 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3875 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3879 bounceBoth: function (t, b, c, d) {
3881 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3883 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3886 * Portions of this file are based on pieces of Yahoo User Interface Library
3887 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3888 * YUI licensed under the BSD License:
3889 * http://developer.yahoo.net/yui/license.txt
3890 * <script type="text/javascript">
3894 Roo.lib.Motion = function(el, attributes, duration, method) {
3896 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3900 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3904 var superclass = Y.Motion.superclass;
3905 var proto = Y.Motion.prototype;
3907 proto.toString = function() {
3908 var el = this.getEl();
3909 var id = el.id || el.tagName;
3910 return ("Motion " + id);
3913 proto.patterns.points = /^points$/i;
3915 proto.setAttribute = function(attr, val, unit) {
3916 if (this.patterns.points.test(attr)) {
3917 unit = unit || 'px';
3918 superclass.setAttribute.call(this, 'left', val[0], unit);
3919 superclass.setAttribute.call(this, 'top', val[1], unit);
3921 superclass.setAttribute.call(this, attr, val, unit);
3925 proto.getAttribute = function(attr) {
3926 if (this.patterns.points.test(attr)) {
3928 superclass.getAttribute.call(this, 'left'),
3929 superclass.getAttribute.call(this, 'top')
3932 val = superclass.getAttribute.call(this, attr);
3938 proto.doMethod = function(attr, start, end) {
3941 if (this.patterns.points.test(attr)) {
3942 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3943 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3945 val = superclass.doMethod.call(this, attr, start, end);
3950 proto.setRuntimeAttribute = function(attr) {
3951 if (this.patterns.points.test(attr)) {
3952 var el = this.getEl();
3953 var attributes = this.attributes;
3955 var control = attributes['points']['control'] || [];
3959 if (control.length > 0 && !(control[0] instanceof Array)) {
3960 control = [control];
3963 for (i = 0,len = control.length; i < len; ++i) {
3964 tmp[i] = control[i];
3969 Roo.fly(el).position();
3971 if (isset(attributes['points']['from'])) {
3972 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3975 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3978 start = this.getAttribute('points');
3981 if (isset(attributes['points']['to'])) {
3982 end = translateValues.call(this, attributes['points']['to'], start);
3984 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = translateValues.call(this, control[i], start);
3990 } else if (isset(attributes['points']['by'])) {
3991 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3993 for (i = 0,len = control.length; i < len; ++i) {
3994 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3998 this.runtimeAttributes[attr] = [start];
4000 if (control.length > 0) {
4001 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4004 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4007 superclass.setRuntimeAttribute.call(this, attr);
4011 var translateValues = function(val, start) {
4012 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4013 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4018 var isset = function(prop) {
4019 return (typeof prop !== 'undefined');
4023 * Portions of this file are based on pieces of Yahoo User Interface Library
4024 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4025 * YUI licensed under the BSD License:
4026 * http://developer.yahoo.net/yui/license.txt
4027 * <script type="text/javascript">
4031 Roo.lib.Scroll = function(el, attributes, duration, method) {
4033 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4037 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4041 var superclass = Y.Scroll.superclass;
4042 var proto = Y.Scroll.prototype;
4044 proto.toString = function() {
4045 var el = this.getEl();
4046 var id = el.id || el.tagName;
4047 return ("Scroll " + id);
4050 proto.doMethod = function(attr, start, end) {
4053 if (attr == 'scroll') {
4055 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4056 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4060 val = superclass.doMethod.call(this, attr, start, end);
4065 proto.getAttribute = function(attr) {
4067 var el = this.getEl();
4069 if (attr == 'scroll') {
4070 val = [ el.scrollLeft, el.scrollTop ];
4072 val = superclass.getAttribute.call(this, attr);
4078 proto.setAttribute = function(attr, val, unit) {
4079 var el = this.getEl();
4081 if (attr == 'scroll') {
4082 el.scrollLeft = val[0];
4083 el.scrollTop = val[1];
4085 superclass.setAttribute.call(this, attr, val, unit);
4091 * Ext JS Library 1.1.1
4092 * Copyright(c) 2006-2007, Ext JS, LLC.
4094 * Originally Released Under LGPL - original licence link has changed is not relivant.
4097 * <script type="text/javascript">
4101 // nasty IE9 hack - what a pile of crap that is..
4103 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4104 Range.prototype.createContextualFragment = function (html) {
4105 var doc = window.document;
4106 var container = doc.createElement("div");
4107 container.innerHTML = html;
4108 var frag = doc.createDocumentFragment(), n;
4109 while ((n = container.firstChild)) {
4110 frag.appendChild(n);
4117 * @class Roo.DomHelper
4118 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4119 * 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>.
4122 Roo.DomHelper = function(){
4123 var tempTableEl = null;
4124 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4125 var tableRe = /^table|tbody|tr|td$/i;
4127 // build as innerHTML where available
4129 var createHtml = function(o){
4130 if(typeof o == 'string'){
4139 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4140 if(attr == "style"){
4142 if(typeof s == "function"){
4145 if(typeof s == "string"){
4146 b += ' style="' + s + '"';
4147 }else if(typeof s == "object"){
4150 if(typeof s[key] != "function"){
4151 b += key + ":" + s[key] + ";";
4158 b += ' class="' + o["cls"] + '"';
4159 }else if(attr == "htmlFor"){
4160 b += ' for="' + o["htmlFor"] + '"';
4162 b += " " + attr + '="' + o[attr] + '"';
4166 if(emptyTags.test(o.tag)){
4170 var cn = o.children || o.cn;
4172 //http://bugs.kde.org/show_bug.cgi?id=71506
4173 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4174 for(var i = 0, len = cn.length; i < len; i++) {
4175 b += createHtml(cn[i], b);
4178 b += createHtml(cn, b);
4184 b += "</" + o.tag + ">";
4191 var createDom = function(o, parentNode){
4193 // defininition craeted..
4195 if (o.ns && o.ns != 'html') {
4197 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4198 xmlns[o.ns] = o.xmlns;
4201 if (typeof(xmlns[o.ns]) == 'undefined') {
4202 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4208 if (typeof(o) == 'string') {
4209 return parentNode.appendChild(document.createTextNode(o));
4211 o.tag = o.tag || div;
4212 if (o.ns && Roo.isIE) {
4214 o.tag = o.ns + ':' + o.tag;
4217 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4218 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4221 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4222 attr == "style" || typeof o[attr] == "function") continue;
4224 if(attr=="cls" && Roo.isIE){
4225 el.className = o["cls"];
4227 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4228 else el[attr] = o[attr];
4231 Roo.DomHelper.applyStyles(el, o.style);
4232 var cn = o.children || o.cn;
4234 //http://bugs.kde.org/show_bug.cgi?id=71506
4235 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4236 for(var i = 0, len = cn.length; i < len; i++) {
4237 createDom(cn[i], el);
4244 el.innerHTML = o.html;
4247 parentNode.appendChild(el);
4252 var ieTable = function(depth, s, h, e){
4253 tempTableEl.innerHTML = [s, h, e].join('');
4254 var i = -1, el = tempTableEl;
4261 // kill repeat to save bytes
4265 tbe = '</tbody>'+te,
4271 * Nasty code for IE's broken table implementation
4273 var insertIntoTable = function(tag, where, el, html){
4275 tempTableEl = document.createElement('div');
4280 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4283 if(where == 'beforebegin'){
4287 before = el.nextSibling;
4290 node = ieTable(4, trs, html, tre);
4292 else if(tag == 'tr'){
4293 if(where == 'beforebegin'){
4296 node = ieTable(3, tbs, html, tbe);
4297 } else if(where == 'afterend'){
4298 before = el.nextSibling;
4300 node = ieTable(3, tbs, html, tbe);
4301 } else{ // INTO a TR
4302 if(where == 'afterbegin'){
4303 before = el.firstChild;
4305 node = ieTable(4, trs, html, tre);
4307 } else if(tag == 'tbody'){
4308 if(where == 'beforebegin'){
4311 node = ieTable(2, ts, html, te);
4312 } else if(where == 'afterend'){
4313 before = el.nextSibling;
4315 node = ieTable(2, ts, html, te);
4317 if(where == 'afterbegin'){
4318 before = el.firstChild;
4320 node = ieTable(3, tbs, html, tbe);
4323 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4326 if(where == 'afterbegin'){
4327 before = el.firstChild;
4329 node = ieTable(2, ts, html, te);
4331 el.insertBefore(node, before);
4336 /** True to force the use of DOM instead of html fragments @type Boolean */
4340 * Returns the markup for the passed Element(s) config
4341 * @param {Object} o The Dom object spec (and children)
4344 markup : function(o){
4345 return createHtml(o);
4349 * Applies a style specification to an element
4350 * @param {String/HTMLElement} el The element to apply styles to
4351 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4352 * a function which returns such a specification.
4354 applyStyles : function(el, styles){
4357 if(typeof styles == "string"){
4358 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4360 while ((matches = re.exec(styles)) != null){
4361 el.setStyle(matches[1], matches[2]);
4363 }else if (typeof styles == "object"){
4364 for (var style in styles){
4365 el.setStyle(style, styles[style]);
4367 }else if (typeof styles == "function"){
4368 Roo.DomHelper.applyStyles(el, styles.call());
4374 * Inserts an HTML fragment into the Dom
4375 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4376 * @param {HTMLElement} el The context element
4377 * @param {String} html The HTML fragmenet
4378 * @return {HTMLElement} The new node
4380 insertHtml : function(where, el, html){
4381 where = where.toLowerCase();
4382 if(el.insertAdjacentHTML){
4383 if(tableRe.test(el.tagName)){
4385 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4391 el.insertAdjacentHTML('BeforeBegin', html);
4392 return el.previousSibling;
4394 el.insertAdjacentHTML('AfterBegin', html);
4395 return el.firstChild;
4397 el.insertAdjacentHTML('BeforeEnd', html);
4398 return el.lastChild;
4400 el.insertAdjacentHTML('AfterEnd', html);
4401 return el.nextSibling;
4403 throw 'Illegal insertion point -> "' + where + '"';
4405 var range = el.ownerDocument.createRange();
4409 range.setStartBefore(el);
4410 frag = range.createContextualFragment(html);
4411 el.parentNode.insertBefore(frag, el);
4412 return el.previousSibling;
4415 range.setStartBefore(el.firstChild);
4416 frag = range.createContextualFragment(html);
4417 el.insertBefore(frag, el.firstChild);
4418 return el.firstChild;
4420 el.innerHTML = html;
4421 return el.firstChild;
4425 range.setStartAfter(el.lastChild);
4426 frag = range.createContextualFragment(html);
4427 el.appendChild(frag);
4428 return el.lastChild;
4430 el.innerHTML = html;
4431 return el.lastChild;
4434 range.setStartAfter(el);
4435 frag = range.createContextualFragment(html);
4436 el.parentNode.insertBefore(frag, el.nextSibling);
4437 return el.nextSibling;
4439 throw 'Illegal insertion point -> "' + where + '"';
4443 * Creates new Dom element(s) and inserts them before el
4444 * @param {String/HTMLElement/Element} el The context element
4445 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4446 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4447 * @return {HTMLElement/Roo.Element} The new node
4449 insertBefore : function(el, o, returnElement){
4450 return this.doInsert(el, o, returnElement, "beforeBegin");
4454 * Creates new Dom element(s) and inserts them after el
4455 * @param {String/HTMLElement/Element} el The context element
4456 * @param {Object} o The Dom object spec (and children)
4457 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4458 * @return {HTMLElement/Roo.Element} The new node
4460 insertAfter : function(el, o, returnElement){
4461 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4465 * Creates new Dom element(s) and inserts them as the first child of el
4466 * @param {String/HTMLElement/Element} el The context element
4467 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4468 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4469 * @return {HTMLElement/Roo.Element} The new node
4471 insertFirst : function(el, o, returnElement){
4472 return this.doInsert(el, o, returnElement, "afterBegin");
4476 doInsert : function(el, o, returnElement, pos, sibling){
4477 el = Roo.getDom(el);
4479 if(this.useDom || o.ns){
4480 newNode = createDom(o, null);
4481 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4483 var html = createHtml(o);
4484 newNode = this.insertHtml(pos, el, html);
4486 return returnElement ? Roo.get(newNode, true) : newNode;
4490 * Creates new Dom element(s) and appends them to el
4491 * @param {String/HTMLElement/Element} el The context element
4492 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4493 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4494 * @return {HTMLElement/Roo.Element} The new node
4496 append : function(el, o, returnElement){
4497 el = Roo.getDom(el);
4499 if(this.useDom || o.ns){
4500 newNode = createDom(o, null);
4501 el.appendChild(newNode);
4503 var html = createHtml(o);
4504 newNode = this.insertHtml("beforeEnd", el, html);
4506 return returnElement ? Roo.get(newNode, true) : newNode;
4510 * Creates new Dom element(s) and overwrites the contents of el with them
4511 * @param {String/HTMLElement/Element} el The context element
4512 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4513 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4514 * @return {HTMLElement/Roo.Element} The new node
4516 overwrite : function(el, o, returnElement){
4517 el = Roo.getDom(el);
4520 while (el.childNodes.length) {
4521 el.removeChild(el.firstChild);
4525 el.innerHTML = createHtml(o);
4528 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4532 * Creates a new Roo.DomHelper.Template from the Dom object spec
4533 * @param {Object} o The Dom object spec (and children)
4534 * @return {Roo.DomHelper.Template} The new template
4536 createTemplate : function(o){
4537 var html = createHtml(o);
4538 return new Roo.Template(html);
4544 * Ext JS Library 1.1.1
4545 * Copyright(c) 2006-2007, Ext JS, LLC.
4547 * Originally Released Under LGPL - original licence link has changed is not relivant.
4550 * <script type="text/javascript">
4554 * @class Roo.Template
4555 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4556 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4559 var t = new Roo.Template({
4560 html : '<div name="{id}">' +
4561 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4563 myformat: function (value, allValues) {
4564 return 'XX' + value;
4567 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4569 * For more information see this blog post with examples:
4570 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4571 - Create Elements using DOM, HTML fragments and Templates</a>.
4573 * @param {Object} cfg - Configuration object.
4575 Roo.Template = function(cfg){
4577 if(cfg instanceof Array){
4579 }else if(arguments.length > 1){
4580 cfg = Array.prototype.join.call(arguments, "");
4584 if (typeof(cfg) == 'object') {
4595 Roo.Template.prototype = {
4598 * @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..
4599 * it should be fixed so that template is observable...
4603 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4607 * Returns an HTML fragment of this template with the specified values applied.
4608 * @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'})
4609 * @return {String} The HTML fragment
4611 applyTemplate : function(values){
4615 return this.compiled(values);
4617 var useF = this.disableFormats !== true;
4618 var fm = Roo.util.Format, tpl = this;
4619 var fn = function(m, name, format, args){
4621 if(format.substr(0, 5) == "this."){
4622 return tpl.call(format.substr(5), values[name], values);
4625 // quoted values are required for strings in compiled templates,
4626 // but for non compiled we need to strip them
4627 // quoted reversed for jsmin
4628 var re = /^\s*['"](.*)["']\s*$/;
4629 args = args.split(',');
4630 for(var i = 0, len = args.length; i < len; i++){
4631 args[i] = args[i].replace(re, "$1");
4633 args = [values[name]].concat(args);
4635 args = [values[name]];
4637 return fm[format].apply(fm, args);
4640 return values[name] !== undefined ? values[name] : "";
4643 return this.html.replace(this.re, fn);
4661 this.loading = true;
4662 this.compiled = false;
4664 var cx = new Roo.data.Connection();
4668 success : function (response) {
4670 _t.html = response.responseText;
4674 failure : function(response) {
4675 Roo.log("Template failed to load from " + _t.url);
4682 * Sets the HTML used as the template and optionally compiles it.
4683 * @param {String} html
4684 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4685 * @return {Roo.Template} this
4687 set : function(html, compile){
4689 this.compiled = null;
4697 * True to disable format functions (defaults to false)
4700 disableFormats : false,
4703 * The regular expression used to match template variables
4707 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4710 * Compiles the template into an internal function, eliminating the RegEx overhead.
4711 * @return {Roo.Template} this
4713 compile : function(){
4714 var fm = Roo.util.Format;
4715 var useF = this.disableFormats !== true;
4716 var sep = Roo.isGecko ? "+" : ",";
4717 var fn = function(m, name, format, args){
4719 args = args ? ',' + args : "";
4720 if(format.substr(0, 5) != "this."){
4721 format = "fm." + format + '(';
4723 format = 'this.call("'+ format.substr(5) + '", ';
4727 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4729 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4732 // branched to use + in gecko and [].join() in others
4734 body = "this.compiled = function(values){ return '" +
4735 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4738 body = ["this.compiled = function(values){ return ['"];
4739 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4740 body.push("'].join('');};");
4741 body = body.join('');
4751 // private function used to call members
4752 call : function(fnName, value, allValues){
4753 return this[fnName](value, allValues);
4757 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4758 * @param {String/HTMLElement/Roo.Element} el The context element
4759 * @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'})
4760 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4761 * @return {HTMLElement/Roo.Element} The new node or Element
4763 insertFirst: function(el, values, returnElement){
4764 return this.doInsert('afterBegin', el, values, returnElement);
4768 * Applies the supplied values to the template and inserts the new node(s) before el.
4769 * @param {String/HTMLElement/Roo.Element} el The context element
4770 * @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'})
4771 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4772 * @return {HTMLElement/Roo.Element} The new node or Element
4774 insertBefore: function(el, values, returnElement){
4775 return this.doInsert('beforeBegin', el, values, returnElement);
4779 * Applies the supplied values to the template and inserts the new node(s) after el.
4780 * @param {String/HTMLElement/Roo.Element} el The context element
4781 * @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'})
4782 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4783 * @return {HTMLElement/Roo.Element} The new node or Element
4785 insertAfter : function(el, values, returnElement){
4786 return this.doInsert('afterEnd', el, values, returnElement);
4790 * Applies the supplied values to the template and appends the new node(s) to el.
4791 * @param {String/HTMLElement/Roo.Element} el The context element
4792 * @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'})
4793 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4794 * @return {HTMLElement/Roo.Element} The new node or Element
4796 append : function(el, values, returnElement){
4797 return this.doInsert('beforeEnd', el, values, returnElement);
4800 doInsert : function(where, el, values, returnEl){
4801 el = Roo.getDom(el);
4802 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4803 return returnEl ? Roo.get(newNode, true) : newNode;
4807 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4808 * @param {String/HTMLElement/Roo.Element} el The context element
4809 * @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'})
4810 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811 * @return {HTMLElement/Roo.Element} The new node or Element
4813 overwrite : function(el, values, returnElement){
4814 el = Roo.getDom(el);
4815 el.innerHTML = this.applyTemplate(values);
4816 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4820 * Alias for {@link #applyTemplate}
4823 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4826 Roo.DomHelper.Template = Roo.Template;
4829 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4830 * @param {String/HTMLElement} el A DOM element or its id
4831 * @returns {Roo.Template} The created template
4834 Roo.Template.from = function(el){
4835 el = Roo.getDom(el);
4836 return new Roo.Template(el.value || el.innerHTML);
4839 * Ext JS Library 1.1.1
4840 * Copyright(c) 2006-2007, Ext JS, LLC.
4842 * Originally Released Under LGPL - original licence link has changed is not relivant.
4845 * <script type="text/javascript">
4850 * This is code is also distributed under MIT license for use
4851 * with jQuery and prototype JavaScript libraries.
4854 * @class Roo.DomQuery
4855 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).
4857 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>
4860 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.
4862 <h4>Element Selectors:</h4>
4864 <li> <b>*</b> any element</li>
4865 <li> <b>E</b> an element with the tag E</li>
4866 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4867 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4868 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4869 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4871 <h4>Attribute Selectors:</h4>
4872 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4874 <li> <b>E[foo]</b> has an attribute "foo"</li>
4875 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4876 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4877 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4878 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4879 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4880 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4882 <h4>Pseudo Classes:</h4>
4884 <li> <b>E:first-child</b> E is the first child of its parent</li>
4885 <li> <b>E:last-child</b> E is the last child of its parent</li>
4886 <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>
4887 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4888 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4889 <li> <b>E:only-child</b> E is the only child of its parent</li>
4890 <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>
4891 <li> <b>E:first</b> the first E in the resultset</li>
4892 <li> <b>E:last</b> the last E in the resultset</li>
4893 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4894 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4895 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4896 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4897 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4898 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4899 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4900 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4901 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4903 <h4>CSS Value Selectors:</h4>
4905 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4906 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4907 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4908 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4909 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4910 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4914 Roo.DomQuery = function(){
4915 var cache = {}, simpleCache = {}, valueCache = {};
4916 var nonSpace = /\S/;
4917 var trimRe = /^\s+|\s+$/g;
4918 var tplRe = /\{(\d+)\}/g;
4919 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4920 var tagTokenRe = /^(#)?([\w-\*]+)/;
4921 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4923 function child(p, index){
4925 var n = p.firstChild;
4927 if(n.nodeType == 1){
4938 while((n = n.nextSibling) && n.nodeType != 1);
4943 while((n = n.previousSibling) && n.nodeType != 1);
4947 function children(d){
4948 var n = d.firstChild, ni = -1;
4950 var nx = n.nextSibling;
4951 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4961 function byClassName(c, a, v){
4965 var r = [], ri = -1, cn;
4966 for(var i = 0, ci; ci = c[i]; i++){
4967 if((' '+ci.className+' ').indexOf(v) != -1){
4974 function attrValue(n, attr){
4975 if(!n.tagName && typeof n.length != "undefined"){
4984 if(attr == "class" || attr == "className"){
4987 return n.getAttribute(attr) || n[attr];
4991 function getNodes(ns, mode, tagName){
4992 var result = [], ri = -1, cs;
4996 tagName = tagName || "*";
4997 if(typeof ns.getElementsByTagName != "undefined"){
5001 for(var i = 0, ni; ni = ns[i]; i++){
5002 cs = ni.getElementsByTagName(tagName);
5003 for(var j = 0, ci; ci = cs[j]; j++){
5007 }else if(mode == "/" || mode == ">"){
5008 var utag = tagName.toUpperCase();
5009 for(var i = 0, ni, cn; ni = ns[i]; i++){
5010 cn = ni.children || ni.childNodes;
5011 for(var j = 0, cj; cj = cn[j]; j++){
5012 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5017 }else if(mode == "+"){
5018 var utag = tagName.toUpperCase();
5019 for(var i = 0, n; n = ns[i]; i++){
5020 while((n = n.nextSibling) && n.nodeType != 1);
5021 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5025 }else if(mode == "~"){
5026 for(var i = 0, n; n = ns[i]; i++){
5027 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5036 function concat(a, b){
5040 for(var i = 0, l = b.length; i < l; i++){
5046 function byTag(cs, tagName){
5047 if(cs.tagName || cs == document){
5053 var r = [], ri = -1;
5054 tagName = tagName.toLowerCase();
5055 for(var i = 0, ci; ci = cs[i]; i++){
5056 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5063 function byId(cs, attr, id){
5064 if(cs.tagName || cs == document){
5070 var r = [], ri = -1;
5071 for(var i = 0,ci; ci = cs[i]; i++){
5072 if(ci && ci.id == id){
5080 function byAttribute(cs, attr, value, op, custom){
5081 var r = [], ri = -1, st = custom=="{";
5082 var f = Roo.DomQuery.operators[op];
5083 for(var i = 0, ci; ci = cs[i]; i++){
5086 a = Roo.DomQuery.getStyle(ci, attr);
5088 else if(attr == "class" || attr == "className"){
5090 }else if(attr == "for"){
5092 }else if(attr == "href"){
5093 a = ci.getAttribute("href", 2);
5095 a = ci.getAttribute(attr);
5097 if((f && f(a, value)) || (!f && a)){
5104 function byPseudo(cs, name, value){
5105 return Roo.DomQuery.pseudos[name](cs, value);
5108 // This is for IE MSXML which does not support expandos.
5109 // IE runs the same speed using setAttribute, however FF slows way down
5110 // and Safari completely fails so they need to continue to use expandos.
5111 var isIE = window.ActiveXObject ? true : false;
5113 // this eval is stop the compressor from
5114 // renaming the variable to something shorter
5116 /** eval:var:batch */
5121 function nodupIEXml(cs){
5123 cs[0].setAttribute("_nodup", d);
5125 for(var i = 1, len = cs.length; i < len; i++){
5127 if(!c.getAttribute("_nodup") != d){
5128 c.setAttribute("_nodup", d);
5132 for(var i = 0, len = cs.length; i < len; i++){
5133 cs[i].removeAttribute("_nodup");
5142 var len = cs.length, c, i, r = cs, cj, ri = -1;
5143 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5146 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5147 return nodupIEXml(cs);
5151 for(i = 1; c = cs[i]; i++){
5156 for(var j = 0; j < i; j++){
5159 for(j = i+1; cj = cs[j]; j++){
5171 function quickDiffIEXml(c1, c2){
5173 for(var i = 0, len = c1.length; i < len; i++){
5174 c1[i].setAttribute("_qdiff", d);
5177 for(var i = 0, len = c2.length; i < len; i++){
5178 if(c2[i].getAttribute("_qdiff") != d){
5179 r[r.length] = c2[i];
5182 for(var i = 0, len = c1.length; i < len; i++){
5183 c1[i].removeAttribute("_qdiff");
5188 function quickDiff(c1, c2){
5189 var len1 = c1.length;
5193 if(isIE && c1[0].selectSingleNode){
5194 return quickDiffIEXml(c1, c2);
5197 for(var i = 0; i < len1; i++){
5201 for(var i = 0, len = c2.length; i < len; i++){
5202 if(c2[i]._qdiff != d){
5203 r[r.length] = c2[i];
5209 function quickId(ns, mode, root, id){
5211 var d = root.ownerDocument || root;
5212 return d.getElementById(id);
5214 ns = getNodes(ns, mode, "*");
5215 return byId(ns, null, id);
5219 getStyle : function(el, name){
5220 return Roo.fly(el).getStyle(name);
5223 * Compiles a selector/xpath query into a reusable function. The returned function
5224 * takes one parameter "root" (optional), which is the context node from where the query should start.
5225 * @param {String} selector The selector/xpath query
5226 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5227 * @return {Function}
5229 compile : function(path, type){
5230 type = type || "select";
5232 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5233 var q = path, mode, lq;
5234 var tk = Roo.DomQuery.matchers;
5235 var tklen = tk.length;
5238 // accept leading mode switch
5239 var lmode = q.match(modeRe);
5240 if(lmode && lmode[1]){
5241 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5242 q = q.replace(lmode[1], "");
5244 // strip leading slashes
5245 while(path.substr(0, 1)=="/"){
5246 path = path.substr(1);
5249 while(q && lq != q){
5251 var tm = q.match(tagTokenRe);
5252 if(type == "select"){
5255 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5257 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5259 q = q.replace(tm[0], "");
5260 }else if(q.substr(0, 1) != '@'){
5261 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5266 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5268 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5270 q = q.replace(tm[0], "");
5273 while(!(mm = q.match(modeRe))){
5274 var matched = false;
5275 for(var j = 0; j < tklen; j++){
5277 var m = q.match(t.re);
5279 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5282 q = q.replace(m[0], "");
5287 // prevent infinite loop on bad selector
5289 throw 'Error parsing selector, parsing failed at "' + q + '"';
5293 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5294 q = q.replace(mm[1], "");
5297 fn[fn.length] = "return nodup(n);\n}";
5300 * list of variables that need from compression as they are used by eval.
5310 * eval:var:byClassName
5312 * eval:var:byAttribute
5313 * eval:var:attrValue
5321 * Selects a group of elements.
5322 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5323 * @param {Node} root (optional) The start of the query (defaults to document).
5326 select : function(path, root, type){
5327 if(!root || root == document){
5330 if(typeof root == "string"){
5331 root = document.getElementById(root);
5333 var paths = path.split(",");
5335 for(var i = 0, len = paths.length; i < len; i++){
5336 var p = paths[i].replace(trimRe, "");
5338 cache[p] = Roo.DomQuery.compile(p);
5340 throw p + " is not a valid selector";
5343 var result = cache[p](root);
5344 if(result && result != document){
5345 results = results.concat(result);
5348 if(paths.length > 1){
5349 return nodup(results);
5355 * Selects a single element.
5356 * @param {String} selector The selector/xpath query
5357 * @param {Node} root (optional) The start of the query (defaults to document).
5360 selectNode : function(path, root){
5361 return Roo.DomQuery.select(path, root)[0];
5365 * Selects the value of a node, optionally replacing null with the defaultValue.
5366 * @param {String} selector The selector/xpath query
5367 * @param {Node} root (optional) The start of the query (defaults to document).
5368 * @param {String} defaultValue
5370 selectValue : function(path, root, defaultValue){
5371 path = path.replace(trimRe, "");
5372 if(!valueCache[path]){
5373 valueCache[path] = Roo.DomQuery.compile(path, "select");
5375 var n = valueCache[path](root);
5376 n = n[0] ? n[0] : n;
5377 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5378 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5382 * Selects the value of a node, parsing integers and floats.
5383 * @param {String} selector The selector/xpath query
5384 * @param {Node} root (optional) The start of the query (defaults to document).
5385 * @param {Number} defaultValue
5388 selectNumber : function(path, root, defaultValue){
5389 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5390 return parseFloat(v);
5394 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5395 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5396 * @param {String} selector The simple selector to test
5399 is : function(el, ss){
5400 if(typeof el == "string"){
5401 el = document.getElementById(el);
5403 var isArray = (el instanceof Array);
5404 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5405 return isArray ? (result.length == el.length) : (result.length > 0);
5409 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5410 * @param {Array} el An array of elements to filter
5411 * @param {String} selector The simple selector to test
5412 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5413 * the selector instead of the ones that match
5416 filter : function(els, ss, nonMatches){
5417 ss = ss.replace(trimRe, "");
5418 if(!simpleCache[ss]){
5419 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5421 var result = simpleCache[ss](els);
5422 return nonMatches ? quickDiff(result, els) : result;
5426 * Collection of matching regular expressions and code snippets.
5430 select: 'n = byClassName(n, null, " {1} ");'
5432 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5433 select: 'n = byPseudo(n, "{1}", "{2}");'
5435 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5436 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5439 select: 'n = byId(n, null, "{1}");'
5442 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5447 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5448 * 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, > <.
5451 "=" : function(a, v){
5454 "!=" : function(a, v){
5457 "^=" : function(a, v){
5458 return a && a.substr(0, v.length) == v;
5460 "$=" : function(a, v){
5461 return a && a.substr(a.length-v.length) == v;
5463 "*=" : function(a, v){
5464 return a && a.indexOf(v) !== -1;
5466 "%=" : function(a, v){
5467 return (a % v) == 0;
5469 "|=" : function(a, v){
5470 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5472 "~=" : function(a, v){
5473 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5478 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5479 * and the argument (if any) supplied in the selector.
5482 "first-child" : function(c){
5483 var r = [], ri = -1, n;
5484 for(var i = 0, ci; ci = n = c[i]; i++){
5485 while((n = n.previousSibling) && n.nodeType != 1);
5493 "last-child" : function(c){
5494 var r = [], ri = -1, n;
5495 for(var i = 0, ci; ci = n = c[i]; i++){
5496 while((n = n.nextSibling) && n.nodeType != 1);
5504 "nth-child" : function(c, a) {
5505 var r = [], ri = -1;
5506 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5507 var f = (m[1] || 1) - 0, l = m[2] - 0;
5508 for(var i = 0, n; n = c[i]; i++){
5509 var pn = n.parentNode;
5510 if (batch != pn._batch) {
5512 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5513 if(cn.nodeType == 1){
5520 if (l == 0 || n.nodeIndex == l){
5523 } else if ((n.nodeIndex + l) % f == 0){
5531 "only-child" : function(c){
5532 var r = [], ri = -1;;
5533 for(var i = 0, ci; ci = c[i]; i++){
5534 if(!prev(ci) && !next(ci)){
5541 "empty" : function(c){
5542 var r = [], ri = -1;
5543 for(var i = 0, ci; ci = c[i]; i++){
5544 var cns = ci.childNodes, j = 0, cn, empty = true;
5547 if(cn.nodeType == 1 || cn.nodeType == 3){
5559 "contains" : function(c, v){
5560 var r = [], ri = -1;
5561 for(var i = 0, ci; ci = c[i]; i++){
5562 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5569 "nodeValue" : function(c, v){
5570 var r = [], ri = -1;
5571 for(var i = 0, ci; ci = c[i]; i++){
5572 if(ci.firstChild && ci.firstChild.nodeValue == v){
5579 "checked" : function(c){
5580 var r = [], ri = -1;
5581 for(var i = 0, ci; ci = c[i]; i++){
5582 if(ci.checked == true){
5589 "not" : function(c, ss){
5590 return Roo.DomQuery.filter(c, ss, true);
5593 "odd" : function(c){
5594 return this["nth-child"](c, "odd");
5597 "even" : function(c){
5598 return this["nth-child"](c, "even");
5601 "nth" : function(c, a){
5602 return c[a-1] || [];
5605 "first" : function(c){
5609 "last" : function(c){
5610 return c[c.length-1] || [];
5613 "has" : function(c, ss){
5614 var s = Roo.DomQuery.select;
5615 var r = [], ri = -1;
5616 for(var i = 0, ci; ci = c[i]; i++){
5617 if(s(ss, ci).length > 0){
5624 "next" : function(c, ss){
5625 var is = Roo.DomQuery.is;
5626 var r = [], ri = -1;
5627 for(var i = 0, ci; ci = c[i]; i++){
5636 "prev" : function(c, ss){
5637 var is = Roo.DomQuery.is;
5638 var r = [], ri = -1;
5639 for(var i = 0, ci; ci = c[i]; i++){
5652 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5653 * @param {String} path The selector/xpath query
5654 * @param {Node} root (optional) The start of the query (defaults to document).
5659 Roo.query = Roo.DomQuery.select;
5662 * Ext JS Library 1.1.1
5663 * Copyright(c) 2006-2007, Ext JS, LLC.
5665 * Originally Released Under LGPL - original licence link has changed is not relivant.
5668 * <script type="text/javascript">
5672 * @class Roo.util.Observable
5673 * Base class that provides a common interface for publishing events. Subclasses are expected to
5674 * to have a property "events" with all the events defined.<br>
5677 Employee = function(name){
5684 Roo.extend(Employee, Roo.util.Observable);
5686 * @param {Object} config properties to use (incuding events / listeners)
5689 Roo.util.Observable = function(cfg){
5692 this.addEvents(cfg.events || {});
5694 delete cfg.events; // make sure
5697 Roo.apply(this, cfg);
5700 this.on(this.listeners);
5701 delete this.listeners;
5704 Roo.util.Observable.prototype = {
5706 * @cfg {Object} listeners list of events and functions to call for this object,
5710 'click' : function(e) {
5720 * Fires the specified event with the passed parameters (minus the event name).
5721 * @param {String} eventName
5722 * @param {Object...} args Variable number of parameters are passed to handlers
5723 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5725 fireEvent : function(){
5726 var ce = this.events[arguments[0].toLowerCase()];
5727 if(typeof ce == "object"){
5728 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5735 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5738 * Appends an event handler to this component
5739 * @param {String} eventName The type of event to listen for
5740 * @param {Function} handler The method the event invokes
5741 * @param {Object} scope (optional) The scope in which to execute the handler
5742 * function. The handler function's "this" context.
5743 * @param {Object} options (optional) An object containing handler configuration
5744 * properties. This may contain any of the following properties:<ul>
5745 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5746 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5747 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5748 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5749 * by the specified number of milliseconds. If the event fires again within that time, the original
5750 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5753 * <b>Combining Options</b><br>
5754 * Using the options argument, it is possible to combine different types of listeners:<br>
5756 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5758 el.on('click', this.onClick, this, {
5765 * <b>Attaching multiple handlers in 1 call</b><br>
5766 * The method also allows for a single argument to be passed which is a config object containing properties
5767 * which specify multiple handlers.
5776 fn: this.onMouseOver,
5780 fn: this.onMouseOut,
5786 * Or a shorthand syntax which passes the same scope object to all handlers:
5789 'click': this.onClick,
5790 'mouseover': this.onMouseOver,
5791 'mouseout': this.onMouseOut,
5796 addListener : function(eventName, fn, scope, o){
5797 if(typeof eventName == "object"){
5800 if(this.filterOptRe.test(e)){
5803 if(typeof o[e] == "function"){
5805 this.addListener(e, o[e], o.scope, o);
5807 // individual options
5808 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5813 o = (!o || typeof o == "boolean") ? {} : o;
5814 eventName = eventName.toLowerCase();
5815 var ce = this.events[eventName] || true;
5816 if(typeof ce == "boolean"){
5817 ce = new Roo.util.Event(this, eventName);
5818 this.events[eventName] = ce;
5820 ce.addListener(fn, scope, o);
5824 * Removes a listener
5825 * @param {String} eventName The type of event to listen for
5826 * @param {Function} handler The handler to remove
5827 * @param {Object} scope (optional) The scope (this object) for the handler
5829 removeListener : function(eventName, fn, scope){
5830 var ce = this.events[eventName.toLowerCase()];
5831 if(typeof ce == "object"){
5832 ce.removeListener(fn, scope);
5837 * Removes all listeners for this object
5839 purgeListeners : function(){
5840 for(var evt in this.events){
5841 if(typeof this.events[evt] == "object"){
5842 this.events[evt].clearListeners();
5847 relayEvents : function(o, events){
5848 var createHandler = function(ename){
5850 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5853 for(var i = 0, len = events.length; i < len; i++){
5854 var ename = events[i];
5855 if(!this.events[ename]){ this.events[ename] = true; };
5856 o.on(ename, createHandler(ename), this);
5861 * Used to define events on this Observable
5862 * @param {Object} object The object with the events defined
5864 addEvents : function(o){
5868 Roo.applyIf(this.events, o);
5872 * Checks to see if this object has any listeners for a specified event
5873 * @param {String} eventName The name of the event to check for
5874 * @return {Boolean} True if the event is being listened for, else false
5876 hasListener : function(eventName){
5877 var e = this.events[eventName];
5878 return typeof e == "object" && e.listeners.length > 0;
5882 * Appends an event handler to this element (shorthand for addListener)
5883 * @param {String} eventName The type of event to listen for
5884 * @param {Function} handler The method the event invokes
5885 * @param {Object} scope (optional) The scope in which to execute the handler
5886 * function. The handler function's "this" context.
5887 * @param {Object} options (optional)
5890 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5892 * Removes a listener (shorthand for removeListener)
5893 * @param {String} eventName The type of event to listen for
5894 * @param {Function} handler The handler to remove
5895 * @param {Object} scope (optional) The scope (this object) for the handler
5898 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5901 * Starts capture on the specified Observable. All events will be passed
5902 * to the supplied function with the event name + standard signature of the event
5903 * <b>before</b> the event is fired. If the supplied function returns false,
5904 * the event will not fire.
5905 * @param {Observable} o The Observable to capture
5906 * @param {Function} fn The function to call
5907 * @param {Object} scope (optional) The scope (this object) for the fn
5910 Roo.util.Observable.capture = function(o, fn, scope){
5911 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5915 * Removes <b>all</b> added captures from the Observable.
5916 * @param {Observable} o The Observable to release
5919 Roo.util.Observable.releaseCapture = function(o){
5920 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5925 var createBuffered = function(h, o, scope){
5926 var task = new Roo.util.DelayedTask();
5928 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5932 var createSingle = function(h, e, fn, scope){
5934 e.removeListener(fn, scope);
5935 return h.apply(scope, arguments);
5939 var createDelayed = function(h, o, scope){
5941 var args = Array.prototype.slice.call(arguments, 0);
5942 setTimeout(function(){
5943 h.apply(scope, args);
5948 Roo.util.Event = function(obj, name){
5951 this.listeners = [];
5954 Roo.util.Event.prototype = {
5955 addListener : function(fn, scope, options){
5956 var o = options || {};
5957 scope = scope || this.obj;
5958 if(!this.isListening(fn, scope)){
5959 var l = {fn: fn, scope: scope, options: o};
5962 h = createDelayed(h, o, scope);
5965 h = createSingle(h, this, fn, scope);
5968 h = createBuffered(h, o, scope);
5971 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5972 this.listeners.push(l);
5974 this.listeners = this.listeners.slice(0);
5975 this.listeners.push(l);
5980 findListener : function(fn, scope){
5981 scope = scope || this.obj;
5982 var ls = this.listeners;
5983 for(var i = 0, len = ls.length; i < len; i++){
5985 if(l.fn == fn && l.scope == scope){
5992 isListening : function(fn, scope){
5993 return this.findListener(fn, scope) != -1;
5996 removeListener : function(fn, scope){
5998 if((index = this.findListener(fn, scope)) != -1){
6000 this.listeners.splice(index, 1);
6002 this.listeners = this.listeners.slice(0);
6003 this.listeners.splice(index, 1);
6010 clearListeners : function(){
6011 this.listeners = [];
6015 var ls = this.listeners, scope, len = ls.length;
6018 var args = Array.prototype.slice.call(arguments, 0);
6019 for(var i = 0; i < len; i++){
6021 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6022 this.firing = false;
6026 this.firing = false;
6033 * Ext JS Library 1.1.1
6034 * Copyright(c) 2006-2007, Ext JS, LLC.
6036 * Originally Released Under LGPL - original licence link has changed is not relivant.
6039 * <script type="text/javascript">
6043 * @class Roo.EventManager
6044 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6045 * several useful events directly.
6046 * See {@link Roo.EventObject} for more details on normalized event objects.
6049 Roo.EventManager = function(){
6050 var docReadyEvent, docReadyProcId, docReadyState = false;
6051 var resizeEvent, resizeTask, textEvent, textSize;
6052 var E = Roo.lib.Event;
6053 var D = Roo.lib.Dom;
6056 var fireDocReady = function(){
6058 docReadyState = true;
6061 clearInterval(docReadyProcId);
6063 if(Roo.isGecko || Roo.isOpera) {
6064 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6067 var defer = document.getElementById("ie-deferred-loader");
6069 defer.onreadystatechange = null;
6070 defer.parentNode.removeChild(defer);
6074 docReadyEvent.fire();
6075 docReadyEvent.clearListeners();
6080 var initDocReady = function(){
6081 docReadyEvent = new Roo.util.Event();
6082 if(Roo.isGecko || Roo.isOpera) {
6083 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6085 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6086 var defer = document.getElementById("ie-deferred-loader");
6087 defer.onreadystatechange = function(){
6088 if(this.readyState == "complete"){
6092 }else if(Roo.isSafari){
6093 docReadyProcId = setInterval(function(){
6094 var rs = document.readyState;
6095 if(rs == "complete") {
6100 // no matter what, make sure it fires on load
6101 E.on(window, "load", fireDocReady);
6104 var createBuffered = function(h, o){
6105 var task = new Roo.util.DelayedTask(h);
6107 // create new event object impl so new events don't wipe out properties
6108 e = new Roo.EventObjectImpl(e);
6109 task.delay(o.buffer, h, null, [e]);
6113 var createSingle = function(h, el, ename, fn){
6115 Roo.EventManager.removeListener(el, ename, fn);
6120 var createDelayed = function(h, o){
6122 // create new event object impl so new events don't wipe out properties
6123 e = new Roo.EventObjectImpl(e);
6124 setTimeout(function(){
6130 var listen = function(element, ename, opt, fn, scope){
6131 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6132 fn = fn || o.fn; scope = scope || o.scope;
6133 var el = Roo.getDom(element);
6135 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6137 var h = function(e){
6138 e = Roo.EventObject.setEvent(e);
6141 t = e.getTarget(o.delegate, el);
6148 if(o.stopEvent === true){
6151 if(o.preventDefault === true){
6154 if(o.stopPropagation === true){
6155 e.stopPropagation();
6158 if(o.normalized === false){
6162 fn.call(scope || el, e, t, o);
6165 h = createDelayed(h, o);
6168 h = createSingle(h, el, ename, fn);
6171 h = createBuffered(h, o);
6173 fn._handlers = fn._handlers || [];
6174 fn._handlers.push([Roo.id(el), ename, h]);
6177 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6178 el.addEventListener("DOMMouseScroll", h, false);
6179 E.on(window, 'unload', function(){
6180 el.removeEventListener("DOMMouseScroll", h, false);
6183 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6184 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6189 var stopListening = function(el, ename, fn){
6190 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6192 for(var i = 0, len = hds.length; i < len; i++){
6194 if(h[0] == id && h[1] == ename){
6201 E.un(el, ename, hd);
6202 el = Roo.getDom(el);
6203 if(ename == "mousewheel" && el.addEventListener){
6204 el.removeEventListener("DOMMouseScroll", hd, false);
6206 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6207 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6211 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6218 * @scope Roo.EventManager
6223 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6224 * object with a Roo.EventObject
6225 * @param {Function} fn The method the event invokes
6226 * @param {Object} scope An object that becomes the scope of the handler
6227 * @param {boolean} override If true, the obj passed in becomes
6228 * the execution scope of the listener
6229 * @return {Function} The wrapped function
6232 wrap : function(fn, scope, override){
6234 Roo.EventObject.setEvent(e);
6235 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6240 * Appends an event handler to an element (shorthand for addListener)
6241 * @param {String/HTMLElement} element The html element or id to assign the
6242 * @param {String} eventName The type of event to listen for
6243 * @param {Function} handler The method the event invokes
6244 * @param {Object} scope (optional) The scope in which to execute the handler
6245 * function. The handler function's "this" context.
6246 * @param {Object} options (optional) An object containing handler configuration
6247 * properties. This may contain any of the following properties:<ul>
6248 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6249 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6250 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6251 * <li>preventDefault {Boolean} True to prevent the default action</li>
6252 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6253 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6254 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6255 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6256 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6257 * by the specified number of milliseconds. If the event fires again within that time, the original
6258 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6261 * <b>Combining Options</b><br>
6262 * Using the options argument, it is possible to combine different types of listeners:<br>
6264 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6266 el.on('click', this.onClick, this, {
6273 * <b>Attaching multiple handlers in 1 call</b><br>
6274 * The method also allows for a single argument to be passed which is a config object containing properties
6275 * which specify multiple handlers.
6285 fn: this.onMouseOver
6294 * Or a shorthand syntax:<br>
6297 'click' : this.onClick,
6298 'mouseover' : this.onMouseOver,
6299 'mouseout' : this.onMouseOut
6303 addListener : function(element, eventName, fn, scope, options){
6304 if(typeof eventName == "object"){
6310 if(typeof o[e] == "function"){
6312 listen(element, e, o, o[e], o.scope);
6314 // individual options
6315 listen(element, e, o[e]);
6320 return listen(element, eventName, options, fn, scope);
6324 * Removes an event handler
6326 * @param {String/HTMLElement} element The id or html element to remove the
6328 * @param {String} eventName The type of event
6329 * @param {Function} fn
6330 * @return {Boolean} True if a listener was actually removed
6332 removeListener : function(element, eventName, fn){
6333 return stopListening(element, eventName, fn);
6337 * Fires when the document is ready (before onload and before images are loaded). Can be
6338 * accessed shorthanded Roo.onReady().
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 onDocumentReady : function(fn, scope, options){
6344 if(docReadyState){ // if it already fired
6345 docReadyEvent.addListener(fn, scope, options);
6346 docReadyEvent.fire();
6347 docReadyEvent.clearListeners();
6353 docReadyEvent.addListener(fn, scope, options);
6357 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6358 * @param {Function} fn The method the event invokes
6359 * @param {Object} scope An object that becomes the scope of the handler
6360 * @param {boolean} options
6362 onWindowResize : function(fn, scope, options){
6364 resizeEvent = new Roo.util.Event();
6365 resizeTask = new Roo.util.DelayedTask(function(){
6366 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 E.on(window, "resize", function(){
6370 resizeTask.delay(50);
6372 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6376 resizeEvent.addListener(fn, scope, options);
6380 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6381 * @param {Function} fn The method the event invokes
6382 * @param {Object} scope An object that becomes the scope of the handler
6383 * @param {boolean} options
6385 onTextResize : function(fn, scope, options){
6387 textEvent = new Roo.util.Event();
6388 var textEl = new Roo.Element(document.createElement('div'));
6389 textEl.dom.className = 'x-text-resize';
6390 textEl.dom.innerHTML = 'X';
6391 textEl.appendTo(document.body);
6392 textSize = textEl.dom.offsetHeight;
6393 setInterval(function(){
6394 if(textEl.dom.offsetHeight != textSize){
6395 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6397 }, this.textResizeInterval);
6399 textEvent.addListener(fn, scope, options);
6403 * Removes the passed window resize listener.
6404 * @param {Function} fn The method the event invokes
6405 * @param {Object} scope The scope of handler
6407 removeResizeListener : function(fn, scope){
6409 resizeEvent.removeListener(fn, scope);
6414 fireResize : function(){
6416 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6420 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6424 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6426 textResizeInterval : 50
6431 * @scopeAlias pub=Roo.EventManager
6435 * Appends an event handler to an element (shorthand for addListener)
6436 * @param {String/HTMLElement} element The html element or id to assign the
6437 * @param {String} eventName The type of event to listen for
6438 * @param {Function} handler The method the event invokes
6439 * @param {Object} scope (optional) The scope in which to execute the handler
6440 * function. The handler function's "this" context.
6441 * @param {Object} options (optional) An object containing handler configuration
6442 * properties. This may contain any of the following properties:<ul>
6443 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6444 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6445 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6446 * <li>preventDefault {Boolean} True to prevent the default action</li>
6447 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6448 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6449 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6450 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6451 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6452 * by the specified number of milliseconds. If the event fires again within that time, the original
6453 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6456 * <b>Combining Options</b><br>
6457 * Using the options argument, it is possible to combine different types of listeners:<br>
6459 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6461 el.on('click', this.onClick, this, {
6468 * <b>Attaching multiple handlers in 1 call</b><br>
6469 * The method also allows for a single argument to be passed which is a config object containing properties
6470 * which specify multiple handlers.
6480 fn: this.onMouseOver
6489 * Or a shorthand syntax:<br>
6492 'click' : this.onClick,
6493 'mouseover' : this.onMouseOver,
6494 'mouseout' : this.onMouseOut
6498 pub.on = pub.addListener;
6499 pub.un = pub.removeListener;
6501 pub.stoppedMouseDownEvent = new Roo.util.Event();
6505 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6506 * @param {Function} fn The method the event invokes
6507 * @param {Object} scope An object that becomes the scope of the handler
6508 * @param {boolean} override If true, the obj passed in becomes
6509 * the execution scope of the listener
6513 Roo.onReady = Roo.EventManager.onDocumentReady;
6515 Roo.onReady(function(){
6516 var bd = Roo.get(document.body);
6521 : Roo.isGecko ? "roo-gecko"
6522 : Roo.isOpera ? "roo-opera"
6523 : Roo.isSafari ? "roo-safari" : ""];
6526 cls.push("roo-mac");
6529 cls.push("roo-linux");
6531 if(Roo.isBorderBox){
6532 cls.push('roo-border-box');
6534 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6535 var p = bd.dom.parentNode;
6537 p.className += ' roo-strict';
6540 bd.addClass(cls.join(' '));
6544 * @class Roo.EventObject
6545 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6546 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6549 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6551 var target = e.getTarget();
6554 var myDiv = Roo.get("myDiv");
6555 myDiv.on("click", handleClick);
6557 Roo.EventManager.on("myDiv", 'click', handleClick);
6558 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6562 Roo.EventObject = function(){
6564 var E = Roo.lib.Event;
6566 // safari keypress events for special keys return bad keycodes
6569 63235 : 39, // right
6572 63276 : 33, // page up
6573 63277 : 34, // page down
6574 63272 : 46, // delete
6579 // normalize button clicks
6580 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6581 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6583 Roo.EventObjectImpl = function(e){
6585 this.setEvent(e.browserEvent || e);
6588 Roo.EventObjectImpl.prototype = {
6590 * Used to fix doc tools.
6591 * @scope Roo.EventObject.prototype
6597 /** The normal browser event */
6598 browserEvent : null,
6599 /** The button pressed in a mouse event */
6601 /** True if the shift key was down during the event */
6603 /** True if the control key was down during the event */
6605 /** True if the alt key was down during the event */
6664 setEvent : function(e){
6665 if(e == this || (e && e.browserEvent)){ // already wrapped
6668 this.browserEvent = e;
6670 // normalize buttons
6671 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6672 if(e.type == 'click' && this.button == -1){
6676 this.shiftKey = e.shiftKey;
6677 // mac metaKey behaves like ctrlKey
6678 this.ctrlKey = e.ctrlKey || e.metaKey;
6679 this.altKey = e.altKey;
6680 // in getKey these will be normalized for the mac
6681 this.keyCode = e.keyCode;
6682 // keyup warnings on firefox.
6683 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6684 // cache the target for the delayed and or buffered events
6685 this.target = E.getTarget(e);
6687 this.xy = E.getXY(e);
6690 this.shiftKey = false;
6691 this.ctrlKey = false;
6692 this.altKey = false;
6702 * Stop the event (preventDefault and stopPropagation)
6704 stopEvent : function(){
6705 if(this.browserEvent){
6706 if(this.browserEvent.type == 'mousedown'){
6707 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6709 E.stopEvent(this.browserEvent);
6714 * Prevents the browsers default handling of the event.
6716 preventDefault : function(){
6717 if(this.browserEvent){
6718 E.preventDefault(this.browserEvent);
6723 isNavKeyPress : function(){
6724 var k = this.keyCode;
6725 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6726 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6729 isSpecialKey : function(){
6730 var k = this.keyCode;
6731 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6732 (k == 16) || (k == 17) ||
6733 (k >= 18 && k <= 20) ||
6734 (k >= 33 && k <= 35) ||
6735 (k >= 36 && k <= 39) ||
6736 (k >= 44 && k <= 45);
6739 * Cancels bubbling of the event.
6741 stopPropagation : function(){
6742 if(this.browserEvent){
6743 if(this.type == 'mousedown'){
6744 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6746 E.stopPropagation(this.browserEvent);
6751 * Gets the key code for the event.
6754 getCharCode : function(){
6755 return this.charCode || this.keyCode;
6759 * Returns a normalized keyCode for the event.
6760 * @return {Number} The key code
6762 getKey : function(){
6763 var k = this.keyCode || this.charCode;
6764 return Roo.isSafari ? (safariKeys[k] || k) : k;
6768 * Gets the x coordinate of the event.
6771 getPageX : function(){
6776 * Gets the y coordinate of the event.
6779 getPageY : function(){
6784 * Gets the time of the event.
6787 getTime : function(){
6788 if(this.browserEvent){
6789 return E.getTime(this.browserEvent);
6795 * Gets the page coordinates of the event.
6796 * @return {Array} The xy values like [x, y]
6803 * Gets the target for the event.
6804 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6805 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6806 search as a number or element (defaults to 10 || document.body)
6807 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6808 * @return {HTMLelement}
6810 getTarget : function(selector, maxDepth, returnEl){
6811 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6814 * Gets the related target.
6815 * @return {HTMLElement}
6817 getRelatedTarget : function(){
6818 if(this.browserEvent){
6819 return E.getRelatedTarget(this.browserEvent);
6825 * Normalizes mouse wheel delta across browsers
6826 * @return {Number} The delta
6828 getWheelDelta : function(){
6829 var e = this.browserEvent;
6831 if(e.wheelDelta){ /* IE/Opera. */
6832 delta = e.wheelDelta/120;
6833 }else if(e.detail){ /* Mozilla case. */
6834 delta = -e.detail/3;
6840 * Returns true if the control, meta, shift or alt key was pressed during this event.
6843 hasModifier : function(){
6844 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6848 * Returns true if the target of this event equals el or is a child of el
6849 * @param {String/HTMLElement/Element} el
6850 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6853 within : function(el, related){
6854 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6855 return t && Roo.fly(el).contains(t);
6858 getPoint : function(){
6859 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6863 return new Roo.EventObjectImpl();
6868 * Ext JS Library 1.1.1
6869 * Copyright(c) 2006-2007, Ext JS, LLC.
6871 * Originally Released Under LGPL - original licence link has changed is not relivant.
6874 * <script type="text/javascript">
6878 // was in Composite Element!??!?!
6881 var D = Roo.lib.Dom;
6882 var E = Roo.lib.Event;
6883 var A = Roo.lib.Anim;
6885 // local style camelizing for speed
6887 var camelRe = /(-[a-z])/gi;
6888 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6889 var view = document.defaultView;
6892 * @class Roo.Element
6893 * Represents an Element in the DOM.<br><br>
6896 var el = Roo.get("my-div");
6899 var el = getEl("my-div");
6901 // or with a DOM element
6902 var el = Roo.get(myDivElement);
6904 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6905 * each call instead of constructing a new one.<br><br>
6906 * <b>Animations</b><br />
6907 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6908 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6910 Option Default Description
6911 --------- -------- ---------------------------------------------
6912 duration .35 The duration of the animation in seconds
6913 easing easeOut The YUI easing method
6914 callback none A function to execute when the anim completes
6915 scope this The scope (this) of the callback function
6917 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6918 * manipulate the animation. Here's an example:
6920 var el = Roo.get("my-div");
6925 // default animation
6926 el.setWidth(100, true);
6928 // animation with some options set
6935 // using the "anim" property to get the Anim object
6941 el.setWidth(100, opt);
6943 if(opt.anim.isAnimated()){
6947 * <b> Composite (Collections of) Elements</b><br />
6948 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6949 * @constructor Create a new Element directly.
6950 * @param {String/HTMLElement} element
6951 * @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).
6953 Roo.Element = function(element, forceNew){
6954 var dom = typeof element == "string" ?
6955 document.getElementById(element) : element;
6956 if(!dom){ // invalid id/element
6960 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6961 return Roo.Element.cache[id];
6971 * The DOM element ID
6974 this.id = id || Roo.id(dom);
6977 var El = Roo.Element;
6981 * The element's default display mode (defaults to "")
6984 originalDisplay : "",
6988 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6993 * Sets the element's visibility mode. When setVisible() is called it
6994 * will use this to determine whether to set the visibility or the display property.
6995 * @param visMode Element.VISIBILITY or Element.DISPLAY
6996 * @return {Roo.Element} this
6998 setVisibilityMode : function(visMode){
6999 this.visibilityMode = visMode;
7003 * Convenience method for setVisibilityMode(Element.DISPLAY)
7004 * @param {String} display (optional) What to set display to when visible
7005 * @return {Roo.Element} this
7007 enableDisplayMode : function(display){
7008 this.setVisibilityMode(El.DISPLAY);
7009 if(typeof display != "undefined") this.originalDisplay = display;
7014 * 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)
7015 * @param {String} selector The simple selector to test
7016 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7017 search as a number or element (defaults to 10 || document.body)
7018 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7019 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7021 findParent : function(simpleSelector, maxDepth, returnEl){
7022 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7023 maxDepth = maxDepth || 50;
7024 if(typeof maxDepth != "number"){
7025 stopEl = Roo.getDom(maxDepth);
7028 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7029 if(dq.is(p, simpleSelector)){
7030 return returnEl ? Roo.get(p) : p;
7040 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7041 * @param {String} selector The simple selector to test
7042 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7043 search as a number or element (defaults to 10 || document.body)
7044 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7045 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7047 findParentNode : function(simpleSelector, maxDepth, returnEl){
7048 var p = Roo.fly(this.dom.parentNode, '_internal');
7049 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7053 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7054 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7055 * @param {String} selector The simple selector to test
7056 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7057 search as a number or element (defaults to 10 || document.body)
7058 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7060 up : function(simpleSelector, maxDepth){
7061 return this.findParentNode(simpleSelector, maxDepth, true);
7067 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7068 * @param {String} selector The simple selector to test
7069 * @return {Boolean} True if this element matches the selector, else false
7071 is : function(simpleSelector){
7072 return Roo.DomQuery.is(this.dom, simpleSelector);
7076 * Perform animation on this element.
7077 * @param {Object} args The YUI animation control args
7078 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7079 * @param {Function} onComplete (optional) Function to call when animation completes
7080 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7081 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7082 * @return {Roo.Element} this
7084 animate : function(args, duration, onComplete, easing, animType){
7085 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7090 * @private Internal animation call
7092 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7093 animType = animType || 'run';
7095 var anim = Roo.lib.Anim[animType](
7097 (opt.duration || defaultDur) || .35,
7098 (opt.easing || defaultEase) || 'easeOut',
7100 Roo.callback(cb, this);
7101 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7109 // private legacy anim prep
7110 preanim : function(a, i){
7111 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7115 * Removes worthless text nodes
7116 * @param {Boolean} forceReclean (optional) By default the element
7117 * keeps track if it has been cleaned already so
7118 * you can call this over and over. However, if you update the element and
7119 * need to force a reclean, you can pass true.
7121 clean : function(forceReclean){
7122 if(this.isCleaned && forceReclean !== true){
7126 var d = this.dom, n = d.firstChild, ni = -1;
7128 var nx = n.nextSibling;
7129 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7136 this.isCleaned = true;
7141 calcOffsetsTo : function(el){
7144 var restorePos = false;
7145 if(el.getStyle('position') == 'static'){
7146 el.position('relative');
7151 while(op && op != d && op.tagName != 'HTML'){
7154 op = op.offsetParent;
7157 el.position('static');
7163 * Scrolls this element into view within the passed container.
7164 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7165 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7166 * @return {Roo.Element} this
7168 scrollIntoView : function(container, hscroll){
7169 var c = Roo.getDom(container) || document.body;
7172 var o = this.calcOffsetsTo(c),
7175 b = t+el.offsetHeight,
7176 r = l+el.offsetWidth;
7178 var ch = c.clientHeight;
7179 var ct = parseInt(c.scrollTop, 10);
7180 var cl = parseInt(c.scrollLeft, 10);
7182 var cr = cl + c.clientWidth;
7190 if(hscroll !== false){
7194 c.scrollLeft = r-c.clientWidth;
7201 scrollChildIntoView : function(child, hscroll){
7202 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7206 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7207 * the new height may not be available immediately.
7208 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7209 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7210 * @param {Function} onComplete (optional) Function to call when animation completes
7211 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7212 * @return {Roo.Element} this
7214 autoHeight : function(animate, duration, onComplete, easing){
7215 var oldHeight = this.getHeight();
7217 this.setHeight(1); // force clipping
7218 setTimeout(function(){
7219 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7221 this.setHeight(height);
7223 if(typeof onComplete == "function"){
7227 this.setHeight(oldHeight); // restore original height
7228 this.setHeight(height, animate, duration, function(){
7230 if(typeof onComplete == "function") onComplete();
7231 }.createDelegate(this), easing);
7233 }.createDelegate(this), 0);
7238 * Returns true if this element is an ancestor of the passed element
7239 * @param {HTMLElement/String} el The element to check
7240 * @return {Boolean} True if this element is an ancestor of el, else false
7242 contains : function(el){
7243 if(!el){return false;}
7244 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7248 * Checks whether the element is currently visible using both visibility and display properties.
7249 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7250 * @return {Boolean} True if the element is currently visible, else false
7252 isVisible : function(deep) {
7253 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7254 if(deep !== true || !vis){
7257 var p = this.dom.parentNode;
7258 while(p && p.tagName.toLowerCase() != "body"){
7259 if(!Roo.fly(p, '_isVisible').isVisible()){
7268 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7269 * @param {String} selector The CSS selector
7270 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7271 * @return {CompositeElement/CompositeElementLite} The composite element
7273 select : function(selector, unique){
7274 return El.select(selector, unique, this.dom);
7278 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7279 * @param {String} selector The CSS selector
7280 * @return {Array} An array of the matched nodes
7282 query : function(selector, unique){
7283 return Roo.DomQuery.select(selector, this.dom);
7287 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7288 * @param {String} selector The CSS selector
7289 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7290 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7292 child : function(selector, returnDom){
7293 var n = Roo.DomQuery.selectNode(selector, this.dom);
7294 return returnDom ? n : Roo.get(n);
7298 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7299 * @param {String} selector The CSS selector
7300 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7301 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7303 down : function(selector, returnDom){
7304 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7305 return returnDom ? n : Roo.get(n);
7309 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7310 * @param {String} group The group the DD object is member of
7311 * @param {Object} config The DD config object
7312 * @param {Object} overrides An object containing methods to override/implement on the DD object
7313 * @return {Roo.dd.DD} The DD object
7315 initDD : function(group, config, overrides){
7316 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7317 return Roo.apply(dd, overrides);
7321 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7322 * @param {String} group The group the DDProxy object is member of
7323 * @param {Object} config The DDProxy config object
7324 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7325 * @return {Roo.dd.DDProxy} The DDProxy object
7327 initDDProxy : function(group, config, overrides){
7328 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7329 return Roo.apply(dd, overrides);
7333 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7334 * @param {String} group The group the DDTarget object is member of
7335 * @param {Object} config The DDTarget config object
7336 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7337 * @return {Roo.dd.DDTarget} The DDTarget object
7339 initDDTarget : function(group, config, overrides){
7340 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7341 return Roo.apply(dd, overrides);
7345 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7346 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7347 * @param {Boolean} visible Whether the element is visible
7348 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7349 * @return {Roo.Element} this
7351 setVisible : function(visible, animate){
7353 if(this.visibilityMode == El.DISPLAY){
7354 this.setDisplayed(visible);
7357 this.dom.style.visibility = visible ? "visible" : "hidden";
7360 // closure for composites
7362 var visMode = this.visibilityMode;
7364 this.setOpacity(.01);
7365 this.setVisible(true);
7367 this.anim({opacity: { to: (visible?1:0) }},
7368 this.preanim(arguments, 1),
7369 null, .35, 'easeIn', function(){
7371 if(visMode == El.DISPLAY){
7372 dom.style.display = "none";
7374 dom.style.visibility = "hidden";
7376 Roo.get(dom).setOpacity(1);
7384 * Returns true if display is not "none"
7387 isDisplayed : function() {
7388 return this.getStyle("display") != "none";
7392 * Toggles the element's visibility or display, depending on visibility mode.
7393 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7394 * @return {Roo.Element} this
7396 toggle : function(animate){
7397 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7402 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7403 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7404 * @return {Roo.Element} this
7406 setDisplayed : function(value) {
7407 if(typeof value == "boolean"){
7408 value = value ? this.originalDisplay : "none";
7410 this.setStyle("display", value);
7415 * Tries to focus the element. Any exceptions are caught and ignored.
7416 * @return {Roo.Element} this
7418 focus : function() {
7426 * Tries to blur the element. Any exceptions are caught and ignored.
7427 * @return {Roo.Element} this
7437 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7438 * @param {String/Array} className The CSS class to add, or an array of classes
7439 * @return {Roo.Element} this
7441 addClass : function(className){
7442 if(className instanceof Array){
7443 for(var i = 0, len = className.length; i < len; i++) {
7444 this.addClass(className[i]);
7447 if(className && !this.hasClass(className)){
7448 this.dom.className = this.dom.className + " " + className;
7455 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7456 * @param {String/Array} className The CSS class to add, or an array of classes
7457 * @return {Roo.Element} this
7459 radioClass : function(className){
7460 var siblings = this.dom.parentNode.childNodes;
7461 for(var i = 0; i < siblings.length; i++) {
7462 var s = siblings[i];
7463 if(s.nodeType == 1){
7464 Roo.get(s).removeClass(className);
7467 this.addClass(className);
7472 * Removes one or more CSS classes from the element.
7473 * @param {String/Array} className The CSS class to remove, or an array of classes
7474 * @return {Roo.Element} this
7476 removeClass : function(className){
7477 if(!className || !this.dom.className){
7480 if(className instanceof Array){
7481 for(var i = 0, len = className.length; i < len; i++) {
7482 this.removeClass(className[i]);
7485 if(this.hasClass(className)){
7486 var re = this.classReCache[className];
7488 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7489 this.classReCache[className] = re;
7491 this.dom.className =
7492 this.dom.className.replace(re, " ");
7502 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7503 * @param {String} className The CSS class to toggle
7504 * @return {Roo.Element} this
7506 toggleClass : function(className){
7507 if(this.hasClass(className)){
7508 this.removeClass(className);
7510 this.addClass(className);
7516 * Checks if the specified CSS class exists on this element's DOM node.
7517 * @param {String} className The CSS class to check for
7518 * @return {Boolean} True if the class exists, else false
7520 hasClass : function(className){
7521 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7525 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7526 * @param {String} oldClassName The CSS class to replace
7527 * @param {String} newClassName The replacement CSS class
7528 * @return {Roo.Element} this
7530 replaceClass : function(oldClassName, newClassName){
7531 this.removeClass(oldClassName);
7532 this.addClass(newClassName);
7537 * Returns an object with properties matching the styles requested.
7538 * For example, el.getStyles('color', 'font-size', 'width') might return
7539 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7540 * @param {String} style1 A style name
7541 * @param {String} style2 A style name
7542 * @param {String} etc.
7543 * @return {Object} The style object
7545 getStyles : function(){
7546 var a = arguments, len = a.length, r = {};
7547 for(var i = 0; i < len; i++){
7548 r[a[i]] = this.getStyle(a[i]);
7554 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7555 * @param {String} property The style property whose value is returned.
7556 * @return {String} The current value of the style property for this element.
7558 getStyle : function(){
7559 return view && view.getComputedStyle ?
7561 var el = this.dom, v, cs, camel;
7562 if(prop == 'float'){
7565 if(el.style && (v = el.style[prop])){
7568 if(cs = view.getComputedStyle(el, "")){
7569 if(!(camel = propCache[prop])){
7570 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7577 var el = this.dom, v, cs, camel;
7578 if(prop == 'opacity'){
7579 if(typeof el.style.filter == 'string'){
7580 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7582 var fv = parseFloat(m[1]);
7584 return fv ? fv / 100 : 0;
7589 }else if(prop == 'float'){
7590 prop = "styleFloat";
7592 if(!(camel = propCache[prop])){
7593 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7595 if(v = el.style[camel]){
7598 if(cs = el.currentStyle){
7606 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7607 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7608 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7609 * @return {Roo.Element} this
7611 setStyle : function(prop, value){
7612 if(typeof prop == "string"){
7614 if (prop == 'float') {
7615 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7620 if(!(camel = propCache[prop])){
7621 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7624 if(camel == 'opacity') {
7625 this.setOpacity(value);
7627 this.dom.style[camel] = value;
7630 for(var style in prop){
7631 if(typeof prop[style] != "function"){
7632 this.setStyle(style, prop[style]);
7640 * More flexible version of {@link #setStyle} for setting style properties.
7641 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7642 * a function which returns such a specification.
7643 * @return {Roo.Element} this
7645 applyStyles : function(style){
7646 Roo.DomHelper.applyStyles(this.dom, style);
7651 * 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).
7652 * @return {Number} The X position of the element
7655 return D.getX(this.dom);
7659 * 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).
7660 * @return {Number} The Y position of the element
7663 return D.getY(this.dom);
7667 * 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).
7668 * @return {Array} The XY position of the element
7671 return D.getXY(this.dom);
7675 * 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).
7676 * @param {Number} The X position of the element
7677 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7678 * @return {Roo.Element} this
7680 setX : function(x, animate){
7682 D.setX(this.dom, x);
7684 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7690 * 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).
7691 * @param {Number} The Y position of the element
7692 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7693 * @return {Roo.Element} this
7695 setY : function(y, animate){
7697 D.setY(this.dom, y);
7699 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7705 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7706 * @param {String} left The left CSS property value
7707 * @return {Roo.Element} this
7709 setLeft : function(left){
7710 this.setStyle("left", this.addUnits(left));
7715 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7716 * @param {String} top The top CSS property value
7717 * @return {Roo.Element} this
7719 setTop : function(top){
7720 this.setStyle("top", this.addUnits(top));
7725 * Sets the element's CSS right style.
7726 * @param {String} right The right CSS property value
7727 * @return {Roo.Element} this
7729 setRight : function(right){
7730 this.setStyle("right", this.addUnits(right));
7735 * Sets the element's CSS bottom style.
7736 * @param {String} bottom The bottom CSS property value
7737 * @return {Roo.Element} this
7739 setBottom : function(bottom){
7740 this.setStyle("bottom", this.addUnits(bottom));
7745 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7746 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7747 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7748 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7749 * @return {Roo.Element} this
7751 setXY : function(pos, animate){
7753 D.setXY(this.dom, pos);
7755 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7761 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7762 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7763 * @param {Number} x X value for new position (coordinates are page-based)
7764 * @param {Number} y Y value for new position (coordinates are page-based)
7765 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7766 * @return {Roo.Element} this
7768 setLocation : function(x, y, animate){
7769 this.setXY([x, y], this.preanim(arguments, 2));
7774 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7775 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7776 * @param {Number} x X value for new position (coordinates are page-based)
7777 * @param {Number} y Y value for new position (coordinates are page-based)
7778 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7779 * @return {Roo.Element} this
7781 moveTo : function(x, y, animate){
7782 this.setXY([x, y], this.preanim(arguments, 2));
7787 * Returns the region of the given element.
7788 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7789 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7791 getRegion : function(){
7792 return D.getRegion(this.dom);
7796 * Returns the offset height of the element
7797 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7798 * @return {Number} The element's height
7800 getHeight : function(contentHeight){
7801 var h = this.dom.offsetHeight || 0;
7802 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7806 * Returns the offset width of the element
7807 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7808 * @return {Number} The element's width
7810 getWidth : function(contentWidth){
7811 var w = this.dom.offsetWidth || 0;
7812 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7816 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7817 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7818 * if a height has not been set using CSS.
7821 getComputedHeight : function(){
7822 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7824 h = parseInt(this.getStyle('height'), 10) || 0;
7825 if(!this.isBorderBox()){
7826 h += this.getFrameWidth('tb');
7833 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7834 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7835 * if a width has not been set using CSS.
7838 getComputedWidth : function(){
7839 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7841 w = parseInt(this.getStyle('width'), 10) || 0;
7842 if(!this.isBorderBox()){
7843 w += this.getFrameWidth('lr');
7850 * Returns the size of the element.
7851 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7852 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7854 getSize : function(contentSize){
7855 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7859 * Returns the width and height of the viewport.
7860 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7862 getViewSize : function(){
7863 var d = this.dom, doc = document, aw = 0, ah = 0;
7864 if(d == doc || d == doc.body){
7865 return {width : D.getViewWidth(), height: D.getViewHeight()};
7868 width : d.clientWidth,
7869 height: d.clientHeight
7875 * Returns the value of the "value" attribute
7876 * @param {Boolean} asNumber true to parse the value as a number
7877 * @return {String/Number}
7879 getValue : function(asNumber){
7880 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7884 adjustWidth : function(width){
7885 if(typeof width == "number"){
7886 if(this.autoBoxAdjust && !this.isBorderBox()){
7887 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7897 adjustHeight : function(height){
7898 if(typeof height == "number"){
7899 if(this.autoBoxAdjust && !this.isBorderBox()){
7900 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7910 * Set the width of the element
7911 * @param {Number} width The new width
7912 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7913 * @return {Roo.Element} this
7915 setWidth : function(width, animate){
7916 width = this.adjustWidth(width);
7918 this.dom.style.width = this.addUnits(width);
7920 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7926 * Set the height of the element
7927 * @param {Number} height The new height
7928 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7929 * @return {Roo.Element} this
7931 setHeight : function(height, animate){
7932 height = this.adjustHeight(height);
7934 this.dom.style.height = this.addUnits(height);
7936 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7942 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7943 * @param {Number} width The new width
7944 * @param {Number} height The new height
7945 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7946 * @return {Roo.Element} this
7948 setSize : function(width, height, animate){
7949 if(typeof width == "object"){ // in case of object from getSize()
7950 height = width.height; width = width.width;
7952 width = this.adjustWidth(width); height = this.adjustHeight(height);
7954 this.dom.style.width = this.addUnits(width);
7955 this.dom.style.height = this.addUnits(height);
7957 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7963 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7964 * @param {Number} x X value for new position (coordinates are page-based)
7965 * @param {Number} y Y value for new position (coordinates are page-based)
7966 * @param {Number} width The new width
7967 * @param {Number} height The new height
7968 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7969 * @return {Roo.Element} this
7971 setBounds : function(x, y, width, height, animate){
7973 this.setSize(width, height);
7974 this.setLocation(x, y);
7976 width = this.adjustWidth(width); height = this.adjustHeight(height);
7977 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7978 this.preanim(arguments, 4), 'motion');
7984 * 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.
7985 * @param {Roo.lib.Region} region The region to fill
7986 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7987 * @return {Roo.Element} this
7989 setRegion : function(region, animate){
7990 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7995 * Appends an event handler
7997 * @param {String} eventName The type of event to append
7998 * @param {Function} fn The method the event invokes
7999 * @param {Object} scope (optional) The scope (this object) of the fn
8000 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8002 addListener : function(eventName, fn, scope, options){
8004 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8009 * Removes an event handler from this element
8010 * @param {String} eventName the type of event to remove
8011 * @param {Function} fn the method the event invokes
8012 * @return {Roo.Element} this
8014 removeListener : function(eventName, fn){
8015 Roo.EventManager.removeListener(this.dom, eventName, fn);
8020 * Removes all previous added listeners from this element
8021 * @return {Roo.Element} this
8023 removeAllListeners : function(){
8024 E.purgeElement(this.dom);
8028 relayEvent : function(eventName, observable){
8029 this.on(eventName, function(e){
8030 observable.fireEvent(eventName, e);
8035 * Set the opacity of the element
8036 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8037 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8038 * @return {Roo.Element} this
8040 setOpacity : function(opacity, animate){
8042 var s = this.dom.style;
8045 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8046 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8048 s.opacity = opacity;
8051 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8057 * Gets the left X coordinate
8058 * @param {Boolean} local True to get the local css position instead of page coordinate
8061 getLeft : function(local){
8065 return parseInt(this.getStyle("left"), 10) || 0;
8070 * Gets the right X coordinate of the element (element X position + element width)
8071 * @param {Boolean} local True to get the local css position instead of page coordinate
8074 getRight : function(local){
8076 return this.getX() + this.getWidth();
8078 return (this.getLeft(true) + this.getWidth()) || 0;
8083 * Gets the top Y coordinate
8084 * @param {Boolean} local True to get the local css position instead of page coordinate
8087 getTop : function(local) {
8091 return parseInt(this.getStyle("top"), 10) || 0;
8096 * Gets the bottom Y coordinate of the element (element Y position + element height)
8097 * @param {Boolean} local True to get the local css position instead of page coordinate
8100 getBottom : function(local){
8102 return this.getY() + this.getHeight();
8104 return (this.getTop(true) + this.getHeight()) || 0;
8109 * Initializes positioning on this element. If a desired position is not passed, it will make the
8110 * the element positioned relative IF it is not already positioned.
8111 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8112 * @param {Number} zIndex (optional) The zIndex to apply
8113 * @param {Number} x (optional) Set the page X position
8114 * @param {Number} y (optional) Set the page Y position
8116 position : function(pos, zIndex, x, y){
8118 if(this.getStyle('position') == 'static'){
8119 this.setStyle('position', 'relative');
8122 this.setStyle("position", pos);
8125 this.setStyle("z-index", zIndex);
8127 if(x !== undefined && y !== undefined){
8129 }else if(x !== undefined){
8131 }else if(y !== undefined){
8137 * Clear positioning back to the default when the document was loaded
8138 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8139 * @return {Roo.Element} this
8141 clearPositioning : function(value){
8149 "position" : "static"
8155 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8156 * snapshot before performing an update and then restoring the element.
8159 getPositioning : function(){
8160 var l = this.getStyle("left");
8161 var t = this.getStyle("top");
8163 "position" : this.getStyle("position"),
8165 "right" : l ? "" : this.getStyle("right"),
8167 "bottom" : t ? "" : this.getStyle("bottom"),
8168 "z-index" : this.getStyle("z-index")
8173 * Gets the width of the border(s) for the specified side(s)
8174 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8175 * passing lr would get the border (l)eft width + the border (r)ight width.
8176 * @return {Number} The width of the sides passed added together
8178 getBorderWidth : function(side){
8179 return this.addStyles(side, El.borders);
8183 * Gets the width of the padding(s) for the specified side(s)
8184 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8185 * passing lr would get the padding (l)eft + the padding (r)ight.
8186 * @return {Number} The padding of the sides passed added together
8188 getPadding : function(side){
8189 return this.addStyles(side, El.paddings);
8193 * Set positioning with an object returned by getPositioning().
8194 * @param {Object} posCfg
8195 * @return {Roo.Element} this
8197 setPositioning : function(pc){
8198 this.applyStyles(pc);
8199 if(pc.right == "auto"){
8200 this.dom.style.right = "";
8202 if(pc.bottom == "auto"){
8203 this.dom.style.bottom = "";
8209 fixDisplay : function(){
8210 if(this.getStyle("display") == "none"){
8211 this.setStyle("visibility", "hidden");
8212 this.setStyle("display", this.originalDisplay); // first try reverting to default
8213 if(this.getStyle("display") == "none"){ // if that fails, default to block
8214 this.setStyle("display", "block");
8220 * Quick set left and top adding default units
8221 * @param {String} left The left CSS property value
8222 * @param {String} top The top CSS property value
8223 * @return {Roo.Element} this
8225 setLeftTop : function(left, top){
8226 this.dom.style.left = this.addUnits(left);
8227 this.dom.style.top = this.addUnits(top);
8232 * Move this element relative to its current position.
8233 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8234 * @param {Number} distance How far to move the element in pixels
8235 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8236 * @return {Roo.Element} this
8238 move : function(direction, distance, animate){
8239 var xy = this.getXY();
8240 direction = direction.toLowerCase();
8244 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8248 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8253 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8258 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8265 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8266 * @return {Roo.Element} this
8269 if(!this.isClipped){
8270 this.isClipped = true;
8271 this.originalClip = {
8272 "o": this.getStyle("overflow"),
8273 "x": this.getStyle("overflow-x"),
8274 "y": this.getStyle("overflow-y")
8276 this.setStyle("overflow", "hidden");
8277 this.setStyle("overflow-x", "hidden");
8278 this.setStyle("overflow-y", "hidden");
8284 * Return clipping (overflow) to original clipping before clip() was called
8285 * @return {Roo.Element} this
8287 unclip : function(){
8289 this.isClipped = false;
8290 var o = this.originalClip;
8291 if(o.o){this.setStyle("overflow", o.o);}
8292 if(o.x){this.setStyle("overflow-x", o.x);}
8293 if(o.y){this.setStyle("overflow-y", o.y);}
8300 * Gets the x,y coordinates specified by the anchor position on the element.
8301 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8302 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8303 * {width: (target width), height: (target height)} (defaults to the element's current size)
8304 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8305 * @return {Array} [x, y] An array containing the element's x and y coordinates
8307 getAnchorXY : function(anchor, local, s){
8308 //Passing a different size is useful for pre-calculating anchors,
8309 //especially for anchored animations that change the el size.
8311 var w, h, vp = false;
8314 if(d == document.body || d == document){
8316 w = D.getViewWidth(); h = D.getViewHeight();
8318 w = this.getWidth(); h = this.getHeight();
8321 w = s.width; h = s.height;
8323 var x = 0, y = 0, r = Math.round;
8324 switch((anchor || "tl").toLowerCase()){
8366 var sc = this.getScroll();
8367 return [x + sc.left, y + sc.top];
8369 //Add the element's offset xy
8370 var o = this.getXY();
8371 return [x+o[0], y+o[1]];
8375 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8376 * supported position values.
8377 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8378 * @param {String} position The position to align to.
8379 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8380 * @return {Array} [x, y]
8382 getAlignToXY : function(el, p, o){
8386 throw "Element.alignTo with an element that doesn't exist";
8388 var c = false; //constrain to viewport
8389 var p1 = "", p2 = "";
8396 }else if(p.indexOf("-") == -1){
8399 p = p.toLowerCase();
8400 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8402 throw "Element.alignTo with an invalid alignment " + p;
8404 p1 = m[1]; p2 = m[2]; c = !!m[3];
8406 //Subtract the aligned el's internal xy from the target's offset xy
8407 //plus custom offset to get the aligned el's new offset xy
8408 var a1 = this.getAnchorXY(p1, true);
8409 var a2 = el.getAnchorXY(p2, false);
8410 var x = a2[0] - a1[0] + o[0];
8411 var y = a2[1] - a1[1] + o[1];
8413 //constrain the aligned el to viewport if necessary
8414 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8415 // 5px of margin for ie
8416 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8418 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8419 //perpendicular to the vp border, allow the aligned el to slide on that border,
8420 //otherwise swap the aligned el to the opposite border of the target.
8421 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8422 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8423 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8424 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8427 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8428 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8430 if((x+w) > dw + scrollX){
8431 x = swapX ? r.left-w : dw+scrollX-w;
8434 x = swapX ? r.right : scrollX;
8436 if((y+h) > dh + scrollY){
8437 y = swapY ? r.top-h : dh+scrollY-h;
8440 y = swapY ? r.bottom : scrollY;
8447 getConstrainToXY : function(){
8448 var os = {top:0, left:0, bottom:0, right: 0};
8450 return function(el, local, offsets, proposedXY){
8452 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8454 var vw, vh, vx = 0, vy = 0;
8455 if(el.dom == document.body || el.dom == document){
8456 vw = Roo.lib.Dom.getViewWidth();
8457 vh = Roo.lib.Dom.getViewHeight();
8459 vw = el.dom.clientWidth;
8460 vh = el.dom.clientHeight;
8462 var vxy = el.getXY();
8468 var s = el.getScroll();
8470 vx += offsets.left + s.left;
8471 vy += offsets.top + s.top;
8473 vw -= offsets.right;
8474 vh -= offsets.bottom;
8479 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8480 var x = xy[0], y = xy[1];
8481 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8483 // only move it if it needs it
8486 // first validate right/bottom
8495 // then make sure top/left isn't negative
8504 return moved ? [x, y] : false;
8509 adjustForConstraints : function(xy, parent, offsets){
8510 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8514 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8515 * document it aligns it to the viewport.
8516 * The position parameter is optional, and can be specified in any one of the following formats:
8518 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8519 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8520 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8521 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8522 * <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
8523 * element's anchor point, and the second value is used as the target's anchor point.</li>
8525 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8526 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8527 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8528 * that specified in order to enforce the viewport constraints.
8529 * Following are all of the supported anchor positions:
8532 ----- -----------------------------
8533 tl The top left corner (default)
8534 t The center of the top edge
8535 tr The top right corner
8536 l The center of the left edge
8537 c In the center of the element
8538 r The center of the right edge
8539 bl The bottom left corner
8540 b The center of the bottom edge
8541 br The bottom right corner
8545 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8546 el.alignTo("other-el");
8548 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8549 el.alignTo("other-el", "tr?");
8551 // align the bottom right corner of el with the center left edge of other-el
8552 el.alignTo("other-el", "br-l?");
8554 // align the center of el with the bottom left corner of other-el and
8555 // adjust the x position by -6 pixels (and the y position by 0)
8556 el.alignTo("other-el", "c-bl", [-6, 0]);
8558 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8559 * @param {String} position The position to align to.
8560 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8561 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8562 * @return {Roo.Element} this
8564 alignTo : function(element, position, offsets, animate){
8565 var xy = this.getAlignToXY(element, position, offsets);
8566 this.setXY(xy, this.preanim(arguments, 3));
8571 * Anchors an element to another element and realigns it when the window is resized.
8572 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8573 * @param {String} position The position to align to.
8574 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8575 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8576 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8577 * is a number, it is used as the buffer delay (defaults to 50ms).
8578 * @param {Function} callback The function to call after the animation finishes
8579 * @return {Roo.Element} this
8581 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8582 var action = function(){
8583 this.alignTo(el, alignment, offsets, animate);
8584 Roo.callback(callback, this);
8586 Roo.EventManager.onWindowResize(action, this);
8587 var tm = typeof monitorScroll;
8588 if(tm != 'undefined'){
8589 Roo.EventManager.on(window, 'scroll', action, this,
8590 {buffer: tm == 'number' ? monitorScroll : 50});
8592 action.call(this); // align immediately
8596 * Clears any opacity settings from this element. Required in some cases for IE.
8597 * @return {Roo.Element} this
8599 clearOpacity : function(){
8600 if (window.ActiveXObject) {
8601 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8602 this.dom.style.filter = "";
8605 this.dom.style.opacity = "";
8606 this.dom.style["-moz-opacity"] = "";
8607 this.dom.style["-khtml-opacity"] = "";
8613 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8614 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8615 * @return {Roo.Element} this
8617 hide : function(animate){
8618 this.setVisible(false, this.preanim(arguments, 0));
8623 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8624 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8625 * @return {Roo.Element} this
8627 show : function(animate){
8628 this.setVisible(true, this.preanim(arguments, 0));
8633 * @private Test if size has a unit, otherwise appends the default
8635 addUnits : function(size){
8636 return Roo.Element.addUnits(size, this.defaultUnit);
8640 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8641 * @return {Roo.Element} this
8643 beginMeasure : function(){
8645 if(el.offsetWidth || el.offsetHeight){
8646 return this; // offsets work already
8649 var p = this.dom, b = document.body; // start with this element
8650 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8651 var pe = Roo.get(p);
8652 if(pe.getStyle('display') == 'none'){
8653 changed.push({el: p, visibility: pe.getStyle("visibility")});
8654 p.style.visibility = "hidden";
8655 p.style.display = "block";
8659 this._measureChanged = changed;
8665 * Restores displays to before beginMeasure was called
8666 * @return {Roo.Element} this
8668 endMeasure : function(){
8669 var changed = this._measureChanged;
8671 for(var i = 0, len = changed.length; i < len; i++) {
8673 r.el.style.visibility = r.visibility;
8674 r.el.style.display = "none";
8676 this._measureChanged = null;
8682 * Update the innerHTML of this element, optionally searching for and processing scripts
8683 * @param {String} html The new HTML
8684 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8685 * @param {Function} callback For async script loading you can be noticed when the update completes
8686 * @return {Roo.Element} this
8688 update : function(html, loadScripts, callback){
8689 if(typeof html == "undefined"){
8692 if(loadScripts !== true){
8693 this.dom.innerHTML = html;
8694 if(typeof callback == "function"){
8702 html += '<span id="' + id + '"></span>';
8704 E.onAvailable(id, function(){
8705 var hd = document.getElementsByTagName("head")[0];
8706 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8707 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8708 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8711 while(match = re.exec(html)){
8712 var attrs = match[1];
8713 var srcMatch = attrs ? attrs.match(srcRe) : false;
8714 if(srcMatch && srcMatch[2]){
8715 var s = document.createElement("script");
8716 s.src = srcMatch[2];
8717 var typeMatch = attrs.match(typeRe);
8718 if(typeMatch && typeMatch[2]){
8719 s.type = typeMatch[2];
8722 }else if(match[2] && match[2].length > 0){
8723 if(window.execScript) {
8724 window.execScript(match[2]);
8732 window.eval(match[2]);
8736 var el = document.getElementById(id);
8737 if(el){el.parentNode.removeChild(el);}
8738 if(typeof callback == "function"){
8742 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8747 * Direct access to the UpdateManager update() method (takes the same parameters).
8748 * @param {String/Function} url The url for this request or a function to call to get the url
8749 * @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}
8750 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8751 * @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.
8752 * @return {Roo.Element} this
8755 var um = this.getUpdateManager();
8756 um.update.apply(um, arguments);
8761 * Gets this element's UpdateManager
8762 * @return {Roo.UpdateManager} The UpdateManager
8764 getUpdateManager : function(){
8765 if(!this.updateManager){
8766 this.updateManager = new Roo.UpdateManager(this);
8768 return this.updateManager;
8772 * Disables text selection for this element (normalized across browsers)
8773 * @return {Roo.Element} this
8775 unselectable : function(){
8776 this.dom.unselectable = "on";
8777 this.swallowEvent("selectstart", true);
8778 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8779 this.addClass("x-unselectable");
8784 * Calculates the x, y to center this element on the screen
8785 * @return {Array} The x, y values [x, y]
8787 getCenterXY : function(){
8788 return this.getAlignToXY(document, 'c-c');
8792 * Centers the Element in either the viewport, or another Element.
8793 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8795 center : function(centerIn){
8796 this.alignTo(centerIn || document, 'c-c');
8801 * Tests various css rules/browsers to determine if this element uses a border box
8804 isBorderBox : function(){
8805 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8809 * Return a box {x, y, width, height} that can be used to set another elements
8810 * size/location to match this element.
8811 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8812 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8813 * @return {Object} box An object in the format {x, y, width, height}
8815 getBox : function(contentBox, local){
8820 var left = parseInt(this.getStyle("left"), 10) || 0;
8821 var top = parseInt(this.getStyle("top"), 10) || 0;
8824 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8826 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8828 var l = this.getBorderWidth("l")+this.getPadding("l");
8829 var r = this.getBorderWidth("r")+this.getPadding("r");
8830 var t = this.getBorderWidth("t")+this.getPadding("t");
8831 var b = this.getBorderWidth("b")+this.getPadding("b");
8832 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)};
8834 bx.right = bx.x + bx.width;
8835 bx.bottom = bx.y + bx.height;
8840 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8841 for more information about the sides.
8842 * @param {String} sides
8845 getFrameWidth : function(sides, onlyContentBox){
8846 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8850 * 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.
8851 * @param {Object} box The box to fill {x, y, width, height}
8852 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8853 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8854 * @return {Roo.Element} this
8856 setBox : function(box, adjust, animate){
8857 var w = box.width, h = box.height;
8858 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8859 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8860 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8862 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8867 * Forces the browser to repaint this element
8868 * @return {Roo.Element} this
8870 repaint : function(){
8872 this.addClass("x-repaint");
8873 setTimeout(function(){
8874 Roo.get(dom).removeClass("x-repaint");
8880 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8881 * then it returns the calculated width of the sides (see getPadding)
8882 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8883 * @return {Object/Number}
8885 getMargins : function(side){
8888 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8889 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8890 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8891 right: parseInt(this.getStyle("margin-right"), 10) || 0
8894 return this.addStyles(side, El.margins);
8899 addStyles : function(sides, styles){
8901 for(var i = 0, len = sides.length; i < len; i++){
8902 v = this.getStyle(styles[sides.charAt(i)]);
8904 w = parseInt(v, 10);
8912 * Creates a proxy element of this element
8913 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8914 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8915 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8916 * @return {Roo.Element} The new proxy element
8918 createProxy : function(config, renderTo, matchBox){
8920 renderTo = Roo.getDom(renderTo);
8922 renderTo = document.body;
8924 config = typeof config == "object" ?
8925 config : {tag : "div", cls: config};
8926 var proxy = Roo.DomHelper.append(renderTo, config, true);
8928 proxy.setBox(this.getBox());
8934 * Puts a mask over this element to disable user interaction. Requires core.css.
8935 * This method can only be applied to elements which accept child nodes.
8936 * @param {String} msg (optional) A message to display in the mask
8937 * @param {String} msgCls (optional) A css class to apply to the msg element
8938 * @return {Element} The mask element
8940 mask : function(msg, msgCls)
8942 if(this.getStyle("position") == "static"){
8943 this.setStyle("position", "relative");
8946 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8948 this.addClass("x-masked");
8949 this._mask.setDisplayed(true);
8954 while (dom && dom.style) {
8955 if (!isNaN(parseInt(dom.style.zIndex))) {
8956 z = Math.max(z, parseInt(dom.style.zIndex));
8958 dom = dom.parentNode;
8960 // if we are masking the body - then it hides everything..
8961 if (this.dom == document.body) {
8963 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8964 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8967 if(typeof msg == 'string'){
8969 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8971 var mm = this._maskMsg;
8972 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8973 mm.dom.firstChild.innerHTML = msg;
8974 mm.setDisplayed(true);
8976 mm.setStyle('z-index', z + 102);
8978 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8979 this._mask.setHeight(this.getHeight());
8981 this._mask.setStyle('z-index', z + 100);
8987 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8988 * it is cached for reuse.
8990 unmask : function(removeEl){
8992 if(removeEl === true){
8993 this._mask.remove();
8996 this._maskMsg.remove();
8997 delete this._maskMsg;
9000 this._mask.setDisplayed(false);
9002 this._maskMsg.setDisplayed(false);
9006 this.removeClass("x-masked");
9010 * Returns true if this element is masked
9013 isMasked : function(){
9014 return this._mask && this._mask.isVisible();
9018 * Creates an iframe shim for this element to keep selects and other windowed objects from
9020 * @return {Roo.Element} The new shim element
9022 createShim : function(){
9023 var el = document.createElement('iframe');
9024 el.frameBorder = 'no';
9025 el.className = 'roo-shim';
9026 if(Roo.isIE && Roo.isSecure){
9027 el.src = Roo.SSL_SECURE_URL;
9029 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9030 shim.autoBoxAdjust = false;
9035 * Removes this element from the DOM and deletes it from the cache
9037 remove : function(){
9038 if(this.dom.parentNode){
9039 this.dom.parentNode.removeChild(this.dom);
9041 delete El.cache[this.dom.id];
9045 * Sets up event handlers to add and remove a css class when the mouse is over this element
9046 * @param {String} className
9047 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9048 * mouseout events for children elements
9049 * @return {Roo.Element} this
9051 addClassOnOver : function(className, preventFlicker){
9052 this.on("mouseover", function(){
9053 Roo.fly(this, '_internal').addClass(className);
9055 var removeFn = function(e){
9056 if(preventFlicker !== true || !e.within(this, true)){
9057 Roo.fly(this, '_internal').removeClass(className);
9060 this.on("mouseout", removeFn, this.dom);
9065 * Sets up event handlers to add and remove a css class when this element has the focus
9066 * @param {String} className
9067 * @return {Roo.Element} this
9069 addClassOnFocus : function(className){
9070 this.on("focus", function(){
9071 Roo.fly(this, '_internal').addClass(className);
9073 this.on("blur", function(){
9074 Roo.fly(this, '_internal').removeClass(className);
9079 * 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)
9080 * @param {String} className
9081 * @return {Roo.Element} this
9083 addClassOnClick : function(className){
9085 this.on("mousedown", function(){
9086 Roo.fly(dom, '_internal').addClass(className);
9087 var d = Roo.get(document);
9088 var fn = function(){
9089 Roo.fly(dom, '_internal').removeClass(className);
9090 d.removeListener("mouseup", fn);
9092 d.on("mouseup", fn);
9098 * Stops the specified event from bubbling and optionally prevents the default action
9099 * @param {String} eventName
9100 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9101 * @return {Roo.Element} this
9103 swallowEvent : function(eventName, preventDefault){
9104 var fn = function(e){
9105 e.stopPropagation();
9110 if(eventName instanceof Array){
9111 for(var i = 0, len = eventName.length; i < len; i++){
9112 this.on(eventName[i], fn);
9116 this.on(eventName, fn);
9123 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9126 * Sizes this element to its parent element's dimensions performing
9127 * neccessary box adjustments.
9128 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9129 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9130 * @return {Roo.Element} this
9132 fitToParent : function(monitorResize, targetParent) {
9133 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9134 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9135 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9138 var p = Roo.get(targetParent || this.dom.parentNode);
9139 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9140 if (monitorResize === true) {
9141 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9142 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9148 * Gets the next sibling, skipping text nodes
9149 * @return {HTMLElement} The next sibling or null
9151 getNextSibling : function(){
9152 var n = this.dom.nextSibling;
9153 while(n && n.nodeType != 1){
9160 * Gets the previous sibling, skipping text nodes
9161 * @return {HTMLElement} The previous sibling or null
9163 getPrevSibling : function(){
9164 var n = this.dom.previousSibling;
9165 while(n && n.nodeType != 1){
9166 n = n.previousSibling;
9173 * Appends the passed element(s) to this element
9174 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9175 * @return {Roo.Element} this
9177 appendChild: function(el){
9184 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9185 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9186 * automatically generated with the specified attributes.
9187 * @param {HTMLElement} insertBefore (optional) a child element of this element
9188 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9189 * @return {Roo.Element} The new child element
9191 createChild: function(config, insertBefore, returnDom){
9192 config = config || {tag:'div'};
9194 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9196 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9200 * Appends this element to the passed element
9201 * @param {String/HTMLElement/Element} el The new parent element
9202 * @return {Roo.Element} this
9204 appendTo: function(el){
9205 el = Roo.getDom(el);
9206 el.appendChild(this.dom);
9211 * Inserts this element before the passed element in the DOM
9212 * @param {String/HTMLElement/Element} el The element to insert before
9213 * @return {Roo.Element} this
9215 insertBefore: function(el){
9216 el = Roo.getDom(el);
9217 el.parentNode.insertBefore(this.dom, el);
9222 * Inserts this element after the passed element in the DOM
9223 * @param {String/HTMLElement/Element} el The element to insert after
9224 * @return {Roo.Element} this
9226 insertAfter: function(el){
9227 el = Roo.getDom(el);
9228 el.parentNode.insertBefore(this.dom, el.nextSibling);
9233 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9234 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9235 * @return {Roo.Element} The new child
9237 insertFirst: function(el, returnDom){
9239 if(typeof el == 'object' && !el.nodeType){ // dh config
9240 return this.createChild(el, this.dom.firstChild, returnDom);
9242 el = Roo.getDom(el);
9243 this.dom.insertBefore(el, this.dom.firstChild);
9244 return !returnDom ? Roo.get(el) : el;
9249 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9250 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9251 * @param {String} where (optional) 'before' or 'after' defaults to before
9252 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9253 * @return {Roo.Element} the inserted Element
9255 insertSibling: function(el, where, returnDom){
9256 where = where ? where.toLowerCase() : 'before';
9258 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9260 if(typeof el == 'object' && !el.nodeType){ // dh config
9261 if(where == 'after' && !this.dom.nextSibling){
9262 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9264 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9268 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9269 where == 'before' ? this.dom : this.dom.nextSibling);
9278 * Creates and wraps this element with another element
9279 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9280 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9281 * @return {HTMLElement/Element} The newly created wrapper element
9283 wrap: function(config, returnDom){
9285 config = {tag: "div"};
9287 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9288 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9293 * Replaces the passed element with this element
9294 * @param {String/HTMLElement/Element} el The element to replace
9295 * @return {Roo.Element} this
9297 replace: function(el){
9299 this.insertBefore(el);
9305 * Inserts an html fragment into this element
9306 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9307 * @param {String} html The HTML fragment
9308 * @param {Boolean} returnEl True to return an Roo.Element
9309 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9311 insertHtml : function(where, html, returnEl){
9312 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9313 return returnEl ? Roo.get(el) : el;
9317 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9318 * @param {Object} o The object with the attributes
9319 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9320 * @return {Roo.Element} this
9322 set : function(o, useSet){
9324 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9326 if(attr == "style" || typeof o[attr] == "function") continue;
9328 el.className = o["cls"];
9330 if(useSet) el.setAttribute(attr, o[attr]);
9331 else el[attr] = o[attr];
9335 Roo.DomHelper.applyStyles(el, o.style);
9341 * Convenience method for constructing a KeyMap
9342 * @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:
9343 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9344 * @param {Function} fn The function to call
9345 * @param {Object} scope (optional) The scope of the function
9346 * @return {Roo.KeyMap} The KeyMap created
9348 addKeyListener : function(key, fn, scope){
9350 if(typeof key != "object" || key instanceof Array){
9366 return new Roo.KeyMap(this, config);
9370 * Creates a KeyMap for this element
9371 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9372 * @return {Roo.KeyMap} The KeyMap created
9374 addKeyMap : function(config){
9375 return new Roo.KeyMap(this, config);
9379 * Returns true if this element is scrollable.
9382 isScrollable : function(){
9384 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9388 * 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().
9389 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9390 * @param {Number} value The new scroll value
9391 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9392 * @return {Element} this
9395 scrollTo : function(side, value, animate){
9396 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9398 this.dom[prop] = value;
9400 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9401 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9407 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9408 * within this element's scrollable range.
9409 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9410 * @param {Number} distance How far to scroll the element in pixels
9411 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9412 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9413 * was scrolled as far as it could go.
9415 scroll : function(direction, distance, animate){
9416 if(!this.isScrollable()){
9420 var l = el.scrollLeft, t = el.scrollTop;
9421 var w = el.scrollWidth, h = el.scrollHeight;
9422 var cw = el.clientWidth, ch = el.clientHeight;
9423 direction = direction.toLowerCase();
9424 var scrolled = false;
9425 var a = this.preanim(arguments, 2);
9430 var v = Math.min(l + distance, w-cw);
9431 this.scrollTo("left", v, a);
9438 var v = Math.max(l - distance, 0);
9439 this.scrollTo("left", v, a);
9447 var v = Math.max(t - distance, 0);
9448 this.scrollTo("top", v, a);
9456 var v = Math.min(t + distance, h-ch);
9457 this.scrollTo("top", v, a);
9466 * Translates the passed page coordinates into left/top css values for this element
9467 * @param {Number/Array} x The page x or an array containing [x, y]
9468 * @param {Number} y The page y
9469 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9471 translatePoints : function(x, y){
9472 if(typeof x == 'object' || x instanceof Array){
9475 var p = this.getStyle('position');
9476 var o = this.getXY();
9478 var l = parseInt(this.getStyle('left'), 10);
9479 var t = parseInt(this.getStyle('top'), 10);
9482 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9485 t = (p == "relative") ? 0 : this.dom.offsetTop;
9488 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9492 * Returns the current scroll position of the element.
9493 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9495 getScroll : function(){
9496 var d = this.dom, doc = document;
9497 if(d == doc || d == doc.body){
9498 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9499 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9500 return {left: l, top: t};
9502 return {left: d.scrollLeft, top: d.scrollTop};
9507 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9508 * are convert to standard 6 digit hex color.
9509 * @param {String} attr The css attribute
9510 * @param {String} defaultValue The default value to use when a valid color isn't found
9511 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9514 getColor : function(attr, defaultValue, prefix){
9515 var v = this.getStyle(attr);
9516 if(!v || v == "transparent" || v == "inherit") {
9517 return defaultValue;
9519 var color = typeof prefix == "undefined" ? "#" : prefix;
9520 if(v.substr(0, 4) == "rgb("){
9521 var rvs = v.slice(4, v.length -1).split(",");
9522 for(var i = 0; i < 3; i++){
9523 var h = parseInt(rvs[i]).toString(16);
9530 if(v.substr(0, 1) == "#"){
9532 for(var i = 1; i < 4; i++){
9533 var c = v.charAt(i);
9536 }else if(v.length == 7){
9537 color += v.substr(1);
9541 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9545 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9546 * gradient background, rounded corners and a 4-way shadow.
9547 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9548 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9549 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9550 * @return {Roo.Element} this
9552 boxWrap : function(cls){
9553 cls = cls || 'x-box';
9554 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9555 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9560 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9561 * @param {String} namespace The namespace in which to look for the attribute
9562 * @param {String} name The attribute name
9563 * @return {String} The attribute value
9565 getAttributeNS : Roo.isIE ? function(ns, name){
9567 var type = typeof d[ns+":"+name];
9568 if(type != 'undefined' && type != 'unknown'){
9569 return d[ns+":"+name];
9572 } : function(ns, name){
9574 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9579 * Sets or Returns the value the dom attribute value
9580 * @param {String} name The attribute name
9581 * @param {String} value (optional) The value to set the attribute to
9582 * @return {String} The attribute value
9584 attr : function(name){
9585 if (arguments.length > 1) {
9586 this.dom.setAttribute(name, arguments[1]);
9587 return arguments[1];
9589 if (!this.dom.hasAttribute(name)) {
9592 return this.dom.getAttribute(name);
9599 var ep = El.prototype;
9602 * Appends an event handler (Shorthand for addListener)
9603 * @param {String} eventName The type of event to append
9604 * @param {Function} fn The method the event invokes
9605 * @param {Object} scope (optional) The scope (this object) of the fn
9606 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9609 ep.on = ep.addListener;
9611 ep.mon = ep.addListener;
9614 * Removes an event handler from this element (shorthand for removeListener)
9615 * @param {String} eventName the type of event to remove
9616 * @param {Function} fn the method the event invokes
9617 * @return {Roo.Element} this
9620 ep.un = ep.removeListener;
9623 * true to automatically adjust width and height settings for box-model issues (default to true)
9625 ep.autoBoxAdjust = true;
9628 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9631 El.addUnits = function(v, defaultUnit){
9632 if(v === "" || v == "auto"){
9635 if(v === undefined){
9638 if(typeof v == "number" || !El.unitPattern.test(v)){
9639 return v + (defaultUnit || 'px');
9644 // special markup used throughout Roo when box wrapping elements
9645 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>';
9647 * Visibility mode constant - Use visibility to hide element
9653 * Visibility mode constant - Use display to hide element
9659 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9660 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9661 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9673 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9674 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9675 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9676 * @return {Element} The Element object
9679 El.get = function(el){
9681 if(!el){ return null; }
9682 if(typeof el == "string"){ // element id
9683 if(!(elm = document.getElementById(el))){
9686 if(ex = El.cache[el]){
9689 ex = El.cache[el] = new El(elm);
9692 }else if(el.tagName){ // dom element
9696 if(ex = El.cache[id]){
9699 ex = El.cache[id] = new El(el);
9702 }else if(el instanceof El){
9704 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9705 // catch case where it hasn't been appended
9706 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9709 }else if(el.isComposite){
9711 }else if(el instanceof Array){
9712 return El.select(el);
9713 }else if(el == document){
9714 // create a bogus element object representing the document object
9716 var f = function(){};
9717 f.prototype = El.prototype;
9719 docEl.dom = document;
9727 El.uncache = function(el){
9728 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9730 delete El.cache[a[i].id || a[i]];
9736 // Garbage collection - uncache elements/purge listeners on orphaned elements
9737 // so we don't hold a reference and cause the browser to retain them
9738 El.garbageCollect = function(){
9739 if(!Roo.enableGarbageCollector){
9740 clearInterval(El.collectorThread);
9743 for(var eid in El.cache){
9744 var el = El.cache[eid], d = el.dom;
9745 // -------------------------------------------------------
9746 // Determining what is garbage:
9747 // -------------------------------------------------------
9749 // dom node is null, definitely garbage
9750 // -------------------------------------------------------
9752 // no parentNode == direct orphan, definitely garbage
9753 // -------------------------------------------------------
9754 // !d.offsetParent && !document.getElementById(eid)
9755 // display none elements have no offsetParent so we will
9756 // also try to look it up by it's id. However, check
9757 // offsetParent first so we don't do unneeded lookups.
9758 // This enables collection of elements that are not orphans
9759 // directly, but somewhere up the line they have an orphan
9761 // -------------------------------------------------------
9762 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9763 delete El.cache[eid];
9764 if(d && Roo.enableListenerCollection){
9770 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9774 El.Flyweight = function(dom){
9777 El.Flyweight.prototype = El.prototype;
9779 El._flyweights = {};
9781 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9782 * the dom node can be overwritten by other code.
9783 * @param {String/HTMLElement} el The dom node or id
9784 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9785 * prevent conflicts (e.g. internally Roo uses "_internal")
9787 * @return {Element} The shared Element object
9789 El.fly = function(el, named){
9790 named = named || '_global';
9791 el = Roo.getDom(el);
9795 if(!El._flyweights[named]){
9796 El._flyweights[named] = new El.Flyweight();
9798 El._flyweights[named].dom = el;
9799 return El._flyweights[named];
9803 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9804 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9805 * Shorthand of {@link Roo.Element#get}
9806 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9807 * @return {Element} The Element object
9813 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9814 * the dom node can be overwritten by other code.
9815 * Shorthand of {@link Roo.Element#fly}
9816 * @param {String/HTMLElement} el The dom node or id
9817 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9818 * prevent conflicts (e.g. internally Roo uses "_internal")
9820 * @return {Element} The shared Element object
9826 // speedy lookup for elements never to box adjust
9827 var noBoxAdjust = Roo.isStrict ? {
9830 input:1, select:1, textarea:1
9832 if(Roo.isIE || Roo.isGecko){
9833 noBoxAdjust['button'] = 1;
9837 Roo.EventManager.on(window, 'unload', function(){
9839 delete El._flyweights;
9847 Roo.Element.selectorFunction = Roo.DomQuery.select;
9850 Roo.Element.select = function(selector, unique, root){
9852 if(typeof selector == "string"){
9853 els = Roo.Element.selectorFunction(selector, root);
9854 }else if(selector.length !== undefined){
9857 throw "Invalid selector";
9859 if(unique === true){
9860 return new Roo.CompositeElement(els);
9862 return new Roo.CompositeElementLite(els);
9866 * Selects elements based on the passed CSS selector to enable working on them as 1.
9867 * @param {String/Array} selector The CSS selector or an array of elements
9868 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9869 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9870 * @return {CompositeElementLite/CompositeElement}
9874 Roo.select = Roo.Element.select;
9891 * Ext JS Library 1.1.1
9892 * Copyright(c) 2006-2007, Ext JS, LLC.
9894 * Originally Released Under LGPL - original licence link has changed is not relivant.
9897 * <script type="text/javascript">
9902 //Notifies Element that fx methods are available
9903 Roo.enableFx = true;
9907 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9908 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9909 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9910 * Element effects to work.</p><br/>
9912 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9913 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9914 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9915 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9916 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9917 * expected results and should be done with care.</p><br/>
9919 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9920 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9923 ----- -----------------------------
9924 tl The top left corner
9925 t The center of the top edge
9926 tr The top right corner
9927 l The center of the left edge
9928 r The center of the right edge
9929 bl The bottom left corner
9930 b The center of the bottom edge
9931 br The bottom right corner
9933 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9934 * below are common options that can be passed to any Fx method.</b>
9935 * @cfg {Function} callback A function called when the effect is finished
9936 * @cfg {Object} scope The scope of the effect function
9937 * @cfg {String} easing A valid Easing value for the effect
9938 * @cfg {String} afterCls A css class to apply after the effect
9939 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9940 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9941 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9942 * effects that end with the element being visually hidden, ignored otherwise)
9943 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9944 * a function which returns such a specification that will be applied to the Element after the effect finishes
9945 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9946 * @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
9947 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9951 * Slides the element into view. An anchor point can be optionally passed to set the point of
9952 * origin for the slide effect. This function automatically handles wrapping the element with
9953 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9956 // default: slide the element in from the top
9959 // custom: slide the element in from the right with a 2-second duration
9960 el.slideIn('r', { duration: 2 });
9962 // common config options shown with default values
9968 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9969 * @param {Object} options (optional) Object literal with any of the Fx config options
9970 * @return {Roo.Element} The Element
9972 slideIn : function(anchor, o){
9973 var el = this.getFxEl();
9976 el.queueFx(o, function(){
9978 anchor = anchor || "t";
9980 // fix display to visibility
9983 // restore values after effect
9984 var r = this.getFxRestore();
9985 var b = this.getBox();
9986 // fixed size for slide
9990 var wrap = this.fxWrap(r.pos, o, "hidden");
9992 var st = this.dom.style;
9993 st.visibility = "visible";
9994 st.position = "absolute";
9996 // clear out temp styles after slide and unwrap
9997 var after = function(){
9998 el.fxUnwrap(wrap, r.pos, o);
10000 st.height = r.height;
10003 // time to calc the positions
10004 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10006 switch(anchor.toLowerCase()){
10008 wrap.setSize(b.width, 0);
10009 st.left = st.bottom = "0";
10013 wrap.setSize(0, b.height);
10014 st.right = st.top = "0";
10018 wrap.setSize(0, b.height);
10019 wrap.setX(b.right);
10020 st.left = st.top = "0";
10021 a = {width: bw, points: pt};
10024 wrap.setSize(b.width, 0);
10025 wrap.setY(b.bottom);
10026 st.left = st.top = "0";
10027 a = {height: bh, points: pt};
10030 wrap.setSize(0, 0);
10031 st.right = st.bottom = "0";
10032 a = {width: bw, height: bh};
10035 wrap.setSize(0, 0);
10036 wrap.setY(b.y+b.height);
10037 st.right = st.top = "0";
10038 a = {width: bw, height: bh, points: pt};
10041 wrap.setSize(0, 0);
10042 wrap.setXY([b.right, b.bottom]);
10043 st.left = st.top = "0";
10044 a = {width: bw, height: bh, points: pt};
10047 wrap.setSize(0, 0);
10048 wrap.setX(b.x+b.width);
10049 st.left = st.bottom = "0";
10050 a = {width: bw, height: bh, points: pt};
10053 this.dom.style.visibility = "visible";
10056 arguments.callee.anim = wrap.fxanim(a,
10066 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10067 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10068 * 'hidden') but block elements will still take up space in the document. The element must be removed
10069 * from the DOM using the 'remove' config option if desired. This function automatically handles
10070 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10073 // default: slide the element out to the top
10076 // custom: slide the element out to the right with a 2-second duration
10077 el.slideOut('r', { duration: 2 });
10079 // common config options shown with default values
10087 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10088 * @param {Object} options (optional) Object literal with any of the Fx config options
10089 * @return {Roo.Element} The Element
10091 slideOut : function(anchor, o){
10092 var el = this.getFxEl();
10095 el.queueFx(o, function(){
10097 anchor = anchor || "t";
10099 // restore values after effect
10100 var r = this.getFxRestore();
10102 var b = this.getBox();
10103 // fixed size for slide
10107 var wrap = this.fxWrap(r.pos, o, "visible");
10109 var st = this.dom.style;
10110 st.visibility = "visible";
10111 st.position = "absolute";
10115 var after = function(){
10117 el.setDisplayed(false);
10122 el.fxUnwrap(wrap, r.pos, o);
10124 st.width = r.width;
10125 st.height = r.height;
10130 var a, zero = {to: 0};
10131 switch(anchor.toLowerCase()){
10133 st.left = st.bottom = "0";
10134 a = {height: zero};
10137 st.right = st.top = "0";
10141 st.left = st.top = "0";
10142 a = {width: zero, points: {to:[b.right, b.y]}};
10145 st.left = st.top = "0";
10146 a = {height: zero, points: {to:[b.x, b.bottom]}};
10149 st.right = st.bottom = "0";
10150 a = {width: zero, height: zero};
10153 st.right = st.top = "0";
10154 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10157 st.left = st.top = "0";
10158 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10161 st.left = st.bottom = "0";
10162 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10166 arguments.callee.anim = wrap.fxanim(a,
10176 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10177 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10178 * The element must be removed from the DOM using the 'remove' config option if desired.
10184 // common config options shown with default values
10192 * @param {Object} options (optional) Object literal with any of the Fx config options
10193 * @return {Roo.Element} The Element
10195 puff : function(o){
10196 var el = this.getFxEl();
10199 el.queueFx(o, function(){
10200 this.clearOpacity();
10203 // restore values after effect
10204 var r = this.getFxRestore();
10205 var st = this.dom.style;
10207 var after = function(){
10209 el.setDisplayed(false);
10216 el.setPositioning(r.pos);
10217 st.width = r.width;
10218 st.height = r.height;
10223 var width = this.getWidth();
10224 var height = this.getHeight();
10226 arguments.callee.anim = this.fxanim({
10227 width : {to: this.adjustWidth(width * 2)},
10228 height : {to: this.adjustHeight(height * 2)},
10229 points : {by: [-(width * .5), -(height * .5)]},
10231 fontSize: {to:200, unit: "%"}
10242 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10243 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10244 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10250 // all config options shown with default values
10258 * @param {Object} options (optional) Object literal with any of the Fx config options
10259 * @return {Roo.Element} The Element
10261 switchOff : function(o){
10262 var el = this.getFxEl();
10265 el.queueFx(o, function(){
10266 this.clearOpacity();
10269 // restore values after effect
10270 var r = this.getFxRestore();
10271 var st = this.dom.style;
10273 var after = function(){
10275 el.setDisplayed(false);
10281 el.setPositioning(r.pos);
10282 st.width = r.width;
10283 st.height = r.height;
10288 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10289 this.clearOpacity();
10293 points:{by:[0, this.getHeight() * .5]}
10294 }, o, 'motion', 0.3, 'easeIn', after);
10295 }).defer(100, this);
10302 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10303 * changed using the "attr" config option) and then fading back to the original color. If no original
10304 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10307 // default: highlight background to yellow
10310 // custom: highlight foreground text to blue for 2 seconds
10311 el.highlight("0000ff", { attr: 'color', duration: 2 });
10313 // common config options shown with default values
10314 el.highlight("ffff9c", {
10315 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10316 endColor: (current color) or "ffffff",
10321 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10322 * @param {Object} options (optional) Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 highlight : function(color, o){
10326 var el = this.getFxEl();
10329 el.queueFx(o, function(){
10330 color = color || "ffff9c";
10331 attr = o.attr || "backgroundColor";
10333 this.clearOpacity();
10336 var origColor = this.getColor(attr);
10337 var restoreColor = this.dom.style[attr];
10338 endColor = (o.endColor || origColor) || "ffffff";
10340 var after = function(){
10341 el.dom.style[attr] = restoreColor;
10346 a[attr] = {from: color, to: endColor};
10347 arguments.callee.anim = this.fxanim(a,
10357 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10360 // default: a single light blue ripple
10363 // custom: 3 red ripples lasting 3 seconds total
10364 el.frame("ff0000", 3, { duration: 3 });
10366 // common config options shown with default values
10367 el.frame("C3DAF9", 1, {
10368 duration: 1 //duration of entire animation (not each individual ripple)
10369 // Note: Easing is not configurable and will be ignored if included
10372 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10373 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10374 * @param {Object} options (optional) Object literal with any of the Fx config options
10375 * @return {Roo.Element} The Element
10377 frame : function(color, count, o){
10378 var el = this.getFxEl();
10381 el.queueFx(o, function(){
10382 color = color || "#C3DAF9";
10383 if(color.length == 6){
10384 color = "#" + color;
10386 count = count || 1;
10387 duration = o.duration || 1;
10390 var b = this.getBox();
10391 var animFn = function(){
10392 var proxy = this.createProxy({
10395 visbility:"hidden",
10396 position:"absolute",
10397 "z-index":"35000", // yee haw
10398 border:"0px solid " + color
10401 var scale = Roo.isBorderBox ? 2 : 1;
10403 top:{from:b.y, to:b.y - 20},
10404 left:{from:b.x, to:b.x - 20},
10405 borderWidth:{from:0, to:10},
10406 opacity:{from:1, to:0},
10407 height:{from:b.height, to:(b.height + (20*scale))},
10408 width:{from:b.width, to:(b.width + (20*scale))}
10409 }, duration, function(){
10413 animFn.defer((duration/2)*1000, this);
10424 * Creates a pause before any subsequent queued effects begin. If there are
10425 * no effects queued after the pause it will have no effect.
10430 * @param {Number} seconds The length of time to pause (in seconds)
10431 * @return {Roo.Element} The Element
10433 pause : function(seconds){
10434 var el = this.getFxEl();
10437 el.queueFx(o, function(){
10438 setTimeout(function(){
10440 }, seconds * 1000);
10446 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade in from opacity 0 to 100%
10453 // custom: fade in from opacity 0 to 75% over 2 seconds
10454 el.fadeIn({ endOpacity: .75, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10463 * @param {Object} options (optional) Object literal with any of the Fx config options
10464 * @return {Roo.Element} The Element
10466 fadeIn : function(o){
10467 var el = this.getFxEl();
10469 el.queueFx(o, function(){
10470 this.setOpacity(0);
10472 this.dom.style.visibility = 'visible';
10473 var to = o.endOpacity || 1;
10474 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10475 o, null, .5, "easeOut", function(){
10477 this.clearOpacity();
10486 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10487 * using the "endOpacity" config option.
10490 // default: fade out from the element's current opacity to 0
10493 // custom: fade out from the element's current opacity to 25% over 2 seconds
10494 el.fadeOut({ endOpacity: .25, duration: 2});
10496 // common config options shown with default values
10498 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 fadeOut : function(o){
10509 var el = this.getFxEl();
10511 el.queueFx(o, function(){
10512 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10513 o, null, .5, "easeOut", function(){
10514 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10515 this.dom.style.display = "none";
10517 this.dom.style.visibility = "hidden";
10519 this.clearOpacity();
10527 * Animates the transition of an element's dimensions from a starting height/width
10528 * to an ending height/width.
10531 // change height and width to 100x100 pixels
10532 el.scale(100, 100);
10534 // common config options shown with default values. The height and width will default to
10535 // the element's existing values if passed as null.
10538 [element's height], {
10543 * @param {Number} width The new width (pass undefined to keep the original width)
10544 * @param {Number} height The new height (pass undefined to keep the original height)
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 scale : function(w, h, o){
10549 this.shift(Roo.apply({}, o, {
10557 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10558 * Any of these properties not specified in the config object will not be changed. This effect
10559 * requires that at least one new dimension, position or opacity setting must be passed in on
10560 * the config object in order for the function to have any effect.
10563 // slide the element horizontally to x position 200 while changing the height and opacity
10564 el.shift({ x: 200, height: 50, opacity: .8 });
10566 // common config options shown with default values.
10568 width: [element's width],
10569 height: [element's height],
10570 x: [element's x position],
10571 y: [element's y position],
10572 opacity: [element's opacity],
10577 * @param {Object} options Object literal with any of the Fx config options
10578 * @return {Roo.Element} The Element
10580 shift : function(o){
10581 var el = this.getFxEl();
10583 el.queueFx(o, function(){
10584 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10585 if(w !== undefined){
10586 a.width = {to: this.adjustWidth(w)};
10588 if(h !== undefined){
10589 a.height = {to: this.adjustHeight(h)};
10591 if(x !== undefined || y !== undefined){
10593 x !== undefined ? x : this.getX(),
10594 y !== undefined ? y : this.getY()
10597 if(op !== undefined){
10598 a.opacity = {to: op};
10600 if(o.xy !== undefined){
10601 a.points = {to: o.xy};
10603 arguments.callee.anim = this.fxanim(a,
10604 o, 'motion', .35, "easeOut", function(){
10612 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10613 * ending point of the effect.
10616 // default: slide the element downward while fading out
10619 // custom: slide the element out to the right with a 2-second duration
10620 el.ghost('r', { duration: 2 });
10622 // common config options shown with default values
10630 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10631 * @param {Object} options (optional) Object literal with any of the Fx config options
10632 * @return {Roo.Element} The Element
10634 ghost : function(anchor, o){
10635 var el = this.getFxEl();
10638 el.queueFx(o, function(){
10639 anchor = anchor || "b";
10641 // restore values after effect
10642 var r = this.getFxRestore();
10643 var w = this.getWidth(),
10644 h = this.getHeight();
10646 var st = this.dom.style;
10648 var after = function(){
10650 el.setDisplayed(false);
10656 el.setPositioning(r.pos);
10657 st.width = r.width;
10658 st.height = r.height;
10663 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10664 switch(anchor.toLowerCase()){
10691 arguments.callee.anim = this.fxanim(a,
10701 * Ensures that all effects queued after syncFx is called on the element are
10702 * run concurrently. This is the opposite of {@link #sequenceFx}.
10703 * @return {Roo.Element} The Element
10705 syncFx : function(){
10706 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10715 * Ensures that all effects queued after sequenceFx is called on the element are
10716 * run in sequence. This is the opposite of {@link #syncFx}.
10717 * @return {Roo.Element} The Element
10719 sequenceFx : function(){
10720 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10722 concurrent : false,
10729 nextFx : function(){
10730 var ef = this.fxQueue[0];
10737 * Returns true if the element has any effects actively running or queued, else returns false.
10738 * @return {Boolean} True if element has active effects, else false
10740 hasActiveFx : function(){
10741 return this.fxQueue && this.fxQueue[0];
10745 * Stops any running effects and clears the element's internal effects queue if it contains
10746 * any additional effects that haven't started yet.
10747 * @return {Roo.Element} The Element
10749 stopFx : function(){
10750 if(this.hasActiveFx()){
10751 var cur = this.fxQueue[0];
10752 if(cur && cur.anim && cur.anim.isAnimated()){
10753 this.fxQueue = [cur]; // clear out others
10754 cur.anim.stop(true);
10761 beforeFx : function(o){
10762 if(this.hasActiveFx() && !o.concurrent){
10773 * Returns true if the element is currently blocking so that no other effect can be queued
10774 * until this effect is finished, else returns false if blocking is not set. This is commonly
10775 * used to ensure that an effect initiated by a user action runs to completion prior to the
10776 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10777 * @return {Boolean} True if blocking, else false
10779 hasFxBlock : function(){
10780 var q = this.fxQueue;
10781 return q && q[0] && q[0].block;
10785 queueFx : function(o, fn){
10789 if(!this.hasFxBlock()){
10790 Roo.applyIf(o, this.fxDefaults);
10792 var run = this.beforeFx(o);
10793 fn.block = o.block;
10794 this.fxQueue.push(fn);
10806 fxWrap : function(pos, o, vis){
10808 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10811 wrapXY = this.getXY();
10813 var div = document.createElement("div");
10814 div.style.visibility = vis;
10815 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10816 wrap.setPositioning(pos);
10817 if(wrap.getStyle("position") == "static"){
10818 wrap.position("relative");
10820 this.clearPositioning('auto');
10822 wrap.dom.appendChild(this.dom);
10824 wrap.setXY(wrapXY);
10831 fxUnwrap : function(wrap, pos, o){
10832 this.clearPositioning();
10833 this.setPositioning(pos);
10835 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10841 getFxRestore : function(){
10842 var st = this.dom.style;
10843 return {pos: this.getPositioning(), width: st.width, height : st.height};
10847 afterFx : function(o){
10849 this.applyStyles(o.afterStyle);
10852 this.addClass(o.afterCls);
10854 if(o.remove === true){
10857 Roo.callback(o.callback, o.scope, [this]);
10859 this.fxQueue.shift();
10865 getFxEl : function(){ // support for composite element fx
10866 return Roo.get(this.dom);
10870 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10871 animType = animType || 'run';
10873 var anim = Roo.lib.Anim[animType](
10875 (opt.duration || defaultDur) || .35,
10876 (opt.easing || defaultEase) || 'easeOut',
10878 Roo.callback(cb, this);
10887 // backwords compat
10888 Roo.Fx.resize = Roo.Fx.scale;
10890 //When included, Roo.Fx is automatically applied to Element so that all basic
10891 //effects are available directly via the Element API
10892 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10894 * Ext JS Library 1.1.1
10895 * Copyright(c) 2006-2007, Ext JS, LLC.
10897 * Originally Released Under LGPL - original licence link has changed is not relivant.
10900 * <script type="text/javascript">
10905 * @class Roo.CompositeElement
10906 * Standard composite class. Creates a Roo.Element for every element in the collection.
10908 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10909 * actions will be performed on all the elements in this collection.</b>
10911 * All methods return <i>this</i> and can be chained.
10913 var els = Roo.select("#some-el div.some-class", true);
10914 // or select directly from an existing element
10915 var el = Roo.get('some-el');
10916 el.select('div.some-class', true);
10918 els.setWidth(100); // all elements become 100 width
10919 els.hide(true); // all elements fade out and hide
10921 els.setWidth(100).hide(true);
10924 Roo.CompositeElement = function(els){
10925 this.elements = [];
10926 this.addElements(els);
10928 Roo.CompositeElement.prototype = {
10930 addElements : function(els){
10931 if(!els) return this;
10932 if(typeof els == "string"){
10933 els = Roo.Element.selectorFunction(els);
10935 var yels = this.elements;
10936 var index = yels.length-1;
10937 for(var i = 0, len = els.length; i < len; i++) {
10938 yels[++index] = Roo.get(els[i]);
10944 * Clears this composite and adds the elements returned by the passed selector.
10945 * @param {String/Array} els A string CSS selector, an array of elements or an element
10946 * @return {CompositeElement} this
10948 fill : function(els){
10949 this.elements = [];
10955 * Filters this composite to only elements that match the passed selector.
10956 * @param {String} selector A string CSS selector
10957 * @return {CompositeElement} this
10959 filter : function(selector){
10961 this.each(function(el){
10962 if(el.is(selector)){
10963 els[els.length] = el.dom;
10970 invoke : function(fn, args){
10971 var els = this.elements;
10972 for(var i = 0, len = els.length; i < len; i++) {
10973 Roo.Element.prototype[fn].apply(els[i], args);
10978 * Adds elements to this composite.
10979 * @param {String/Array} els A string CSS selector, an array of elements or an element
10980 * @return {CompositeElement} this
10982 add : function(els){
10983 if(typeof els == "string"){
10984 this.addElements(Roo.Element.selectorFunction(els));
10985 }else if(els.length !== undefined){
10986 this.addElements(els);
10988 this.addElements([els]);
10993 * Calls the passed function passing (el, this, index) for each element in this composite.
10994 * @param {Function} fn The function to call
10995 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10996 * @return {CompositeElement} this
10998 each : function(fn, scope){
10999 var els = this.elements;
11000 for(var i = 0, len = els.length; i < len; i++){
11001 if(fn.call(scope || els[i], els[i], this, i) === false) {
11009 * Returns the Element object at the specified index
11010 * @param {Number} index
11011 * @return {Roo.Element}
11013 item : function(index){
11014 return this.elements[index] || null;
11018 * Returns the first Element
11019 * @return {Roo.Element}
11021 first : function(){
11022 return this.item(0);
11026 * Returns the last Element
11027 * @return {Roo.Element}
11030 return this.item(this.elements.length-1);
11034 * Returns the number of elements in this composite
11037 getCount : function(){
11038 return this.elements.length;
11042 * Returns true if this composite contains the passed element
11045 contains : function(el){
11046 return this.indexOf(el) !== -1;
11050 * Returns true if this composite contains the passed element
11053 indexOf : function(el){
11054 return this.elements.indexOf(Roo.get(el));
11059 * Removes the specified element(s).
11060 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11061 * or an array of any of those.
11062 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11063 * @return {CompositeElement} this
11065 removeElement : function(el, removeDom){
11066 if(el instanceof Array){
11067 for(var i = 0, len = el.length; i < len; i++){
11068 this.removeElement(el[i]);
11072 var index = typeof el == 'number' ? el : this.indexOf(el);
11075 var d = this.elements[index];
11079 d.parentNode.removeChild(d);
11082 this.elements.splice(index, 1);
11088 * Replaces the specified element with the passed element.
11089 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11091 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11092 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11093 * @return {CompositeElement} this
11095 replaceElement : function(el, replacement, domReplace){
11096 var index = typeof el == 'number' ? el : this.indexOf(el);
11099 this.elements[index].replaceWith(replacement);
11101 this.elements.splice(index, 1, Roo.get(replacement))
11108 * Removes all elements.
11110 clear : function(){
11111 this.elements = [];
11115 Roo.CompositeElement.createCall = function(proto, fnName){
11116 if(!proto[fnName]){
11117 proto[fnName] = function(){
11118 return this.invoke(fnName, arguments);
11122 for(var fnName in Roo.Element.prototype){
11123 if(typeof Roo.Element.prototype[fnName] == "function"){
11124 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11130 * Ext JS Library 1.1.1
11131 * Copyright(c) 2006-2007, Ext JS, LLC.
11133 * Originally Released Under LGPL - original licence link has changed is not relivant.
11136 * <script type="text/javascript">
11140 * @class Roo.CompositeElementLite
11141 * @extends Roo.CompositeElement
11142 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11144 var els = Roo.select("#some-el div.some-class");
11145 // or select directly from an existing element
11146 var el = Roo.get('some-el');
11147 el.select('div.some-class');
11149 els.setWidth(100); // all elements become 100 width
11150 els.hide(true); // all elements fade out and hide
11152 els.setWidth(100).hide(true);
11153 </code></pre><br><br>
11154 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11155 * actions will be performed on all the elements in this collection.</b>
11157 Roo.CompositeElementLite = function(els){
11158 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11159 this.el = new Roo.Element.Flyweight();
11161 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11162 addElements : function(els){
11164 if(els instanceof Array){
11165 this.elements = this.elements.concat(els);
11167 var yels = this.elements;
11168 var index = yels.length-1;
11169 for(var i = 0, len = els.length; i < len; i++) {
11170 yels[++index] = els[i];
11176 invoke : function(fn, args){
11177 var els = this.elements;
11179 for(var i = 0, len = els.length; i < len; i++) {
11181 Roo.Element.prototype[fn].apply(el, args);
11186 * Returns a flyweight Element of the dom element object at the specified index
11187 * @param {Number} index
11188 * @return {Roo.Element}
11190 item : function(index){
11191 if(!this.elements[index]){
11194 this.el.dom = this.elements[index];
11198 // fixes scope with flyweight
11199 addListener : function(eventName, handler, scope, opt){
11200 var els = this.elements;
11201 for(var i = 0, len = els.length; i < len; i++) {
11202 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11208 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11209 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11210 * a reference to the dom node, use el.dom.</b>
11211 * @param {Function} fn The function to call
11212 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11213 * @return {CompositeElement} this
11215 each : function(fn, scope){
11216 var els = this.elements;
11218 for(var i = 0, len = els.length; i < len; i++){
11220 if(fn.call(scope || el, el, this, i) === false){
11227 indexOf : function(el){
11228 return this.elements.indexOf(Roo.getDom(el));
11231 replaceElement : function(el, replacement, domReplace){
11232 var index = typeof el == 'number' ? el : this.indexOf(el);
11234 replacement = Roo.getDom(replacement);
11236 var d = this.elements[index];
11237 d.parentNode.insertBefore(replacement, d);
11238 d.parentNode.removeChild(d);
11240 this.elements.splice(index, 1, replacement);
11245 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11249 * Ext JS Library 1.1.1
11250 * Copyright(c) 2006-2007, Ext JS, LLC.
11252 * Originally Released Under LGPL - original licence link has changed is not relivant.
11255 * <script type="text/javascript">
11261 * @class Roo.data.Connection
11262 * @extends Roo.util.Observable
11263 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11264 * either to a configured URL, or to a URL specified at request time.<br><br>
11266 * Requests made by this class are asynchronous, and will return immediately. No data from
11267 * the server will be available to the statement immediately following the {@link #request} call.
11268 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11270 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11271 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11272 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11273 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11274 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11275 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11276 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11277 * standard DOM methods.
11279 * @param {Object} config a configuration object.
11281 Roo.data.Connection = function(config){
11282 Roo.apply(this, config);
11285 * @event beforerequest
11286 * Fires before a network request is made to retrieve a data object.
11287 * @param {Connection} conn This Connection object.
11288 * @param {Object} options The options config object passed to the {@link #request} method.
11290 "beforerequest" : true,
11292 * @event requestcomplete
11293 * Fires if the request was successfully completed.
11294 * @param {Connection} conn This Connection object.
11295 * @param {Object} response The XHR object containing the response data.
11296 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11297 * @param {Object} options The options config object passed to the {@link #request} method.
11299 "requestcomplete" : true,
11301 * @event requestexception
11302 * Fires if an error HTTP status was returned from the server.
11303 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11304 * @param {Connection} conn This Connection object.
11305 * @param {Object} response The XHR object containing the response data.
11306 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11307 * @param {Object} options The options config object passed to the {@link #request} method.
11309 "requestexception" : true
11311 Roo.data.Connection.superclass.constructor.call(this);
11314 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11316 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11319 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11320 * extra parameters to each request made by this object. (defaults to undefined)
11323 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11324 * to each request made by this object. (defaults to undefined)
11327 * @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)
11330 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11334 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11340 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11343 disableCaching: true,
11346 * Sends an HTTP request to a remote server.
11347 * @param {Object} options An object which may contain the following properties:<ul>
11348 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11349 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11350 * request, a url encoded string or a function to call to get either.</li>
11351 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11352 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11353 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11354 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11355 * <li>options {Object} The parameter to the request call.</li>
11356 * <li>success {Boolean} True if the request succeeded.</li>
11357 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11359 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11360 * The callback is passed the following parameters:<ul>
11361 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362 * <li>options {Object} The parameter to the request call.</li>
11364 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11365 * The callback is passed the following parameters:<ul>
11366 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11367 * <li>options {Object} The parameter to the request call.</li>
11369 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11370 * for the callback function. Defaults to the browser window.</li>
11371 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11372 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11373 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11374 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11375 * params for the post data. Any params will be appended to the URL.</li>
11376 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11378 * @return {Number} transactionId
11380 request : function(o){
11381 if(this.fireEvent("beforerequest", this, o) !== false){
11384 if(typeof p == "function"){
11385 p = p.call(o.scope||window, o);
11387 if(typeof p == "object"){
11388 p = Roo.urlEncode(o.params);
11390 if(this.extraParams){
11391 var extras = Roo.urlEncode(this.extraParams);
11392 p = p ? (p + '&' + extras) : extras;
11395 var url = o.url || this.url;
11396 if(typeof url == 'function'){
11397 url = url.call(o.scope||window, o);
11401 var form = Roo.getDom(o.form);
11402 url = url || form.action;
11404 var enctype = form.getAttribute("enctype");
11405 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11406 return this.doFormUpload(o, p, url);
11408 var f = Roo.lib.Ajax.serializeForm(form);
11409 p = p ? (p + '&' + f) : f;
11412 var hs = o.headers;
11413 if(this.defaultHeaders){
11414 hs = Roo.apply(hs || {}, this.defaultHeaders);
11421 success: this.handleResponse,
11422 failure: this.handleFailure,
11424 argument: {options: o},
11425 timeout : o.timeout || this.timeout
11428 var method = o.method||this.method||(p ? "POST" : "GET");
11430 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11431 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11434 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11438 }else if(this.autoAbort !== false){
11442 if((method == 'GET' && p) || o.xmlData){
11443 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11446 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11447 return this.transId;
11449 Roo.callback(o.callback, o.scope, [o, null, null]);
11455 * Determine whether this object has a request outstanding.
11456 * @param {Number} transactionId (Optional) defaults to the last transaction
11457 * @return {Boolean} True if there is an outstanding request.
11459 isLoading : function(transId){
11461 return Roo.lib.Ajax.isCallInProgress(transId);
11463 return this.transId ? true : false;
11468 * Aborts any outstanding request.
11469 * @param {Number} transactionId (Optional) defaults to the last transaction
11471 abort : function(transId){
11472 if(transId || this.isLoading()){
11473 Roo.lib.Ajax.abort(transId || this.transId);
11478 handleResponse : function(response){
11479 this.transId = false;
11480 var options = response.argument.options;
11481 response.argument = options ? options.argument : null;
11482 this.fireEvent("requestcomplete", this, response, options);
11483 Roo.callback(options.success, options.scope, [response, options]);
11484 Roo.callback(options.callback, options.scope, [options, true, response]);
11488 handleFailure : function(response, e){
11489 this.transId = false;
11490 var options = response.argument.options;
11491 response.argument = options ? options.argument : null;
11492 this.fireEvent("requestexception", this, response, options, e);
11493 Roo.callback(options.failure, options.scope, [response, options]);
11494 Roo.callback(options.callback, options.scope, [options, false, response]);
11498 doFormUpload : function(o, ps, url){
11500 var frame = document.createElement('iframe');
11503 frame.className = 'x-hidden';
11505 frame.src = Roo.SSL_SECURE_URL;
11507 document.body.appendChild(frame);
11510 document.frames[id].name = id;
11513 var form = Roo.getDom(o.form);
11515 form.method = 'POST';
11516 form.enctype = form.encoding = 'multipart/form-data';
11522 if(ps){ // add dynamic params
11524 ps = Roo.urlDecode(ps, false);
11526 if(ps.hasOwnProperty(k)){
11527 hd = document.createElement('input');
11528 hd.type = 'hidden';
11531 form.appendChild(hd);
11538 var r = { // bogus response object
11543 r.argument = o ? o.argument : null;
11548 doc = frame.contentWindow.document;
11550 doc = (frame.contentDocument || window.frames[id].document);
11552 if(doc && doc.body){
11553 r.responseText = doc.body.innerHTML;
11555 if(doc && doc.XMLDocument){
11556 r.responseXML = doc.XMLDocument;
11558 r.responseXML = doc;
11565 Roo.EventManager.removeListener(frame, 'load', cb, this);
11567 this.fireEvent("requestcomplete", this, r, o);
11568 Roo.callback(o.success, o.scope, [r, o]);
11569 Roo.callback(o.callback, o.scope, [o, true, r]);
11571 setTimeout(function(){document.body.removeChild(frame);}, 100);
11574 Roo.EventManager.on(frame, 'load', cb, this);
11577 if(hiddens){ // remove dynamic params
11578 for(var i = 0, len = hiddens.length; i < len; i++){
11579 form.removeChild(hiddens[i]);
11586 * Ext JS Library 1.1.1
11587 * Copyright(c) 2006-2007, Ext JS, LLC.
11589 * Originally Released Under LGPL - original licence link has changed is not relivant.
11592 * <script type="text/javascript">
11596 * Global Ajax request class.
11599 * @extends Roo.data.Connection
11602 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11603 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11604 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11605 * @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)
11606 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11607 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11608 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11610 Roo.Ajax = new Roo.data.Connection({
11619 * Serialize the passed form into a url encoded string
11621 * @param {String/HTMLElement} form
11624 serializeForm : function(form){
11625 return Roo.lib.Ajax.serializeForm(form);
11629 * Ext JS Library 1.1.1
11630 * Copyright(c) 2006-2007, Ext JS, LLC.
11632 * Originally Released Under LGPL - original licence link has changed is not relivant.
11635 * <script type="text/javascript">
11640 * @class Roo.UpdateManager
11641 * @extends Roo.util.Observable
11642 * Provides AJAX-style update for Element object.<br><br>
11645 * // Get it from a Roo.Element object
11646 * var el = Roo.get("foo");
11647 * var mgr = el.getUpdateManager();
11648 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11650 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11652 * // or directly (returns the same UpdateManager instance)
11653 * var mgr = new Roo.UpdateManager("myElementId");
11654 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11655 * mgr.on("update", myFcnNeedsToKnow);
11657 // short handed call directly from the element object
11658 Roo.get("foo").load({
11662 text: "Loading Foo..."
11666 * Create new UpdateManager directly.
11667 * @param {String/HTMLElement/Roo.Element} el The element to update
11668 * @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).
11670 Roo.UpdateManager = function(el, forceNew){
11672 if(!forceNew && el.updateManager){
11673 return el.updateManager;
11676 * The Element object
11677 * @type Roo.Element
11681 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11684 this.defaultUrl = null;
11688 * @event beforeupdate
11689 * Fired before an update is made, return false from your handler and the update is cancelled.
11690 * @param {Roo.Element} el
11691 * @param {String/Object/Function} url
11692 * @param {String/Object} params
11694 "beforeupdate": true,
11697 * Fired after successful update is made.
11698 * @param {Roo.Element} el
11699 * @param {Object} oResponseObject The response Object
11704 * Fired on update failure.
11705 * @param {Roo.Element} el
11706 * @param {Object} oResponseObject The response Object
11710 var d = Roo.UpdateManager.defaults;
11712 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11715 this.sslBlankUrl = d.sslBlankUrl;
11717 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11720 this.disableCaching = d.disableCaching;
11722 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11725 this.indicatorText = d.indicatorText;
11727 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11730 this.showLoadIndicator = d.showLoadIndicator;
11732 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11735 this.timeout = d.timeout;
11738 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11741 this.loadScripts = d.loadScripts;
11744 * Transaction object of current executing transaction
11746 this.transaction = null;
11751 this.autoRefreshProcId = null;
11753 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11756 this.refreshDelegate = this.refresh.createDelegate(this);
11758 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11761 this.updateDelegate = this.update.createDelegate(this);
11763 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11766 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11770 this.successDelegate = this.processSuccess.createDelegate(this);
11774 this.failureDelegate = this.processFailure.createDelegate(this);
11776 if(!this.renderer){
11778 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11780 this.renderer = new Roo.UpdateManager.BasicRenderer();
11783 Roo.UpdateManager.superclass.constructor.call(this);
11786 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11788 * Get the Element this UpdateManager is bound to
11789 * @return {Roo.Element} The element
11791 getEl : function(){
11795 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11796 * @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:
11799 url: "your-url.php",<br/>
11800 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11801 callback: yourFunction,<br/>
11802 scope: yourObject, //(optional scope) <br/>
11803 discardUrl: false, <br/>
11804 nocache: false,<br/>
11805 text: "Loading...",<br/>
11807 scripts: false<br/>
11810 * The only required property is url. The optional properties nocache, text and scripts
11811 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11812 * @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}
11813 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11814 * @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.
11816 update : function(url, params, callback, discardUrl){
11817 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11818 var method = this.method,
11820 if(typeof url == "object"){ // must be config object
11823 params = params || cfg.params;
11824 callback = callback || cfg.callback;
11825 discardUrl = discardUrl || cfg.discardUrl;
11826 if(callback && cfg.scope){
11827 callback = callback.createDelegate(cfg.scope);
11829 if(typeof cfg.method != "undefined"){method = cfg.method;};
11830 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11831 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11832 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11833 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11835 this.showLoading();
11837 this.defaultUrl = url;
11839 if(typeof url == "function"){
11840 url = url.call(this);
11843 method = method || (params ? "POST" : "GET");
11844 if(method == "GET"){
11845 url = this.prepareUrl(url);
11848 var o = Roo.apply(cfg ||{}, {
11851 success: this.successDelegate,
11852 failure: this.failureDelegate,
11853 callback: undefined,
11854 timeout: (this.timeout*1000),
11855 argument: {"url": url, "form": null, "callback": callback, "params": params}
11857 Roo.log("updated manager called with timeout of " + o.timeout);
11858 this.transaction = Roo.Ajax.request(o);
11863 * 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.
11864 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11865 * @param {String/HTMLElement} form The form Id or form element
11866 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11867 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11868 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11870 formUpdate : function(form, url, reset, callback){
11871 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11872 if(typeof url == "function"){
11873 url = url.call(this);
11875 form = Roo.getDom(form);
11876 this.transaction = Roo.Ajax.request({
11879 success: this.successDelegate,
11880 failure: this.failureDelegate,
11881 timeout: (this.timeout*1000),
11882 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11884 this.showLoading.defer(1, this);
11889 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11890 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11892 refresh : function(callback){
11893 if(this.defaultUrl == null){
11896 this.update(this.defaultUrl, null, callback, true);
11900 * Set this element to auto refresh.
11901 * @param {Number} interval How often to update (in seconds).
11902 * @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)
11903 * @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}
11904 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11905 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11907 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11909 this.update(url || this.defaultUrl, params, callback, true);
11911 if(this.autoRefreshProcId){
11912 clearInterval(this.autoRefreshProcId);
11914 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11918 * Stop auto refresh on this element.
11920 stopAutoRefresh : function(){
11921 if(this.autoRefreshProcId){
11922 clearInterval(this.autoRefreshProcId);
11923 delete this.autoRefreshProcId;
11927 isAutoRefreshing : function(){
11928 return this.autoRefreshProcId ? true : false;
11931 * Called to update the element to "Loading" state. Override to perform custom action.
11933 showLoading : function(){
11934 if(this.showLoadIndicator){
11935 this.el.update(this.indicatorText);
11940 * Adds unique parameter to query string if disableCaching = true
11943 prepareUrl : function(url){
11944 if(this.disableCaching){
11945 var append = "_dc=" + (new Date().getTime());
11946 if(url.indexOf("?") !== -1){
11947 url += "&" + append;
11949 url += "?" + append;
11958 processSuccess : function(response){
11959 this.transaction = null;
11960 if(response.argument.form && response.argument.reset){
11961 try{ // put in try/catch since some older FF releases had problems with this
11962 response.argument.form.reset();
11965 if(this.loadScripts){
11966 this.renderer.render(this.el, response, this,
11967 this.updateComplete.createDelegate(this, [response]));
11969 this.renderer.render(this.el, response, this);
11970 this.updateComplete(response);
11974 updateComplete : function(response){
11975 this.fireEvent("update", this.el, response);
11976 if(typeof response.argument.callback == "function"){
11977 response.argument.callback(this.el, true, response);
11984 processFailure : function(response){
11985 this.transaction = null;
11986 this.fireEvent("failure", this.el, response);
11987 if(typeof response.argument.callback == "function"){
11988 response.argument.callback(this.el, false, response);
11993 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11994 * @param {Object} renderer The object implementing the render() method
11996 setRenderer : function(renderer){
11997 this.renderer = renderer;
12000 getRenderer : function(){
12001 return this.renderer;
12005 * Set the defaultUrl used for updates
12006 * @param {String/Function} defaultUrl The url or a function to call to get the url
12008 setDefaultUrl : function(defaultUrl){
12009 this.defaultUrl = defaultUrl;
12013 * Aborts the executing transaction
12015 abort : function(){
12016 if(this.transaction){
12017 Roo.Ajax.abort(this.transaction);
12022 * Returns true if an update is in progress
12023 * @return {Boolean}
12025 isUpdating : function(){
12026 if(this.transaction){
12027 return Roo.Ajax.isLoading(this.transaction);
12034 * @class Roo.UpdateManager.defaults
12035 * @static (not really - but it helps the doc tool)
12036 * The defaults collection enables customizing the default properties of UpdateManager
12038 Roo.UpdateManager.defaults = {
12040 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12046 * True to process scripts by default (Defaults to false).
12049 loadScripts : false,
12052 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12055 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12057 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12060 disableCaching : false,
12062 * Whether to show indicatorText when loading (Defaults to true).
12065 showLoadIndicator : true,
12067 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12070 indicatorText : '<div class="loading-indicator">Loading...</div>'
12074 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12076 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12077 * @param {String/HTMLElement/Roo.Element} el The element to update
12078 * @param {String} url The url
12079 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12080 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12083 * @member Roo.UpdateManager
12085 Roo.UpdateManager.updateElement = function(el, url, params, options){
12086 var um = Roo.get(el, true).getUpdateManager();
12087 Roo.apply(um, options);
12088 um.update(url, params, options ? options.callback : null);
12090 // alias for backwards compat
12091 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12093 * @class Roo.UpdateManager.BasicRenderer
12094 * Default Content renderer. Updates the elements innerHTML with the responseText.
12096 Roo.UpdateManager.BasicRenderer = function(){};
12098 Roo.UpdateManager.BasicRenderer.prototype = {
12100 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12101 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12102 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12103 * @param {Roo.Element} el The element being rendered
12104 * @param {Object} response The YUI Connect response object
12105 * @param {UpdateManager} updateManager The calling update manager
12106 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12108 render : function(el, response, updateManager, callback){
12109 el.update(response.responseText, updateManager.loadScripts, callback);
12115 * (c)) Alan Knowles
12121 * @class Roo.DomTemplate
12122 * @extends Roo.Template
12123 * An effort at a dom based template engine..
12125 * Similar to XTemplate, except it uses dom parsing to create the template..
12127 * Supported features:
12132 {a_variable} - output encoded.
12133 {a_variable.format:("Y-m-d")} - call a method on the variable
12134 {a_variable:raw} - unencoded output
12135 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12136 {a_variable:this.method_on_template(...)} - call a method on the template object.
12141 <div roo-for="a_variable or condition.."></div>
12142 <div roo-if="a_variable or condition"></div>
12143 <div roo-exec="some javascript"></div>
12144 <div roo-name="named_template"></div>
12149 Roo.DomTemplate = function()
12151 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12158 Roo.extend(Roo.DomTemplate, Roo.Template, {
12160 * id counter for sub templates.
12164 * flag to indicate if dom parser is inside a pre,
12165 * it will strip whitespace if not.
12170 * The various sub templates
12178 * basic tag replacing syntax
12181 * // you can fake an object call by doing this
12185 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12186 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12188 iterChild : function (node, method) {
12190 var oldPre = this.inPre;
12191 if (node.tagName == 'PRE') {
12194 for( var i = 0; i < node.childNodes.length; i++) {
12195 method.call(this, node.childNodes[i]);
12197 this.inPre = oldPre;
12203 * compile the template
12205 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12208 compile: function()
12212 // covert the html into DOM...
12216 doc = document.implementation.createHTMLDocument("");
12217 doc.documentElement.innerHTML = this.html ;
12218 div = doc.documentElement;
12220 // old IE... - nasty -- it causes all sorts of issues.. with
12221 // images getting pulled from server..
12222 div = document.createElement('div');
12223 div.innerHTML = this.html;
12225 //doc.documentElement.innerHTML = htmlBody
12231 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12233 var tpls = this.tpls;
12235 // create a top level template from the snippet..
12237 //Roo.log(div.innerHTML);
12244 body : div.innerHTML,
12257 Roo.each(tpls, function(tp){
12258 this.compileTpl(tp);
12259 this.tpls[tp.id] = tp;
12262 this.master = tpls[0];
12268 compileNode : function(node, istop) {
12273 // skip anything not a tag..
12274 if (node.nodeType != 1) {
12275 if (node.nodeType == 3 && !this.inPre) {
12276 // reduce white space..
12277 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12300 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12301 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12302 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12303 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12309 // just itterate children..
12310 this.iterChild(node,this.compileNode);
12313 tpl.uid = this.id++;
12314 tpl.value = node.getAttribute('roo-' + tpl.attr);
12315 node.removeAttribute('roo-'+ tpl.attr);
12316 if (tpl.attr != 'name') {
12317 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12318 node.parentNode.replaceChild(placeholder, node);
12321 var placeholder = document.createElement('span');
12322 placeholder.className = 'roo-tpl-' + tpl.value;
12323 node.parentNode.replaceChild(placeholder, node);
12326 // parent now sees '{domtplXXXX}
12327 this.iterChild(node,this.compileNode);
12329 // we should now have node body...
12330 var div = document.createElement('div');
12331 div.appendChild(node);
12333 // this has the unfortunate side effect of converting tagged attributes
12334 // eg. href="{...}" into %7C...%7D
12335 // this has been fixed by searching for those combo's although it's a bit hacky..
12338 tpl.body = div.innerHTML;
12345 switch (tpl.value) {
12346 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12347 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12348 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12353 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12357 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12361 tpl.id = tpl.value; // replace non characters???
12367 this.tpls.push(tpl);
12377 * Compile a segment of the template into a 'sub-template'
12383 compileTpl : function(tpl)
12385 var fm = Roo.util.Format;
12386 var useF = this.disableFormats !== true;
12388 var sep = Roo.isGecko ? "+\n" : ",\n";
12390 var undef = function(str) {
12391 Roo.debug && Roo.log("Property not found :" + str);
12395 //Roo.log(tpl.body);
12399 var fn = function(m, lbrace, name, format, args)
12402 //Roo.log(arguments);
12403 args = args ? args.replace(/\\'/g,"'") : args;
12404 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12405 if (typeof(format) == 'undefined') {
12406 format = 'htmlEncode';
12408 if (format == 'raw' ) {
12412 if(name.substr(0, 6) == 'domtpl'){
12413 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12416 // build an array of options to determine if value is undefined..
12418 // basically get 'xxxx.yyyy' then do
12419 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12420 // (function () { Roo.log("Property not found"); return ''; })() :
12425 Roo.each(name.split('.'), function(st) {
12426 lookfor += (lookfor.length ? '.': '') + st;
12427 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12430 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12433 if(format && useF){
12435 args = args ? ',' + args : "";
12437 if(format.substr(0, 5) != "this."){
12438 format = "fm." + format + '(';
12440 format = 'this.call("'+ format.substr(5) + '", ';
12444 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12447 if (args && args.length) {
12448 // called with xxyx.yuu:(test,test)
12450 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12452 // raw.. - :raw modifier..
12453 return "'"+ sep + udef_st + name + ")"+sep+"'";
12457 // branched to use + in gecko and [].join() in others
12459 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12460 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12463 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12464 body.push(tpl.body.replace(/(\r\n|\n)/g,
12465 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12466 body.push("'].join('');};};");
12467 body = body.join('');
12470 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12472 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12479 * same as applyTemplate, except it's done to one of the subTemplates
12480 * when using named templates, you can do:
12482 * var str = pl.applySubTemplate('your-name', values);
12485 * @param {Number} id of the template
12486 * @param {Object} values to apply to template
12487 * @param {Object} parent (normaly the instance of this object)
12489 applySubTemplate : function(id, values, parent)
12493 var t = this.tpls[id];
12497 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12498 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12502 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12509 if(t.execCall && t.execCall.call(this, values, parent)){
12513 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12519 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12520 parent = t.target ? values : parent;
12521 if(t.forCall && vs instanceof Array){
12523 for(var i = 0, len = vs.length; i < len; i++){
12525 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12527 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12529 //Roo.log(t.compiled);
12533 return buf.join('');
12536 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12541 return t.compiled.call(this, vs, parent);
12543 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12545 //Roo.log(t.compiled);
12553 applyTemplate : function(values){
12554 return this.master.compiled.call(this, values, {});
12555 //var s = this.subs;
12558 apply : function(){
12559 return this.applyTemplate.apply(this, arguments);
12564 Roo.DomTemplate.from = function(el){
12565 el = Roo.getDom(el);
12566 return new Roo.Domtemplate(el.value || el.innerHTML);
12569 * Ext JS Library 1.1.1
12570 * Copyright(c) 2006-2007, Ext JS, LLC.
12572 * Originally Released Under LGPL - original licence link has changed is not relivant.
12575 * <script type="text/javascript">
12579 * @class Roo.util.DelayedTask
12580 * Provides a convenient method of performing setTimeout where a new
12581 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12582 * You can use this class to buffer
12583 * the keypress events for a certain number of milliseconds, and perform only if they stop
12584 * for that amount of time.
12585 * @constructor The parameters to this constructor serve as defaults and are not required.
12586 * @param {Function} fn (optional) The default function to timeout
12587 * @param {Object} scope (optional) The default scope of that timeout
12588 * @param {Array} args (optional) The default Array of arguments
12590 Roo.util.DelayedTask = function(fn, scope, args){
12591 var id = null, d, t;
12593 var call = function(){
12594 var now = new Date().getTime();
12598 fn.apply(scope, args || []);
12602 * Cancels any pending timeout and queues a new one
12603 * @param {Number} delay The milliseconds to delay
12604 * @param {Function} newFn (optional) Overrides function passed to constructor
12605 * @param {Object} newScope (optional) Overrides scope passed to constructor
12606 * @param {Array} newArgs (optional) Overrides args passed to constructor
12608 this.delay = function(delay, newFn, newScope, newArgs){
12609 if(id && delay != d){
12613 t = new Date().getTime();
12615 scope = newScope || scope;
12616 args = newArgs || args;
12618 id = setInterval(call, d);
12623 * Cancel the last queued timeout
12625 this.cancel = function(){
12633 * Ext JS Library 1.1.1
12634 * Copyright(c) 2006-2007, Ext JS, LLC.
12636 * Originally Released Under LGPL - original licence link has changed is not relivant.
12639 * <script type="text/javascript">
12643 Roo.util.TaskRunner = function(interval){
12644 interval = interval || 10;
12645 var tasks = [], removeQueue = [];
12647 var running = false;
12649 var stopThread = function(){
12655 var startThread = function(){
12658 id = setInterval(runTasks, interval);
12662 var removeTask = function(task){
12663 removeQueue.push(task);
12669 var runTasks = function(){
12670 if(removeQueue.length > 0){
12671 for(var i = 0, len = removeQueue.length; i < len; i++){
12672 tasks.remove(removeQueue[i]);
12675 if(tasks.length < 1){
12680 var now = new Date().getTime();
12681 for(var i = 0, len = tasks.length; i < len; ++i){
12683 var itime = now - t.taskRunTime;
12684 if(t.interval <= itime){
12685 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12686 t.taskRunTime = now;
12687 if(rt === false || t.taskRunCount === t.repeat){
12692 if(t.duration && t.duration <= (now - t.taskStartTime)){
12699 * Queues a new task.
12700 * @param {Object} task
12702 this.start = function(task){
12704 task.taskStartTime = new Date().getTime();
12705 task.taskRunTime = 0;
12706 task.taskRunCount = 0;
12711 this.stop = function(task){
12716 this.stopAll = function(){
12718 for(var i = 0, len = tasks.length; i < len; i++){
12719 if(tasks[i].onStop){
12728 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12730 * Ext JS Library 1.1.1
12731 * Copyright(c) 2006-2007, Ext JS, LLC.
12733 * Originally Released Under LGPL - original licence link has changed is not relivant.
12736 * <script type="text/javascript">
12741 * @class Roo.util.MixedCollection
12742 * @extends Roo.util.Observable
12743 * A Collection class that maintains both numeric indexes and keys and exposes events.
12745 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12746 * collection (defaults to false)
12747 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12748 * and return the key value for that item. This is used when available to look up the key on items that
12749 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12750 * equivalent to providing an implementation for the {@link #getKey} method.
12752 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12760 * Fires when the collection is cleared.
12765 * Fires when an item is added to the collection.
12766 * @param {Number} index The index at which the item was added.
12767 * @param {Object} o The item added.
12768 * @param {String} key The key associated with the added item.
12773 * Fires when an item is replaced in the collection.
12774 * @param {String} key he key associated with the new added.
12775 * @param {Object} old The item being replaced.
12776 * @param {Object} new The new item.
12781 * Fires when an item is removed from the collection.
12782 * @param {Object} o The item being removed.
12783 * @param {String} key (optional) The key associated with the removed item.
12788 this.allowFunctions = allowFunctions === true;
12790 this.getKey = keyFn;
12792 Roo.util.MixedCollection.superclass.constructor.call(this);
12795 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12796 allowFunctions : false,
12799 * Adds an item to the collection.
12800 * @param {String} key The key to associate with the item
12801 * @param {Object} o The item to add.
12802 * @return {Object} The item added.
12804 add : function(key, o){
12805 if(arguments.length == 1){
12807 key = this.getKey(o);
12809 if(typeof key == "undefined" || key === null){
12811 this.items.push(o);
12812 this.keys.push(null);
12814 var old = this.map[key];
12816 return this.replace(key, o);
12819 this.items.push(o);
12821 this.keys.push(key);
12823 this.fireEvent("add", this.length-1, o, key);
12828 * MixedCollection has a generic way to fetch keys if you implement getKey.
12831 var mc = new Roo.util.MixedCollection();
12832 mc.add(someEl.dom.id, someEl);
12833 mc.add(otherEl.dom.id, otherEl);
12837 var mc = new Roo.util.MixedCollection();
12838 mc.getKey = function(el){
12844 // or via the constructor
12845 var mc = new Roo.util.MixedCollection(false, function(el){
12851 * @param o {Object} The item for which to find the key.
12852 * @return {Object} The key for the passed item.
12854 getKey : function(o){
12859 * Replaces an item in the collection.
12860 * @param {String} key The key associated with the item to replace, or the item to replace.
12861 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12862 * @return {Object} The new item.
12864 replace : function(key, o){
12865 if(arguments.length == 1){
12867 key = this.getKey(o);
12869 var old = this.item(key);
12870 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12871 return this.add(key, o);
12873 var index = this.indexOfKey(key);
12874 this.items[index] = o;
12876 this.fireEvent("replace", key, old, o);
12881 * Adds all elements of an Array or an Object to the collection.
12882 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12883 * an Array of values, each of which are added to the collection.
12885 addAll : function(objs){
12886 if(arguments.length > 1 || objs instanceof Array){
12887 var args = arguments.length > 1 ? arguments : objs;
12888 for(var i = 0, len = args.length; i < len; i++){
12892 for(var key in objs){
12893 if(this.allowFunctions || typeof objs[key] != "function"){
12894 this.add(key, objs[key]);
12901 * Executes the specified function once for every item in the collection, passing each
12902 * item as the first and only parameter. returning false from the function will stop the iteration.
12903 * @param {Function} fn The function to execute for each item.
12904 * @param {Object} scope (optional) The scope in which to execute the function.
12906 each : function(fn, scope){
12907 var items = [].concat(this.items); // each safe for removal
12908 for(var i = 0, len = items.length; i < len; i++){
12909 if(fn.call(scope || items[i], items[i], i, len) === false){
12916 * Executes the specified function once for every key in the collection, passing each
12917 * key, and its associated item as the first two parameters.
12918 * @param {Function} fn The function to execute for each item.
12919 * @param {Object} scope (optional) The scope in which to execute the function.
12921 eachKey : function(fn, scope){
12922 for(var i = 0, len = this.keys.length; i < len; i++){
12923 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12928 * Returns the first item in the collection which elicits a true return value from the
12929 * passed selection function.
12930 * @param {Function} fn The selection function to execute for each item.
12931 * @param {Object} scope (optional) The scope in which to execute the function.
12932 * @return {Object} The first item in the collection which returned true from the selection function.
12934 find : function(fn, scope){
12935 for(var i = 0, len = this.items.length; i < len; i++){
12936 if(fn.call(scope || window, this.items[i], this.keys[i])){
12937 return this.items[i];
12944 * Inserts an item at the specified index in the collection.
12945 * @param {Number} index The index to insert the item at.
12946 * @param {String} key The key to associate with the new item, or the item itself.
12947 * @param {Object} o (optional) If the second parameter was a key, the new item.
12948 * @return {Object} The item inserted.
12950 insert : function(index, key, o){
12951 if(arguments.length == 2){
12953 key = this.getKey(o);
12955 if(index >= this.length){
12956 return this.add(key, o);
12959 this.items.splice(index, 0, o);
12960 if(typeof key != "undefined" && key != null){
12963 this.keys.splice(index, 0, key);
12964 this.fireEvent("add", index, o, key);
12969 * Removed an item from the collection.
12970 * @param {Object} o The item to remove.
12971 * @return {Object} The item removed.
12973 remove : function(o){
12974 return this.removeAt(this.indexOf(o));
12978 * Remove an item from a specified index in the collection.
12979 * @param {Number} index The index within the collection of the item to remove.
12981 removeAt : function(index){
12982 if(index < this.length && index >= 0){
12984 var o = this.items[index];
12985 this.items.splice(index, 1);
12986 var key = this.keys[index];
12987 if(typeof key != "undefined"){
12988 delete this.map[key];
12990 this.keys.splice(index, 1);
12991 this.fireEvent("remove", o, key);
12996 * Removed an item associated with the passed key fom the collection.
12997 * @param {String} key The key of the item to remove.
12999 removeKey : function(key){
13000 return this.removeAt(this.indexOfKey(key));
13004 * Returns the number of items in the collection.
13005 * @return {Number} the number of items in the collection.
13007 getCount : function(){
13008 return this.length;
13012 * Returns index within the collection of the passed Object.
13013 * @param {Object} o The item to find the index of.
13014 * @return {Number} index of the item.
13016 indexOf : function(o){
13017 if(!this.items.indexOf){
13018 for(var i = 0, len = this.items.length; i < len; i++){
13019 if(this.items[i] == o) return i;
13023 return this.items.indexOf(o);
13028 * Returns index within the collection of the passed key.
13029 * @param {String} key The key to find the index of.
13030 * @return {Number} index of the key.
13032 indexOfKey : function(key){
13033 if(!this.keys.indexOf){
13034 for(var i = 0, len = this.keys.length; i < len; i++){
13035 if(this.keys[i] == key) return i;
13039 return this.keys.indexOf(key);
13044 * Returns the item associated with the passed key OR index. Key has priority over index.
13045 * @param {String/Number} key The key or index of the item.
13046 * @return {Object} The item associated with the passed key.
13048 item : function(key){
13049 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13050 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13054 * Returns the item at the specified index.
13055 * @param {Number} index The index of the item.
13058 itemAt : function(index){
13059 return this.items[index];
13063 * Returns the item associated with the passed key.
13064 * @param {String/Number} key The key of the item.
13065 * @return {Object} The item associated with the passed key.
13067 key : function(key){
13068 return this.map[key];
13072 * Returns true if the collection contains the passed Object as an item.
13073 * @param {Object} o The Object to look for in the collection.
13074 * @return {Boolean} True if the collection contains the Object as an item.
13076 contains : function(o){
13077 return this.indexOf(o) != -1;
13081 * Returns true if the collection contains the passed Object as a key.
13082 * @param {String} key The key to look for in the collection.
13083 * @return {Boolean} True if the collection contains the Object as a key.
13085 containsKey : function(key){
13086 return typeof this.map[key] != "undefined";
13090 * Removes all items from the collection.
13092 clear : function(){
13097 this.fireEvent("clear");
13101 * Returns the first item in the collection.
13102 * @return {Object} the first item in the collection..
13104 first : function(){
13105 return this.items[0];
13109 * Returns the last item in the collection.
13110 * @return {Object} the last item in the collection..
13113 return this.items[this.length-1];
13116 _sort : function(property, dir, fn){
13117 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13118 fn = fn || function(a, b){
13121 var c = [], k = this.keys, items = this.items;
13122 for(var i = 0, len = items.length; i < len; i++){
13123 c[c.length] = {key: k[i], value: items[i], index: i};
13125 c.sort(function(a, b){
13126 var v = fn(a[property], b[property]) * dsc;
13128 v = (a.index < b.index ? -1 : 1);
13132 for(var i = 0, len = c.length; i < len; i++){
13133 items[i] = c[i].value;
13136 this.fireEvent("sort", this);
13140 * Sorts this collection with the passed comparison function
13141 * @param {String} direction (optional) "ASC" or "DESC"
13142 * @param {Function} fn (optional) comparison function
13144 sort : function(dir, fn){
13145 this._sort("value", dir, fn);
13149 * Sorts this collection by keys
13150 * @param {String} direction (optional) "ASC" or "DESC"
13151 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13153 keySort : function(dir, fn){
13154 this._sort("key", dir, fn || function(a, b){
13155 return String(a).toUpperCase()-String(b).toUpperCase();
13160 * Returns a range of items in this collection
13161 * @param {Number} startIndex (optional) defaults to 0
13162 * @param {Number} endIndex (optional) default to the last item
13163 * @return {Array} An array of items
13165 getRange : function(start, end){
13166 var items = this.items;
13167 if(items.length < 1){
13170 start = start || 0;
13171 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13174 for(var i = start; i <= end; i++) {
13175 r[r.length] = items[i];
13178 for(var i = start; i >= end; i--) {
13179 r[r.length] = items[i];
13186 * Filter the <i>objects</i> in this collection by a specific property.
13187 * Returns a new collection that has been filtered.
13188 * @param {String} property A property on your objects
13189 * @param {String/RegExp} value Either string that the property values
13190 * should start with or a RegExp to test against the property
13191 * @return {MixedCollection} The new filtered collection
13193 filter : function(property, value){
13194 if(!value.exec){ // not a regex
13195 value = String(value);
13196 if(value.length == 0){
13197 return this.clone();
13199 value = new RegExp("^" + Roo.escapeRe(value), "i");
13201 return this.filterBy(function(o){
13202 return o && value.test(o[property]);
13207 * Filter by a function. * Returns a new collection that has been filtered.
13208 * The passed function will be called with each
13209 * object in the collection. If the function returns true, the value is included
13210 * otherwise it is filtered.
13211 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13212 * @param {Object} scope (optional) The scope of the function (defaults to this)
13213 * @return {MixedCollection} The new filtered collection
13215 filterBy : function(fn, scope){
13216 var r = new Roo.util.MixedCollection();
13217 r.getKey = this.getKey;
13218 var k = this.keys, it = this.items;
13219 for(var i = 0, len = it.length; i < len; i++){
13220 if(fn.call(scope||this, it[i], k[i])){
13221 r.add(k[i], it[i]);
13228 * Creates a duplicate of this collection
13229 * @return {MixedCollection}
13231 clone : function(){
13232 var r = new Roo.util.MixedCollection();
13233 var k = this.keys, it = this.items;
13234 for(var i = 0, len = it.length; i < len; i++){
13235 r.add(k[i], it[i]);
13237 r.getKey = this.getKey;
13242 * Returns the item associated with the passed key or index.
13244 * @param {String/Number} key The key or index of the item.
13245 * @return {Object} The item associated with the passed key.
13247 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13249 * Ext JS Library 1.1.1
13250 * Copyright(c) 2006-2007, Ext JS, LLC.
13252 * Originally Released Under LGPL - original licence link has changed is not relivant.
13255 * <script type="text/javascript">
13258 * @class Roo.util.JSON
13259 * Modified version of Douglas Crockford"s json.js that doesn"t
13260 * mess with the Object prototype
13261 * http://www.json.org/js.html
13264 Roo.util.JSON = new (function(){
13265 var useHasOwn = {}.hasOwnProperty ? true : false;
13267 // crashes Safari in some instances
13268 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13270 var pad = function(n) {
13271 return n < 10 ? "0" + n : n;
13284 var encodeString = function(s){
13285 if (/["\\\x00-\x1f]/.test(s)) {
13286 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13291 c = b.charCodeAt();
13293 Math.floor(c / 16).toString(16) +
13294 (c % 16).toString(16);
13297 return '"' + s + '"';
13300 var encodeArray = function(o){
13301 var a = ["["], b, i, l = o.length, v;
13302 for (i = 0; i < l; i += 1) {
13304 switch (typeof v) {
13313 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13321 var encodeDate = function(o){
13322 return '"' + o.getFullYear() + "-" +
13323 pad(o.getMonth() + 1) + "-" +
13324 pad(o.getDate()) + "T" +
13325 pad(o.getHours()) + ":" +
13326 pad(o.getMinutes()) + ":" +
13327 pad(o.getSeconds()) + '"';
13331 * Encodes an Object, Array or other value
13332 * @param {Mixed} o The variable to encode
13333 * @return {String} The JSON string
13335 this.encode = function(o)
13337 // should this be extended to fully wrap stringify..
13339 if(typeof o == "undefined" || o === null){
13341 }else if(o instanceof Array){
13342 return encodeArray(o);
13343 }else if(o instanceof Date){
13344 return encodeDate(o);
13345 }else if(typeof o == "string"){
13346 return encodeString(o);
13347 }else if(typeof o == "number"){
13348 return isFinite(o) ? String(o) : "null";
13349 }else if(typeof o == "boolean"){
13352 var a = ["{"], b, i, v;
13354 if(!useHasOwn || o.hasOwnProperty(i)) {
13356 switch (typeof v) {
13365 a.push(this.encode(i), ":",
13366 v === null ? "null" : this.encode(v));
13377 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13378 * @param {String} json The JSON string
13379 * @return {Object} The resulting object
13381 this.decode = function(json){
13383 return /** eval:var:json */ eval("(" + json + ')');
13387 * Shorthand for {@link Roo.util.JSON#encode}
13388 * @member Roo encode
13390 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13392 * Shorthand for {@link Roo.util.JSON#decode}
13393 * @member Roo decode
13395 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13398 * Ext JS Library 1.1.1
13399 * Copyright(c) 2006-2007, Ext JS, LLC.
13401 * Originally Released Under LGPL - original licence link has changed is not relivant.
13404 * <script type="text/javascript">
13408 * @class Roo.util.Format
13409 * Reusable data formatting functions
13412 Roo.util.Format = function(){
13413 var trimRe = /^\s+|\s+$/g;
13416 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13417 * @param {String} value The string to truncate
13418 * @param {Number} length The maximum length to allow before truncating
13419 * @return {String} The converted text
13421 ellipsis : function(value, len){
13422 if(value && value.length > len){
13423 return value.substr(0, len-3)+"...";
13429 * Checks a reference and converts it to empty string if it is undefined
13430 * @param {Mixed} value Reference to check
13431 * @return {Mixed} Empty string if converted, otherwise the original value
13433 undef : function(value){
13434 return typeof value != "undefined" ? value : "";
13438 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13439 * @param {String} value The string to encode
13440 * @return {String} The encoded text
13442 htmlEncode : function(value){
13443 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13447 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13448 * @param {String} value The string to decode
13449 * @return {String} The decoded text
13451 htmlDecode : function(value){
13452 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13456 * Trims any whitespace from either side of a string
13457 * @param {String} value The text to trim
13458 * @return {String} The trimmed text
13460 trim : function(value){
13461 return String(value).replace(trimRe, "");
13465 * Returns a substring from within an original string
13466 * @param {String} value The original text
13467 * @param {Number} start The start index of the substring
13468 * @param {Number} length The length of the substring
13469 * @return {String} The substring
13471 substr : function(value, start, length){
13472 return String(value).substr(start, length);
13476 * Converts a string to all lower case letters
13477 * @param {String} value The text to convert
13478 * @return {String} The converted text
13480 lowercase : function(value){
13481 return String(value).toLowerCase();
13485 * Converts a string to all upper case letters
13486 * @param {String} value The text to convert
13487 * @return {String} The converted text
13489 uppercase : function(value){
13490 return String(value).toUpperCase();
13494 * Converts the first character only of a string to upper case
13495 * @param {String} value The text to convert
13496 * @return {String} The converted text
13498 capitalize : function(value){
13499 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13503 call : function(value, fn){
13504 if(arguments.length > 2){
13505 var args = Array.prototype.slice.call(arguments, 2);
13506 args.unshift(value);
13508 return /** eval:var:value */ eval(fn).apply(window, args);
13510 /** eval:var:value */
13511 return /** eval:var:value */ eval(fn).call(window, value);
13517 * safer version of Math.toFixed..??/
13518 * @param {Number/String} value The numeric value to format
13519 * @param {Number/String} value Decimal places
13520 * @return {String} The formatted currency string
13522 toFixed : function(v, n)
13524 // why not use to fixed - precision is buggered???
13526 return Math.round(v-0);
13528 var fact = Math.pow(10,n+1);
13529 v = (Math.round((v-0)*fact))/fact;
13530 var z = (''+fact).substring(2);
13531 if (v == Math.floor(v)) {
13532 return Math.floor(v) + '.' + z;
13535 // now just padd decimals..
13536 var ps = String(v).split('.');
13537 var fd = (ps[1] + z);
13538 var r = fd.substring(0,n);
13539 var rm = fd.substring(n);
13541 return ps[0] + '.' + r;
13543 r*=1; // turn it into a number;
13545 if (String(r).length != n) {
13548 r = String(r).substring(1); // chop the end off.
13551 return ps[0] + '.' + r;
13556 * Format a number as US currency
13557 * @param {Number/String} value The numeric value to format
13558 * @return {String} The formatted currency string
13560 usMoney : function(v){
13561 return '$' + Roo.util.Format.number(v);
13566 * eventually this should probably emulate php's number_format
13567 * @param {Number/String} value The numeric value to format
13568 * @param {Number} decimals number of decimal places
13569 * @return {String} The formatted currency string
13571 number : function(v,decimals)
13573 // multiply and round.
13574 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13575 var mul = Math.pow(10, decimals);
13576 var zero = String(mul).substring(1);
13577 v = (Math.round((v-0)*mul))/mul;
13579 // if it's '0' number.. then
13581 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13583 var ps = v.split('.');
13587 var r = /(\d+)(\d{3})/;
13589 while (r.test(whole)) {
13590 whole = whole.replace(r, '$1' + ',' + '$2');
13596 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13597 // does not have decimals
13598 (decimals ? ('.' + zero) : '');
13601 return whole + sub ;
13605 * Parse a value into a formatted date using the specified format pattern.
13606 * @param {Mixed} value The value to format
13607 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13608 * @return {String} The formatted date string
13610 date : function(v, format){
13614 if(!(v instanceof Date)){
13615 v = new Date(Date.parse(v));
13617 return v.dateFormat(format || "m/d/Y");
13621 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13622 * @param {String} format Any valid date format string
13623 * @return {Function} The date formatting function
13625 dateRenderer : function(format){
13626 return function(v){
13627 return Roo.util.Format.date(v, format);
13632 stripTagsRE : /<\/?[^>]+>/gi,
13635 * Strips all HTML tags
13636 * @param {Mixed} value The text from which to strip tags
13637 * @return {String} The stripped text
13639 stripTags : function(v){
13640 return !v ? v : String(v).replace(this.stripTagsRE, "");
13645 * Ext JS Library 1.1.1
13646 * Copyright(c) 2006-2007, Ext JS, LLC.
13648 * Originally Released Under LGPL - original licence link has changed is not relivant.
13651 * <script type="text/javascript">
13658 * @class Roo.MasterTemplate
13659 * @extends Roo.Template
13660 * Provides a template that can have child templates. The syntax is:
13662 var t = new Roo.MasterTemplate(
13663 '<select name="{name}">',
13664 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13667 t.add('options', {value: 'foo', text: 'bar'});
13668 // or you can add multiple child elements in one shot
13669 t.addAll('options', [
13670 {value: 'foo', text: 'bar'},
13671 {value: 'foo2', text: 'bar2'},
13672 {value: 'foo3', text: 'bar3'}
13674 // then append, applying the master template values
13675 t.append('my-form', {name: 'my-select'});
13677 * A name attribute for the child template is not required if you have only one child
13678 * template or you want to refer to them by index.
13680 Roo.MasterTemplate = function(){
13681 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13682 this.originalHtml = this.html;
13684 var m, re = this.subTemplateRe;
13687 while(m = re.exec(this.html)){
13688 var name = m[1], content = m[2];
13693 tpl : new Roo.Template(content)
13696 st[name] = st[subIndex];
13698 st[subIndex].tpl.compile();
13699 st[subIndex].tpl.call = this.call.createDelegate(this);
13702 this.subCount = subIndex;
13705 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13707 * The regular expression used to match sub templates
13711 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13714 * Applies the passed values to a child template.
13715 * @param {String/Number} name (optional) The name or index of the child template
13716 * @param {Array/Object} values The values to be applied to the template
13717 * @return {MasterTemplate} this
13719 add : function(name, values){
13720 if(arguments.length == 1){
13721 values = arguments[0];
13724 var s = this.subs[name];
13725 s.buffer[s.buffer.length] = s.tpl.apply(values);
13730 * Applies all the passed values to a child template.
13731 * @param {String/Number} name (optional) The name or index of the child template
13732 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13733 * @param {Boolean} reset (optional) True to reset the template first
13734 * @return {MasterTemplate} this
13736 fill : function(name, values, reset){
13738 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13746 for(var i = 0, len = values.length; i < len; i++){
13747 this.add(name, values[i]);
13753 * Resets the template for reuse
13754 * @return {MasterTemplate} this
13756 reset : function(){
13758 for(var i = 0; i < this.subCount; i++){
13764 applyTemplate : function(values){
13766 var replaceIndex = -1;
13767 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13768 return s[++replaceIndex].buffer.join("");
13770 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13773 apply : function(){
13774 return this.applyTemplate.apply(this, arguments);
13777 compile : function(){return this;}
13781 * Alias for fill().
13784 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13786 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13787 * var tpl = Roo.MasterTemplate.from('element-id');
13788 * @param {String/HTMLElement} el
13789 * @param {Object} config
13792 Roo.MasterTemplate.from = function(el, config){
13793 el = Roo.getDom(el);
13794 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13797 * Ext JS Library 1.1.1
13798 * Copyright(c) 2006-2007, Ext JS, LLC.
13800 * Originally Released Under LGPL - original licence link has changed is not relivant.
13803 * <script type="text/javascript">
13808 * @class Roo.util.CSS
13809 * Utility class for manipulating CSS rules
13812 Roo.util.CSS = function(){
13814 var doc = document;
13816 var camelRe = /(-[a-z])/gi;
13817 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13821 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13822 * tag and appended to the HEAD of the document.
13823 * @param {String|Object} cssText The text containing the css rules
13824 * @param {String} id An id to add to the stylesheet for later removal
13825 * @return {StyleSheet}
13827 createStyleSheet : function(cssText, id){
13829 var head = doc.getElementsByTagName("head")[0];
13830 var nrules = doc.createElement("style");
13831 nrules.setAttribute("type", "text/css");
13833 nrules.setAttribute("id", id);
13835 if (typeof(cssText) != 'string') {
13836 // support object maps..
13837 // not sure if this a good idea..
13838 // perhaps it should be merged with the general css handling
13839 // and handle js style props.
13840 var cssTextNew = [];
13841 for(var n in cssText) {
13843 for(var k in cssText[n]) {
13844 citems.push( k + ' : ' +cssText[n][k] + ';' );
13846 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13849 cssText = cssTextNew.join("\n");
13855 head.appendChild(nrules);
13856 ss = nrules.styleSheet;
13857 ss.cssText = cssText;
13860 nrules.appendChild(doc.createTextNode(cssText));
13862 nrules.cssText = cssText;
13864 head.appendChild(nrules);
13865 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13867 this.cacheStyleSheet(ss);
13872 * Removes a style or link tag by id
13873 * @param {String} id The id of the tag
13875 removeStyleSheet : function(id){
13876 var existing = doc.getElementById(id);
13878 existing.parentNode.removeChild(existing);
13883 * Dynamically swaps an existing stylesheet reference for a new one
13884 * @param {String} id The id of an existing link tag to remove
13885 * @param {String} url The href of the new stylesheet to include
13887 swapStyleSheet : function(id, url){
13888 this.removeStyleSheet(id);
13889 var ss = doc.createElement("link");
13890 ss.setAttribute("rel", "stylesheet");
13891 ss.setAttribute("type", "text/css");
13892 ss.setAttribute("id", id);
13893 ss.setAttribute("href", url);
13894 doc.getElementsByTagName("head")[0].appendChild(ss);
13898 * Refresh the rule cache if you have dynamically added stylesheets
13899 * @return {Object} An object (hash) of rules indexed by selector
13901 refreshCache : function(){
13902 return this.getRules(true);
13906 cacheStyleSheet : function(stylesheet){
13910 try{// try catch for cross domain access issue
13911 var ssRules = stylesheet.cssRules || stylesheet.rules;
13912 for(var j = ssRules.length-1; j >= 0; --j){
13913 rules[ssRules[j].selectorText] = ssRules[j];
13919 * Gets all css rules for the document
13920 * @param {Boolean} refreshCache true to refresh the internal cache
13921 * @return {Object} An object (hash) of rules indexed by selector
13923 getRules : function(refreshCache){
13924 if(rules == null || refreshCache){
13926 var ds = doc.styleSheets;
13927 for(var i =0, len = ds.length; i < len; i++){
13929 this.cacheStyleSheet(ds[i]);
13937 * Gets an an individual CSS rule by selector(s)
13938 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13939 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13940 * @return {CSSRule} The CSS rule or null if one is not found
13942 getRule : function(selector, refreshCache){
13943 var rs = this.getRules(refreshCache);
13944 if(!(selector instanceof Array)){
13945 return rs[selector];
13947 for(var i = 0; i < selector.length; i++){
13948 if(rs[selector[i]]){
13949 return rs[selector[i]];
13957 * Updates a rule property
13958 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13959 * @param {String} property The css property
13960 * @param {String} value The new value for the property
13961 * @return {Boolean} true If a rule was found and updated
13963 updateRule : function(selector, property, value){
13964 if(!(selector instanceof Array)){
13965 var rule = this.getRule(selector);
13967 rule.style[property.replace(camelRe, camelFn)] = value;
13971 for(var i = 0; i < selector.length; i++){
13972 if(this.updateRule(selector[i], property, value)){
13982 * Ext JS Library 1.1.1
13983 * Copyright(c) 2006-2007, Ext JS, LLC.
13985 * Originally Released Under LGPL - original licence link has changed is not relivant.
13988 * <script type="text/javascript">
13994 * @class Roo.util.ClickRepeater
13995 * @extends Roo.util.Observable
13997 * A wrapper class which can be applied to any element. Fires a "click" event while the
13998 * mouse is pressed. The interval between firings may be specified in the config but
13999 * defaults to 10 milliseconds.
14001 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14003 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14004 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14005 * Similar to an autorepeat key delay.
14006 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14007 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14008 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14009 * "interval" and "delay" are ignored. "immediate" is honored.
14010 * @cfg {Boolean} preventDefault True to prevent the default click event
14011 * @cfg {Boolean} stopDefault True to stop the default click event
14014 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14015 * 2007-02-02 jvs Renamed to ClickRepeater
14016 * 2007-02-03 jvs Modifications for FF Mac and Safari
14019 * @param {String/HTMLElement/Element} el The element to listen on
14020 * @param {Object} config
14022 Roo.util.ClickRepeater = function(el, config)
14024 this.el = Roo.get(el);
14025 this.el.unselectable();
14027 Roo.apply(this, config);
14032 * Fires when the mouse button is depressed.
14033 * @param {Roo.util.ClickRepeater} this
14035 "mousedown" : true,
14038 * Fires on a specified interval during the time the element is pressed.
14039 * @param {Roo.util.ClickRepeater} this
14044 * Fires when the mouse key is released.
14045 * @param {Roo.util.ClickRepeater} this
14050 this.el.on("mousedown", this.handleMouseDown, this);
14051 if(this.preventDefault || this.stopDefault){
14052 this.el.on("click", function(e){
14053 if(this.preventDefault){
14054 e.preventDefault();
14056 if(this.stopDefault){
14062 // allow inline handler
14064 this.on("click", this.handler, this.scope || this);
14067 Roo.util.ClickRepeater.superclass.constructor.call(this);
14070 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14073 preventDefault : true,
14074 stopDefault : false,
14078 handleMouseDown : function(){
14079 clearTimeout(this.timer);
14081 if(this.pressClass){
14082 this.el.addClass(this.pressClass);
14084 this.mousedownTime = new Date();
14086 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14087 this.el.on("mouseout", this.handleMouseOut, this);
14089 this.fireEvent("mousedown", this);
14090 this.fireEvent("click", this);
14092 this.timer = this.click.defer(this.delay || this.interval, this);
14096 click : function(){
14097 this.fireEvent("click", this);
14098 this.timer = this.click.defer(this.getInterval(), this);
14102 getInterval: function(){
14103 if(!this.accelerate){
14104 return this.interval;
14106 var pressTime = this.mousedownTime.getElapsed();
14107 if(pressTime < 500){
14109 }else if(pressTime < 1700){
14111 }else if(pressTime < 2600){
14113 }else if(pressTime < 3500){
14115 }else if(pressTime < 4400){
14117 }else if(pressTime < 5300){
14119 }else if(pressTime < 6200){
14127 handleMouseOut : function(){
14128 clearTimeout(this.timer);
14129 if(this.pressClass){
14130 this.el.removeClass(this.pressClass);
14132 this.el.on("mouseover", this.handleMouseReturn, this);
14136 handleMouseReturn : function(){
14137 this.el.un("mouseover", this.handleMouseReturn);
14138 if(this.pressClass){
14139 this.el.addClass(this.pressClass);
14145 handleMouseUp : function(){
14146 clearTimeout(this.timer);
14147 this.el.un("mouseover", this.handleMouseReturn);
14148 this.el.un("mouseout", this.handleMouseOut);
14149 Roo.get(document).un("mouseup", this.handleMouseUp);
14150 this.el.removeClass(this.pressClass);
14151 this.fireEvent("mouseup", this);
14155 * Ext JS Library 1.1.1
14156 * Copyright(c) 2006-2007, Ext JS, LLC.
14158 * Originally Released Under LGPL - original licence link has changed is not relivant.
14161 * <script type="text/javascript">
14166 * @class Roo.KeyNav
14167 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14168 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14169 * way to implement custom navigation schemes for any UI component.</p>
14170 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14171 * pageUp, pageDown, del, home, end. Usage:</p>
14173 var nav = new Roo.KeyNav("my-element", {
14174 "left" : function(e){
14175 this.moveLeft(e.ctrlKey);
14177 "right" : function(e){
14178 this.moveRight(e.ctrlKey);
14180 "enter" : function(e){
14187 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14188 * @param {Object} config The config
14190 Roo.KeyNav = function(el, config){
14191 this.el = Roo.get(el);
14192 Roo.apply(this, config);
14193 if(!this.disabled){
14194 this.disabled = true;
14199 Roo.KeyNav.prototype = {
14201 * @cfg {Boolean} disabled
14202 * True to disable this KeyNav instance (defaults to false)
14206 * @cfg {String} defaultEventAction
14207 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14208 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14209 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14211 defaultEventAction: "stopEvent",
14213 * @cfg {Boolean} forceKeyDown
14214 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14215 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14216 * handle keydown instead of keypress.
14218 forceKeyDown : false,
14221 prepareEvent : function(e){
14222 var k = e.getKey();
14223 var h = this.keyToHandler[k];
14224 //if(h && this[h]){
14225 // e.stopPropagation();
14227 if(Roo.isSafari && h && k >= 37 && k <= 40){
14233 relay : function(e){
14234 var k = e.getKey();
14235 var h = this.keyToHandler[k];
14237 if(this.doRelay(e, this[h], h) !== true){
14238 e[this.defaultEventAction]();
14244 doRelay : function(e, h, hname){
14245 return h.call(this.scope || this, e);
14248 // possible handlers
14262 // quick lookup hash
14279 * Enable this KeyNav
14281 enable: function(){
14283 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14284 // the EventObject will normalize Safari automatically
14285 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14286 this.el.on("keydown", this.relay, this);
14288 this.el.on("keydown", this.prepareEvent, this);
14289 this.el.on("keypress", this.relay, this);
14291 this.disabled = false;
14296 * Disable this KeyNav
14298 disable: function(){
14299 if(!this.disabled){
14300 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14301 this.el.un("keydown", this.relay);
14303 this.el.un("keydown", this.prepareEvent);
14304 this.el.un("keypress", this.relay);
14306 this.disabled = true;
14311 * Ext JS Library 1.1.1
14312 * Copyright(c) 2006-2007, Ext JS, LLC.
14314 * Originally Released Under LGPL - original licence link has changed is not relivant.
14317 * <script type="text/javascript">
14322 * @class Roo.KeyMap
14323 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14324 * The constructor accepts the same config object as defined by {@link #addBinding}.
14325 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14326 * combination it will call the function with this signature (if the match is a multi-key
14327 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14328 * A KeyMap can also handle a string representation of keys.<br />
14331 // map one key by key code
14332 var map = new Roo.KeyMap("my-element", {
14333 key: 13, // or Roo.EventObject.ENTER
14338 // map multiple keys to one action by string
14339 var map = new Roo.KeyMap("my-element", {
14345 // map multiple keys to multiple actions by strings and array of codes
14346 var map = new Roo.KeyMap("my-element", [
14349 fn: function(){ alert("Return was pressed"); }
14352 fn: function(){ alert('a, b or c was pressed'); }
14357 fn: function(){ alert('Control + shift + tab was pressed.'); }
14361 * <b>Note: A KeyMap starts enabled</b>
14363 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14364 * @param {Object} config The config (see {@link #addBinding})
14365 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14367 Roo.KeyMap = function(el, config, eventName){
14368 this.el = Roo.get(el);
14369 this.eventName = eventName || "keydown";
14370 this.bindings = [];
14372 this.addBinding(config);
14377 Roo.KeyMap.prototype = {
14379 * True to stop the event from bubbling and prevent the default browser action if the
14380 * key was handled by the KeyMap (defaults to false)
14386 * Add a new binding to this KeyMap. The following config object properties are supported:
14388 Property Type Description
14389 ---------- --------------- ----------------------------------------------------------------------
14390 key String/Array A single keycode or an array of keycodes to handle
14391 shift Boolean True to handle key only when shift is pressed (defaults to false)
14392 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14393 alt Boolean True to handle key only when alt is pressed (defaults to false)
14394 fn Function The function to call when KeyMap finds the expected key combination
14395 scope Object The scope of the callback function
14401 var map = new Roo.KeyMap(document, {
14402 key: Roo.EventObject.ENTER,
14407 //Add a new binding to the existing KeyMap later
14415 * @param {Object/Array} config A single KeyMap config or an array of configs
14417 addBinding : function(config){
14418 if(config instanceof Array){
14419 for(var i = 0, len = config.length; i < len; i++){
14420 this.addBinding(config[i]);
14424 var keyCode = config.key,
14425 shift = config.shift,
14426 ctrl = config.ctrl,
14429 scope = config.scope;
14430 if(typeof keyCode == "string"){
14432 var keyString = keyCode.toUpperCase();
14433 for(var j = 0, len = keyString.length; j < len; j++){
14434 ks.push(keyString.charCodeAt(j));
14438 var keyArray = keyCode instanceof Array;
14439 var handler = function(e){
14440 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14441 var k = e.getKey();
14443 for(var i = 0, len = keyCode.length; i < len; i++){
14444 if(keyCode[i] == k){
14445 if(this.stopEvent){
14448 fn.call(scope || window, k, e);
14454 if(this.stopEvent){
14457 fn.call(scope || window, k, e);
14462 this.bindings.push(handler);
14466 * Shorthand for adding a single key listener
14467 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14468 * following options:
14469 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14470 * @param {Function} fn The function to call
14471 * @param {Object} scope (optional) The scope of the function
14473 on : function(key, fn, scope){
14474 var keyCode, shift, ctrl, alt;
14475 if(typeof key == "object" && !(key instanceof Array)){
14494 handleKeyDown : function(e){
14495 if(this.enabled){ //just in case
14496 var b = this.bindings;
14497 for(var i = 0, len = b.length; i < len; i++){
14498 b[i].call(this, e);
14504 * Returns true if this KeyMap is enabled
14505 * @return {Boolean}
14507 isEnabled : function(){
14508 return this.enabled;
14512 * Enables this KeyMap
14514 enable: function(){
14516 this.el.on(this.eventName, this.handleKeyDown, this);
14517 this.enabled = true;
14522 * Disable this KeyMap
14524 disable: function(){
14526 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14527 this.enabled = false;
14532 * Ext JS Library 1.1.1
14533 * Copyright(c) 2006-2007, Ext JS, LLC.
14535 * Originally Released Under LGPL - original licence link has changed is not relivant.
14538 * <script type="text/javascript">
14543 * @class Roo.util.TextMetrics
14544 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14545 * wide, in pixels, a given block of text will be.
14548 Roo.util.TextMetrics = function(){
14552 * Measures the size of the specified text
14553 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14554 * that can affect the size of the rendered text
14555 * @param {String} text The text to measure
14556 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14557 * in order to accurately measure the text height
14558 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14560 measure : function(el, text, fixedWidth){
14562 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14565 shared.setFixedWidth(fixedWidth || 'auto');
14566 return shared.getSize(text);
14570 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14571 * the overhead of multiple calls to initialize the style properties on each measurement.
14572 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14573 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14574 * in order to accurately measure the text height
14575 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14577 createInstance : function(el, fixedWidth){
14578 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14585 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14586 var ml = new Roo.Element(document.createElement('div'));
14587 document.body.appendChild(ml.dom);
14588 ml.position('absolute');
14589 ml.setLeftTop(-1000, -1000);
14593 ml.setWidth(fixedWidth);
14598 * Returns the size of the specified text based on the internal element's style and width properties
14599 * @memberOf Roo.util.TextMetrics.Instance#
14600 * @param {String} text The text to measure
14601 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14603 getSize : function(text){
14605 var s = ml.getSize();
14611 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14612 * that can affect the size of the rendered text
14613 * @memberOf Roo.util.TextMetrics.Instance#
14614 * @param {String/HTMLElement} el The element, dom node or id
14616 bind : function(el){
14618 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14623 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14624 * to set a fixed width in order to accurately measure the text height.
14625 * @memberOf Roo.util.TextMetrics.Instance#
14626 * @param {Number} width The width to set on the element
14628 setFixedWidth : function(width){
14629 ml.setWidth(width);
14633 * Returns the measured width of the specified text
14634 * @memberOf Roo.util.TextMetrics.Instance#
14635 * @param {String} text The text to measure
14636 * @return {Number} width The width in pixels
14638 getWidth : function(text){
14639 ml.dom.style.width = 'auto';
14640 return this.getSize(text).width;
14644 * Returns the measured height of the specified text. For multiline text, be sure to call
14645 * {@link #setFixedWidth} if necessary.
14646 * @memberOf Roo.util.TextMetrics.Instance#
14647 * @param {String} text The text to measure
14648 * @return {Number} height The height in pixels
14650 getHeight : function(text){
14651 return this.getSize(text).height;
14655 instance.bind(bindTo);
14660 // backwards compat
14661 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14663 * Ext JS Library 1.1.1
14664 * Copyright(c) 2006-2007, Ext JS, LLC.
14666 * Originally Released Under LGPL - original licence link has changed is not relivant.
14669 * <script type="text/javascript">
14673 * @class Roo.state.Provider
14674 * Abstract base class for state provider implementations. This class provides methods
14675 * for encoding and decoding <b>typed</b> variables including dates and defines the
14676 * Provider interface.
14678 Roo.state.Provider = function(){
14680 * @event statechange
14681 * Fires when a state change occurs.
14682 * @param {Provider} this This state provider
14683 * @param {String} key The state key which was changed
14684 * @param {String} value The encoded value for the state
14687 "statechange": true
14690 Roo.state.Provider.superclass.constructor.call(this);
14692 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14694 * Returns the current value for a key
14695 * @param {String} name The key name
14696 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14697 * @return {Mixed} The state data
14699 get : function(name, defaultValue){
14700 return typeof this.state[name] == "undefined" ?
14701 defaultValue : this.state[name];
14705 * Clears a value from the state
14706 * @param {String} name The key name
14708 clear : function(name){
14709 delete this.state[name];
14710 this.fireEvent("statechange", this, name, null);
14714 * Sets the value for a key
14715 * @param {String} name The key name
14716 * @param {Mixed} value The value to set
14718 set : function(name, value){
14719 this.state[name] = value;
14720 this.fireEvent("statechange", this, name, value);
14724 * Decodes a string previously encoded with {@link #encodeValue}.
14725 * @param {String} value The value to decode
14726 * @return {Mixed} The decoded value
14728 decodeValue : function(cookie){
14729 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14730 var matches = re.exec(unescape(cookie));
14731 if(!matches || !matches[1]) return; // non state cookie
14732 var type = matches[1];
14733 var v = matches[2];
14736 return parseFloat(v);
14738 return new Date(Date.parse(v));
14743 var values = v.split("^");
14744 for(var i = 0, len = values.length; i < len; i++){
14745 all.push(this.decodeValue(values[i]));
14750 var values = v.split("^");
14751 for(var i = 0, len = values.length; i < len; i++){
14752 var kv = values[i].split("=");
14753 all[kv[0]] = this.decodeValue(kv[1]);
14762 * Encodes a value including type information. Decode with {@link #decodeValue}.
14763 * @param {Mixed} value The value to encode
14764 * @return {String} The encoded value
14766 encodeValue : function(v){
14768 if(typeof v == "number"){
14770 }else if(typeof v == "boolean"){
14771 enc = "b:" + (v ? "1" : "0");
14772 }else if(v instanceof Date){
14773 enc = "d:" + v.toGMTString();
14774 }else if(v instanceof Array){
14776 for(var i = 0, len = v.length; i < len; i++){
14777 flat += this.encodeValue(v[i]);
14778 if(i != len-1) flat += "^";
14781 }else if(typeof v == "object"){
14784 if(typeof v[key] != "function"){
14785 flat += key + "=" + this.encodeValue(v[key]) + "^";
14788 enc = "o:" + flat.substring(0, flat.length-1);
14792 return escape(enc);
14798 * Ext JS Library 1.1.1
14799 * Copyright(c) 2006-2007, Ext JS, LLC.
14801 * Originally Released Under LGPL - original licence link has changed is not relivant.
14804 * <script type="text/javascript">
14807 * @class Roo.state.Manager
14808 * This is the global state manager. By default all components that are "state aware" check this class
14809 * for state information if you don't pass them a custom state provider. In order for this class
14810 * to be useful, it must be initialized with a provider when your application initializes.
14812 // in your initialization function
14814 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14816 // supposed you have a {@link Roo.BorderLayout}
14817 var layout = new Roo.BorderLayout(...);
14818 layout.restoreState();
14819 // or a {Roo.BasicDialog}
14820 var dialog = new Roo.BasicDialog(...);
14821 dialog.restoreState();
14825 Roo.state.Manager = function(){
14826 var provider = new Roo.state.Provider();
14830 * Configures the default state provider for your application
14831 * @param {Provider} stateProvider The state provider to set
14833 setProvider : function(stateProvider){
14834 provider = stateProvider;
14838 * Returns the current value for a key
14839 * @param {String} name The key name
14840 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14841 * @return {Mixed} The state data
14843 get : function(key, defaultValue){
14844 return provider.get(key, defaultValue);
14848 * Sets the value for a key
14849 * @param {String} name The key name
14850 * @param {Mixed} value The state data
14852 set : function(key, value){
14853 provider.set(key, value);
14857 * Clears a value from the state
14858 * @param {String} name The key name
14860 clear : function(key){
14861 provider.clear(key);
14865 * Gets the currently configured state provider
14866 * @return {Provider} The state provider
14868 getProvider : function(){
14875 * Ext JS Library 1.1.1
14876 * Copyright(c) 2006-2007, Ext JS, LLC.
14878 * Originally Released Under LGPL - original licence link has changed is not relivant.
14881 * <script type="text/javascript">
14884 * @class Roo.state.CookieProvider
14885 * @extends Roo.state.Provider
14886 * The default Provider implementation which saves state via cookies.
14889 var cp = new Roo.state.CookieProvider({
14891 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14892 domain: "roojs.com"
14894 Roo.state.Manager.setProvider(cp);
14896 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14897 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14898 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14899 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14900 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14901 * domain the page is running on including the 'www' like 'www.roojs.com')
14902 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14904 * Create a new CookieProvider
14905 * @param {Object} config The configuration object
14907 Roo.state.CookieProvider = function(config){
14908 Roo.state.CookieProvider.superclass.constructor.call(this);
14910 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14911 this.domain = null;
14912 this.secure = false;
14913 Roo.apply(this, config);
14914 this.state = this.readCookies();
14917 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14919 set : function(name, value){
14920 if(typeof value == "undefined" || value === null){
14924 this.setCookie(name, value);
14925 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14929 clear : function(name){
14930 this.clearCookie(name);
14931 Roo.state.CookieProvider.superclass.clear.call(this, name);
14935 readCookies : function(){
14937 var c = document.cookie + ";";
14938 var re = /\s?(.*?)=(.*?);/g;
14940 while((matches = re.exec(c)) != null){
14941 var name = matches[1];
14942 var value = matches[2];
14943 if(name && name.substring(0,3) == "ys-"){
14944 cookies[name.substr(3)] = this.decodeValue(value);
14951 setCookie : function(name, value){
14952 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14953 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14954 ((this.path == null) ? "" : ("; path=" + this.path)) +
14955 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14956 ((this.secure == true) ? "; secure" : "");
14960 clearCookie : function(name){
14961 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14962 ((this.path == null) ? "" : ("; path=" + this.path)) +
14963 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14964 ((this.secure == true) ? "; secure" : "");
14968 * Ext JS Library 1.1.1
14969 * Copyright(c) 2006-2007, Ext JS, LLC.
14971 * Originally Released Under LGPL - original licence link has changed is not relivant.
14974 * <script type="text/javascript">
14980 * These classes are derivatives of the similarly named classes in the YUI Library.
14981 * The original license:
14982 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14983 * Code licensed under the BSD License:
14984 * http://developer.yahoo.net/yui/license.txt
14989 var Event=Roo.EventManager;
14990 var Dom=Roo.lib.Dom;
14993 * @class Roo.dd.DragDrop
14994 * @extends Roo.util.Observable
14995 * Defines the interface and base operation of items that that can be
14996 * dragged or can be drop targets. It was designed to be extended, overriding
14997 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14998 * Up to three html elements can be associated with a DragDrop instance:
15000 * <li>linked element: the element that is passed into the constructor.
15001 * This is the element which defines the boundaries for interaction with
15002 * other DragDrop objects.</li>
15003 * <li>handle element(s): The drag operation only occurs if the element that
15004 * was clicked matches a handle element. By default this is the linked
15005 * element, but there are times that you will want only a portion of the
15006 * linked element to initiate the drag operation, and the setHandleElId()
15007 * method provides a way to define this.</li>
15008 * <li>drag element: this represents the element that would be moved along
15009 * with the cursor during a drag operation. By default, this is the linked
15010 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
15011 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
15014 * This class should not be instantiated until the onload event to ensure that
15015 * the associated elements are available.
15016 * The following would define a DragDrop obj that would interact with any
15017 * other DragDrop obj in the "group1" group:
15019 * dd = new Roo.dd.DragDrop("div1", "group1");
15021 * Since none of the event handlers have been implemented, nothing would
15022 * actually happen if you were to run the code above. Normally you would
15023 * override this class or one of the default implementations, but you can
15024 * also override the methods you want on an instance of the class...
15026 * dd.onDragDrop = function(e, id) {
15027 * alert("dd was dropped on " + id);
15031 * @param {String} id of the element that is linked to this instance
15032 * @param {String} sGroup the group of related DragDrop objects
15033 * @param {object} config an object containing configurable attributes
15034 * Valid properties for DragDrop:
15035 * padding, isTarget, maintainOffset, primaryButtonOnly
15037 Roo.dd.DragDrop = function(id, sGroup, config) {
15039 this.init(id, sGroup, config);
15044 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15047 * The id of the element associated with this object. This is what we
15048 * refer to as the "linked element" because the size and position of
15049 * this element is used to determine when the drag and drop objects have
15057 * Configuration attributes passed into the constructor
15064 * The id of the element that will be dragged. By default this is same
15065 * as the linked element , but could be changed to another element. Ex:
15067 * @property dragElId
15074 * the id of the element that initiates the drag operation. By default
15075 * this is the linked element, but could be changed to be a child of this
15076 * element. This lets us do things like only starting the drag when the
15077 * header element within the linked html element is clicked.
15078 * @property handleElId
15085 * An associative array of HTML tags that will be ignored if clicked.
15086 * @property invalidHandleTypes
15087 * @type {string: string}
15089 invalidHandleTypes: null,
15092 * An associative array of ids for elements that will be ignored if clicked
15093 * @property invalidHandleIds
15094 * @type {string: string}
15096 invalidHandleIds: null,
15099 * An indexted array of css class names for elements that will be ignored
15101 * @property invalidHandleClasses
15104 invalidHandleClasses: null,
15107 * The linked element's absolute X position at the time the drag was
15109 * @property startPageX
15116 * The linked element's absolute X position at the time the drag was
15118 * @property startPageY
15125 * The group defines a logical collection of DragDrop objects that are
15126 * related. Instances only get events when interacting with other
15127 * DragDrop object in the same group. This lets us define multiple
15128 * groups using a single DragDrop subclass if we want.
15130 * @type {string: string}
15135 * Individual drag/drop instances can be locked. This will prevent
15136 * onmousedown start drag.
15144 * Lock this instance
15147 lock: function() { this.locked = true; },
15150 * Unlock this instace
15153 unlock: function() { this.locked = false; },
15156 * By default, all insances can be a drop target. This can be disabled by
15157 * setting isTarget to false.
15164 * The padding configured for this drag and drop object for calculating
15165 * the drop zone intersection with this object.
15172 * Cached reference to the linked element
15173 * @property _domRef
15179 * Internal typeof flag
15180 * @property __ygDragDrop
15183 __ygDragDrop: true,
15186 * Set to true when horizontal contraints are applied
15187 * @property constrainX
15194 * Set to true when vertical contraints are applied
15195 * @property constrainY
15202 * The left constraint
15210 * The right constraint
15218 * The up constraint
15227 * The down constraint
15235 * Maintain offsets when we resetconstraints. Set to true when you want
15236 * the position of the element relative to its parent to stay the same
15237 * when the page changes
15239 * @property maintainOffset
15242 maintainOffset: false,
15245 * Array of pixel locations the element will snap to if we specified a
15246 * horizontal graduation/interval. This array is generated automatically
15247 * when you define a tick interval.
15254 * Array of pixel locations the element will snap to if we specified a
15255 * vertical graduation/interval. This array is generated automatically
15256 * when you define a tick interval.
15263 * By default the drag and drop instance will only respond to the primary
15264 * button click (left button for a right-handed mouse). Set to true to
15265 * allow drag and drop to start with any mouse click that is propogated
15267 * @property primaryButtonOnly
15270 primaryButtonOnly: true,
15273 * The availabe property is false until the linked dom element is accessible.
15274 * @property available
15280 * By default, drags can only be initiated if the mousedown occurs in the
15281 * region the linked element is. This is done in part to work around a
15282 * bug in some browsers that mis-report the mousedown if the previous
15283 * mouseup happened outside of the window. This property is set to true
15284 * if outer handles are defined.
15286 * @property hasOuterHandles
15290 hasOuterHandles: false,
15293 * Code that executes immediately before the startDrag event
15294 * @method b4StartDrag
15297 b4StartDrag: function(x, y) { },
15300 * Abstract method called after a drag/drop object is clicked
15301 * and the drag or mousedown time thresholds have beeen met.
15302 * @method startDrag
15303 * @param {int} X click location
15304 * @param {int} Y click location
15306 startDrag: function(x, y) { /* override this */ },
15309 * Code that executes immediately before the onDrag event
15313 b4Drag: function(e) { },
15316 * Abstract method called during the onMouseMove event while dragging an
15319 * @param {Event} e the mousemove event
15321 onDrag: function(e) { /* override this */ },
15324 * Abstract method called when this element fist begins hovering over
15325 * another DragDrop obj
15326 * @method onDragEnter
15327 * @param {Event} e the mousemove event
15328 * @param {String|DragDrop[]} id In POINT mode, the element
15329 * id this is hovering over. In INTERSECT mode, an array of one or more
15330 * dragdrop items being hovered over.
15332 onDragEnter: function(e, id) { /* override this */ },
15335 * Code that executes immediately before the onDragOver event
15336 * @method b4DragOver
15339 b4DragOver: function(e) { },
15342 * Abstract method called when this element is hovering over another
15344 * @method onDragOver
15345 * @param {Event} e the mousemove event
15346 * @param {String|DragDrop[]} id In POINT mode, the element
15347 * id this is hovering over. In INTERSECT mode, an array of dd items
15348 * being hovered over.
15350 onDragOver: function(e, id) { /* override this */ },
15353 * Code that executes immediately before the onDragOut event
15354 * @method b4DragOut
15357 b4DragOut: function(e) { },
15360 * Abstract method called when we are no longer hovering over an element
15361 * @method onDragOut
15362 * @param {Event} e the mousemove event
15363 * @param {String|DragDrop[]} id In POINT mode, the element
15364 * id this was hovering over. In INTERSECT mode, an array of dd items
15365 * that the mouse is no longer over.
15367 onDragOut: function(e, id) { /* override this */ },
15370 * Code that executes immediately before the onDragDrop event
15371 * @method b4DragDrop
15374 b4DragDrop: function(e) { },
15377 * Abstract method called when this item is dropped on another DragDrop
15379 * @method onDragDrop
15380 * @param {Event} e the mouseup event
15381 * @param {String|DragDrop[]} id In POINT mode, the element
15382 * id this was dropped on. In INTERSECT mode, an array of dd items this
15385 onDragDrop: function(e, id) { /* override this */ },
15388 * Abstract method called when this item is dropped on an area with no
15390 * @method onInvalidDrop
15391 * @param {Event} e the mouseup event
15393 onInvalidDrop: function(e) { /* override this */ },
15396 * Code that executes immediately before the endDrag event
15397 * @method b4EndDrag
15400 b4EndDrag: function(e) { },
15403 * Fired when we are done dragging the object
15405 * @param {Event} e the mouseup event
15407 endDrag: function(e) { /* override this */ },
15410 * Code executed immediately before the onMouseDown event
15411 * @method b4MouseDown
15412 * @param {Event} e the mousedown event
15415 b4MouseDown: function(e) { },
15418 * Event handler that fires when a drag/drop obj gets a mousedown
15419 * @method onMouseDown
15420 * @param {Event} e the mousedown event
15422 onMouseDown: function(e) { /* override this */ },
15425 * Event handler that fires when a drag/drop obj gets a mouseup
15426 * @method onMouseUp
15427 * @param {Event} e the mouseup event
15429 onMouseUp: function(e) { /* override this */ },
15432 * Override the onAvailable method to do what is needed after the initial
15433 * position was determined.
15434 * @method onAvailable
15436 onAvailable: function () {
15440 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15443 defaultPadding : {left:0, right:0, top:0, bottom:0},
15446 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15450 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15451 { dragElId: "existingProxyDiv" });
15452 dd.startDrag = function(){
15453 this.constrainTo("parent-id");
15456 * Or you can initalize it using the {@link Roo.Element} object:
15458 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15459 startDrag : function(){
15460 this.constrainTo("parent-id");
15464 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15465 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15466 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15467 * an object containing the sides to pad. For example: {right:10, bottom:10}
15468 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15470 constrainTo : function(constrainTo, pad, inContent){
15471 if(typeof pad == "number"){
15472 pad = {left: pad, right:pad, top:pad, bottom:pad};
15474 pad = pad || this.defaultPadding;
15475 var b = Roo.get(this.getEl()).getBox();
15476 var ce = Roo.get(constrainTo);
15477 var s = ce.getScroll();
15478 var c, cd = ce.dom;
15479 if(cd == document.body){
15480 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15483 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15487 var topSpace = b.y - c.y;
15488 var leftSpace = b.x - c.x;
15490 this.resetConstraints();
15491 this.setXConstraint(leftSpace - (pad.left||0), // left
15492 c.width - leftSpace - b.width - (pad.right||0) //right
15494 this.setYConstraint(topSpace - (pad.top||0), //top
15495 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15500 * Returns a reference to the linked element
15502 * @return {HTMLElement} the html element
15504 getEl: function() {
15505 if (!this._domRef) {
15506 this._domRef = Roo.getDom(this.id);
15509 return this._domRef;
15513 * Returns a reference to the actual element to drag. By default this is
15514 * the same as the html element, but it can be assigned to another
15515 * element. An example of this can be found in Roo.dd.DDProxy
15516 * @method getDragEl
15517 * @return {HTMLElement} the html element
15519 getDragEl: function() {
15520 return Roo.getDom(this.dragElId);
15524 * Sets up the DragDrop object. Must be called in the constructor of any
15525 * Roo.dd.DragDrop subclass
15527 * @param id the id of the linked element
15528 * @param {String} sGroup the group of related items
15529 * @param {object} config configuration attributes
15531 init: function(id, sGroup, config) {
15532 this.initTarget(id, sGroup, config);
15533 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15534 // Event.on(this.id, "selectstart", Event.preventDefault);
15538 * Initializes Targeting functionality only... the object does not
15539 * get a mousedown handler.
15540 * @method initTarget
15541 * @param id the id of the linked element
15542 * @param {String} sGroup the group of related items
15543 * @param {object} config configuration attributes
15545 initTarget: function(id, sGroup, config) {
15547 // configuration attributes
15548 this.config = config || {};
15550 // create a local reference to the drag and drop manager
15551 this.DDM = Roo.dd.DDM;
15552 // initialize the groups array
15555 // assume that we have an element reference instead of an id if the
15556 // parameter is not a string
15557 if (typeof id !== "string") {
15564 // add to an interaction group
15565 this.addToGroup((sGroup) ? sGroup : "default");
15567 // We don't want to register this as the handle with the manager
15568 // so we just set the id rather than calling the setter.
15569 this.handleElId = id;
15571 // the linked element is the element that gets dragged by default
15572 this.setDragElId(id);
15574 // by default, clicked anchors will not start drag operations.
15575 this.invalidHandleTypes = { A: "A" };
15576 this.invalidHandleIds = {};
15577 this.invalidHandleClasses = [];
15579 this.applyConfig();
15581 this.handleOnAvailable();
15585 * Applies the configuration parameters that were passed into the constructor.
15586 * This is supposed to happen at each level through the inheritance chain. So
15587 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15588 * DragDrop in order to get all of the parameters that are available in
15590 * @method applyConfig
15592 applyConfig: function() {
15594 // configurable properties:
15595 // padding, isTarget, maintainOffset, primaryButtonOnly
15596 this.padding = this.config.padding || [0, 0, 0, 0];
15597 this.isTarget = (this.config.isTarget !== false);
15598 this.maintainOffset = (this.config.maintainOffset);
15599 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15604 * Executed when the linked element is available
15605 * @method handleOnAvailable
15608 handleOnAvailable: function() {
15609 this.available = true;
15610 this.resetConstraints();
15611 this.onAvailable();
15615 * Configures the padding for the target zone in px. Effectively expands
15616 * (or reduces) the virtual object size for targeting calculations.
15617 * Supports css-style shorthand; if only one parameter is passed, all sides
15618 * will have that padding, and if only two are passed, the top and bottom
15619 * will have the first param, the left and right the second.
15620 * @method setPadding
15621 * @param {int} iTop Top pad
15622 * @param {int} iRight Right pad
15623 * @param {int} iBot Bot pad
15624 * @param {int} iLeft Left pad
15626 setPadding: function(iTop, iRight, iBot, iLeft) {
15627 // this.padding = [iLeft, iRight, iTop, iBot];
15628 if (!iRight && 0 !== iRight) {
15629 this.padding = [iTop, iTop, iTop, iTop];
15630 } else if (!iBot && 0 !== iBot) {
15631 this.padding = [iTop, iRight, iTop, iRight];
15633 this.padding = [iTop, iRight, iBot, iLeft];
15638 * Stores the initial placement of the linked element.
15639 * @method setInitialPosition
15640 * @param {int} diffX the X offset, default 0
15641 * @param {int} diffY the Y offset, default 0
15643 setInitPosition: function(diffX, diffY) {
15644 var el = this.getEl();
15646 if (!this.DDM.verifyEl(el)) {
15650 var dx = diffX || 0;
15651 var dy = diffY || 0;
15653 var p = Dom.getXY( el );
15655 this.initPageX = p[0] - dx;
15656 this.initPageY = p[1] - dy;
15658 this.lastPageX = p[0];
15659 this.lastPageY = p[1];
15662 this.setStartPosition(p);
15666 * Sets the start position of the element. This is set when the obj
15667 * is initialized, the reset when a drag is started.
15668 * @method setStartPosition
15669 * @param pos current position (from previous lookup)
15672 setStartPosition: function(pos) {
15673 var p = pos || Dom.getXY( this.getEl() );
15674 this.deltaSetXY = null;
15676 this.startPageX = p[0];
15677 this.startPageY = p[1];
15681 * Add this instance to a group of related drag/drop objects. All
15682 * instances belong to at least one group, and can belong to as many
15683 * groups as needed.
15684 * @method addToGroup
15685 * @param sGroup {string} the name of the group
15687 addToGroup: function(sGroup) {
15688 this.groups[sGroup] = true;
15689 this.DDM.regDragDrop(this, sGroup);
15693 * Remove's this instance from the supplied interaction group
15694 * @method removeFromGroup
15695 * @param {string} sGroup The group to drop
15697 removeFromGroup: function(sGroup) {
15698 if (this.groups[sGroup]) {
15699 delete this.groups[sGroup];
15702 this.DDM.removeDDFromGroup(this, sGroup);
15706 * Allows you to specify that an element other than the linked element
15707 * will be moved with the cursor during a drag
15708 * @method setDragElId
15709 * @param id {string} the id of the element that will be used to initiate the drag
15711 setDragElId: function(id) {
15712 this.dragElId = id;
15716 * Allows you to specify a child of the linked element that should be
15717 * used to initiate the drag operation. An example of this would be if
15718 * you have a content div with text and links. Clicking anywhere in the
15719 * content area would normally start the drag operation. Use this method
15720 * to specify that an element inside of the content div is the element
15721 * that starts the drag operation.
15722 * @method setHandleElId
15723 * @param id {string} the id of the element that will be used to
15724 * initiate the drag.
15726 setHandleElId: function(id) {
15727 if (typeof id !== "string") {
15730 this.handleElId = id;
15731 this.DDM.regHandle(this.id, id);
15735 * Allows you to set an element outside of the linked element as a drag
15737 * @method setOuterHandleElId
15738 * @param id the id of the element that will be used to initiate the drag
15740 setOuterHandleElId: function(id) {
15741 if (typeof id !== "string") {
15744 Event.on(id, "mousedown",
15745 this.handleMouseDown, this);
15746 this.setHandleElId(id);
15748 this.hasOuterHandles = true;
15752 * Remove all drag and drop hooks for this element
15755 unreg: function() {
15756 Event.un(this.id, "mousedown",
15757 this.handleMouseDown);
15758 this._domRef = null;
15759 this.DDM._remove(this);
15762 destroy : function(){
15767 * Returns true if this instance is locked, or the drag drop mgr is locked
15768 * (meaning that all drag/drop is disabled on the page.)
15770 * @return {boolean} true if this obj or all drag/drop is locked, else
15773 isLocked: function() {
15774 return (this.DDM.isLocked() || this.locked);
15778 * Fired when this object is clicked
15779 * @method handleMouseDown
15781 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15784 handleMouseDown: function(e, oDD){
15785 if (this.primaryButtonOnly && e.button != 0) {
15789 if (this.isLocked()) {
15793 this.DDM.refreshCache(this.groups);
15795 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15796 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15798 if (this.clickValidator(e)) {
15800 // set the initial element position
15801 this.setStartPosition();
15804 this.b4MouseDown(e);
15805 this.onMouseDown(e);
15807 this.DDM.handleMouseDown(e, this);
15809 this.DDM.stopEvent(e);
15817 clickValidator: function(e) {
15818 var target = e.getTarget();
15819 return ( this.isValidHandleChild(target) &&
15820 (this.id == this.handleElId ||
15821 this.DDM.handleWasClicked(target, this.id)) );
15825 * Allows you to specify a tag name that should not start a drag operation
15826 * when clicked. This is designed to facilitate embedding links within a
15827 * drag handle that do something other than start the drag.
15828 * @method addInvalidHandleType
15829 * @param {string} tagName the type of element to exclude
15831 addInvalidHandleType: function(tagName) {
15832 var type = tagName.toUpperCase();
15833 this.invalidHandleTypes[type] = type;
15837 * Lets you to specify an element id for a child of a drag handle
15838 * that should not initiate a drag
15839 * @method addInvalidHandleId
15840 * @param {string} id the element id of the element you wish to ignore
15842 addInvalidHandleId: function(id) {
15843 if (typeof id !== "string") {
15846 this.invalidHandleIds[id] = id;
15850 * Lets you specify a css class of elements that will not initiate a drag
15851 * @method addInvalidHandleClass
15852 * @param {string} cssClass the class of the elements you wish to ignore
15854 addInvalidHandleClass: function(cssClass) {
15855 this.invalidHandleClasses.push(cssClass);
15859 * Unsets an excluded tag name set by addInvalidHandleType
15860 * @method removeInvalidHandleType
15861 * @param {string} tagName the type of element to unexclude
15863 removeInvalidHandleType: function(tagName) {
15864 var type = tagName.toUpperCase();
15865 // this.invalidHandleTypes[type] = null;
15866 delete this.invalidHandleTypes[type];
15870 * Unsets an invalid handle id
15871 * @method removeInvalidHandleId
15872 * @param {string} id the id of the element to re-enable
15874 removeInvalidHandleId: function(id) {
15875 if (typeof id !== "string") {
15878 delete this.invalidHandleIds[id];
15882 * Unsets an invalid css class
15883 * @method removeInvalidHandleClass
15884 * @param {string} cssClass the class of the element(s) you wish to
15887 removeInvalidHandleClass: function(cssClass) {
15888 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15889 if (this.invalidHandleClasses[i] == cssClass) {
15890 delete this.invalidHandleClasses[i];
15896 * Checks the tag exclusion list to see if this click should be ignored
15897 * @method isValidHandleChild
15898 * @param {HTMLElement} node the HTMLElement to evaluate
15899 * @return {boolean} true if this is a valid tag type, false if not
15901 isValidHandleChild: function(node) {
15904 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15907 nodeName = node.nodeName.toUpperCase();
15909 nodeName = node.nodeName;
15911 valid = valid && !this.invalidHandleTypes[nodeName];
15912 valid = valid && !this.invalidHandleIds[node.id];
15914 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15915 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15924 * Create the array of horizontal tick marks if an interval was specified
15925 * in setXConstraint().
15926 * @method setXTicks
15929 setXTicks: function(iStartX, iTickSize) {
15931 this.xTickSize = iTickSize;
15935 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15937 this.xTicks[this.xTicks.length] = i;
15942 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15944 this.xTicks[this.xTicks.length] = i;
15949 this.xTicks.sort(this.DDM.numericSort) ;
15953 * Create the array of vertical tick marks if an interval was specified in
15954 * setYConstraint().
15955 * @method setYTicks
15958 setYTicks: function(iStartY, iTickSize) {
15960 this.yTickSize = iTickSize;
15964 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15966 this.yTicks[this.yTicks.length] = i;
15971 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15973 this.yTicks[this.yTicks.length] = i;
15978 this.yTicks.sort(this.DDM.numericSort) ;
15982 * By default, the element can be dragged any place on the screen. Use
15983 * this method to limit the horizontal travel of the element. Pass in
15984 * 0,0 for the parameters if you want to lock the drag to the y axis.
15985 * @method setXConstraint
15986 * @param {int} iLeft the number of pixels the element can move to the left
15987 * @param {int} iRight the number of pixels the element can move to the
15989 * @param {int} iTickSize optional parameter for specifying that the
15991 * should move iTickSize pixels at a time.
15993 setXConstraint: function(iLeft, iRight, iTickSize) {
15994 this.leftConstraint = iLeft;
15995 this.rightConstraint = iRight;
15997 this.minX = this.initPageX - iLeft;
15998 this.maxX = this.initPageX + iRight;
15999 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
16001 this.constrainX = true;
16005 * Clears any constraints applied to this instance. Also clears ticks
16006 * since they can't exist independent of a constraint at this time.
16007 * @method clearConstraints
16009 clearConstraints: function() {
16010 this.constrainX = false;
16011 this.constrainY = false;
16016 * Clears any tick interval defined for this instance
16017 * @method clearTicks
16019 clearTicks: function() {
16020 this.xTicks = null;
16021 this.yTicks = null;
16022 this.xTickSize = 0;
16023 this.yTickSize = 0;
16027 * By default, the element can be dragged any place on the screen. Set
16028 * this to limit the vertical travel of the element. Pass in 0,0 for the
16029 * parameters if you want to lock the drag to the x axis.
16030 * @method setYConstraint
16031 * @param {int} iUp the number of pixels the element can move up
16032 * @param {int} iDown the number of pixels the element can move down
16033 * @param {int} iTickSize optional parameter for specifying that the
16034 * element should move iTickSize pixels at a time.
16036 setYConstraint: function(iUp, iDown, iTickSize) {
16037 this.topConstraint = iUp;
16038 this.bottomConstraint = iDown;
16040 this.minY = this.initPageY - iUp;
16041 this.maxY = this.initPageY + iDown;
16042 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16044 this.constrainY = true;
16049 * resetConstraints must be called if you manually reposition a dd element.
16050 * @method resetConstraints
16051 * @param {boolean} maintainOffset
16053 resetConstraints: function() {
16056 // Maintain offsets if necessary
16057 if (this.initPageX || this.initPageX === 0) {
16058 // figure out how much this thing has moved
16059 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16060 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16062 this.setInitPosition(dx, dy);
16064 // This is the first time we have detected the element's position
16066 this.setInitPosition();
16069 if (this.constrainX) {
16070 this.setXConstraint( this.leftConstraint,
16071 this.rightConstraint,
16075 if (this.constrainY) {
16076 this.setYConstraint( this.topConstraint,
16077 this.bottomConstraint,
16083 * Normally the drag element is moved pixel by pixel, but we can specify
16084 * that it move a number of pixels at a time. This method resolves the
16085 * location when we have it set up like this.
16087 * @param {int} val where we want to place the object
16088 * @param {int[]} tickArray sorted array of valid points
16089 * @return {int} the closest tick
16092 getTick: function(val, tickArray) {
16095 // If tick interval is not defined, it is effectively 1 pixel,
16096 // so we return the value passed to us.
16098 } else if (tickArray[0] >= val) {
16099 // The value is lower than the first tick, so we return the first
16101 return tickArray[0];
16103 for (var i=0, len=tickArray.length; i<len; ++i) {
16105 if (tickArray[next] && tickArray[next] >= val) {
16106 var diff1 = val - tickArray[i];
16107 var diff2 = tickArray[next] - val;
16108 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16112 // The value is larger than the last tick, so we return the last
16114 return tickArray[tickArray.length - 1];
16121 * @return {string} string representation of the dd obj
16123 toString: function() {
16124 return ("DragDrop " + this.id);
16132 * Ext JS Library 1.1.1
16133 * Copyright(c) 2006-2007, Ext JS, LLC.
16135 * Originally Released Under LGPL - original licence link has changed is not relivant.
16138 * <script type="text/javascript">
16143 * The drag and drop utility provides a framework for building drag and drop
16144 * applications. In addition to enabling drag and drop for specific elements,
16145 * the drag and drop elements are tracked by the manager class, and the
16146 * interactions between the various elements are tracked during the drag and
16147 * the implementing code is notified about these important moments.
16150 // Only load the library once. Rewriting the manager class would orphan
16151 // existing drag and drop instances.
16152 if (!Roo.dd.DragDropMgr) {
16155 * @class Roo.dd.DragDropMgr
16156 * DragDropMgr is a singleton that tracks the element interaction for
16157 * all DragDrop items in the window. Generally, you will not call
16158 * this class directly, but it does have helper methods that could
16159 * be useful in your DragDrop implementations.
16162 Roo.dd.DragDropMgr = function() {
16164 var Event = Roo.EventManager;
16169 * Two dimensional Array of registered DragDrop objects. The first
16170 * dimension is the DragDrop item group, the second the DragDrop
16173 * @type {string: string}
16180 * Array of element ids defined as drag handles. Used to determine
16181 * if the element that generated the mousedown event is actually the
16182 * handle and not the html element itself.
16183 * @property handleIds
16184 * @type {string: string}
16191 * the DragDrop object that is currently being dragged
16192 * @property dragCurrent
16200 * the DragDrop object(s) that are being hovered over
16201 * @property dragOvers
16209 * the X distance between the cursor and the object being dragged
16218 * the Y distance between the cursor and the object being dragged
16227 * Flag to determine if we should prevent the default behavior of the
16228 * events we define. By default this is true, but this can be set to
16229 * false if you need the default behavior (not recommended)
16230 * @property preventDefault
16234 preventDefault: true,
16237 * Flag to determine if we should stop the propagation of the events
16238 * we generate. This is true by default but you may want to set it to
16239 * false if the html element contains other features that require the
16241 * @property stopPropagation
16245 stopPropagation: true,
16248 * Internal flag that is set to true when drag and drop has been
16250 * @property initialized
16257 * All drag and drop can be disabled.
16265 * Called the first time an element is registered.
16271 this.initialized = true;
16275 * In point mode, drag and drop interaction is defined by the
16276 * location of the cursor during the drag/drop
16284 * In intersect mode, drag and drop interactio nis defined by the
16285 * overlap of two or more drag and drop objects.
16286 * @property INTERSECT
16293 * The current drag and drop mode. Default: POINT
16301 * Runs method on all drag and drop objects
16302 * @method _execOnAll
16306 _execOnAll: function(sMethod, args) {
16307 for (var i in this.ids) {
16308 for (var j in this.ids[i]) {
16309 var oDD = this.ids[i][j];
16310 if (! this.isTypeOfDD(oDD)) {
16313 oDD[sMethod].apply(oDD, args);
16319 * Drag and drop initialization. Sets up the global event handlers
16324 _onLoad: function() {
16329 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16330 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16331 Event.on(window, "unload", this._onUnload, this, true);
16332 Event.on(window, "resize", this._onResize, this, true);
16333 // Event.on(window, "mouseout", this._test);
16338 * Reset constraints on all drag and drop objs
16339 * @method _onResize
16343 _onResize: function(e) {
16344 this._execOnAll("resetConstraints", []);
16348 * Lock all drag and drop functionality
16352 lock: function() { this.locked = true; },
16355 * Unlock all drag and drop functionality
16359 unlock: function() { this.locked = false; },
16362 * Is drag and drop locked?
16364 * @return {boolean} True if drag and drop is locked, false otherwise.
16367 isLocked: function() { return this.locked; },
16370 * Location cache that is set for all drag drop objects when a drag is
16371 * initiated, cleared when the drag is finished.
16372 * @property locationCache
16379 * Set useCache to false if you want to force object the lookup of each
16380 * drag and drop linked element constantly during a drag.
16381 * @property useCache
16388 * The number of pixels that the mouse needs to move after the
16389 * mousedown before the drag is initiated. Default=3;
16390 * @property clickPixelThresh
16394 clickPixelThresh: 3,
16397 * The number of milliseconds after the mousedown event to initiate the
16398 * drag if we don't get a mouseup event. Default=1000
16399 * @property clickTimeThresh
16403 clickTimeThresh: 350,
16406 * Flag that indicates that either the drag pixel threshold or the
16407 * mousdown time threshold has been met
16408 * @property dragThreshMet
16413 dragThreshMet: false,
16416 * Timeout used for the click time threshold
16417 * @property clickTimeout
16422 clickTimeout: null,
16425 * The X position of the mousedown event stored for later use when a
16426 * drag threshold is met.
16435 * The Y position of the mousedown event stored for later use when a
16436 * drag threshold is met.
16445 * Each DragDrop instance must be registered with the DragDropMgr.
16446 * This is executed in DragDrop.init()
16447 * @method regDragDrop
16448 * @param {DragDrop} oDD the DragDrop object to register
16449 * @param {String} sGroup the name of the group this element belongs to
16452 regDragDrop: function(oDD, sGroup) {
16453 if (!this.initialized) { this.init(); }
16455 if (!this.ids[sGroup]) {
16456 this.ids[sGroup] = {};
16458 this.ids[sGroup][oDD.id] = oDD;
16462 * Removes the supplied dd instance from the supplied group. Executed
16463 * by DragDrop.removeFromGroup, so don't call this function directly.
16464 * @method removeDDFromGroup
16468 removeDDFromGroup: function(oDD, sGroup) {
16469 if (!this.ids[sGroup]) {
16470 this.ids[sGroup] = {};
16473 var obj = this.ids[sGroup];
16474 if (obj && obj[oDD.id]) {
16475 delete obj[oDD.id];
16480 * Unregisters a drag and drop item. This is executed in
16481 * DragDrop.unreg, use that method instead of calling this directly.
16486 _remove: function(oDD) {
16487 for (var g in oDD.groups) {
16488 if (g && this.ids[g][oDD.id]) {
16489 delete this.ids[g][oDD.id];
16492 delete this.handleIds[oDD.id];
16496 * Each DragDrop handle element must be registered. This is done
16497 * automatically when executing DragDrop.setHandleElId()
16498 * @method regHandle
16499 * @param {String} sDDId the DragDrop id this element is a handle for
16500 * @param {String} sHandleId the id of the element that is the drag
16504 regHandle: function(sDDId, sHandleId) {
16505 if (!this.handleIds[sDDId]) {
16506 this.handleIds[sDDId] = {};
16508 this.handleIds[sDDId][sHandleId] = sHandleId;
16512 * Utility function to determine if a given element has been
16513 * registered as a drag drop item.
16514 * @method isDragDrop
16515 * @param {String} id the element id to check
16516 * @return {boolean} true if this element is a DragDrop item,
16520 isDragDrop: function(id) {
16521 return ( this.getDDById(id) ) ? true : false;
16525 * Returns the drag and drop instances that are in all groups the
16526 * passed in instance belongs to.
16527 * @method getRelated
16528 * @param {DragDrop} p_oDD the obj to get related data for
16529 * @param {boolean} bTargetsOnly if true, only return targetable objs
16530 * @return {DragDrop[]} the related instances
16533 getRelated: function(p_oDD, bTargetsOnly) {
16535 for (var i in p_oDD.groups) {
16536 for (j in this.ids[i]) {
16537 var dd = this.ids[i][j];
16538 if (! this.isTypeOfDD(dd)) {
16541 if (!bTargetsOnly || dd.isTarget) {
16542 oDDs[oDDs.length] = dd;
16551 * Returns true if the specified dd target is a legal target for
16552 * the specifice drag obj
16553 * @method isLegalTarget
16554 * @param {DragDrop} the drag obj
16555 * @param {DragDrop} the target
16556 * @return {boolean} true if the target is a legal target for the
16560 isLegalTarget: function (oDD, oTargetDD) {
16561 var targets = this.getRelated(oDD, true);
16562 for (var i=0, len=targets.length;i<len;++i) {
16563 if (targets[i].id == oTargetDD.id) {
16572 * My goal is to be able to transparently determine if an object is
16573 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16574 * returns "object", oDD.constructor.toString() always returns
16575 * "DragDrop" and not the name of the subclass. So for now it just
16576 * evaluates a well-known variable in DragDrop.
16577 * @method isTypeOfDD
16578 * @param {Object} the object to evaluate
16579 * @return {boolean} true if typeof oDD = DragDrop
16582 isTypeOfDD: function (oDD) {
16583 return (oDD && oDD.__ygDragDrop);
16587 * Utility function to determine if a given element has been
16588 * registered as a drag drop handle for the given Drag Drop object.
16590 * @param {String} id the element id to check
16591 * @return {boolean} true if this element is a DragDrop handle, false
16595 isHandle: function(sDDId, sHandleId) {
16596 return ( this.handleIds[sDDId] &&
16597 this.handleIds[sDDId][sHandleId] );
16601 * Returns the DragDrop instance for a given id
16602 * @method getDDById
16603 * @param {String} id the id of the DragDrop object
16604 * @return {DragDrop} the drag drop object, null if it is not found
16607 getDDById: function(id) {
16608 for (var i in this.ids) {
16609 if (this.ids[i][id]) {
16610 return this.ids[i][id];
16617 * Fired after a registered DragDrop object gets the mousedown event.
16618 * Sets up the events required to track the object being dragged
16619 * @method handleMouseDown
16620 * @param {Event} e the event
16621 * @param oDD the DragDrop object being dragged
16625 handleMouseDown: function(e, oDD) {
16627 Roo.QuickTips.disable();
16629 this.currentTarget = e.getTarget();
16631 this.dragCurrent = oDD;
16633 var el = oDD.getEl();
16635 // track start position
16636 this.startX = e.getPageX();
16637 this.startY = e.getPageY();
16639 this.deltaX = this.startX - el.offsetLeft;
16640 this.deltaY = this.startY - el.offsetTop;
16642 this.dragThreshMet = false;
16644 this.clickTimeout = setTimeout(
16646 var DDM = Roo.dd.DDM;
16647 DDM.startDrag(DDM.startX, DDM.startY);
16649 this.clickTimeThresh );
16653 * Fired when either the drag pixel threshol or the mousedown hold
16654 * time threshold has been met.
16655 * @method startDrag
16656 * @param x {int} the X position of the original mousedown
16657 * @param y {int} the Y position of the original mousedown
16660 startDrag: function(x, y) {
16661 clearTimeout(this.clickTimeout);
16662 if (this.dragCurrent) {
16663 this.dragCurrent.b4StartDrag(x, y);
16664 this.dragCurrent.startDrag(x, y);
16666 this.dragThreshMet = true;
16670 * Internal function to handle the mouseup event. Will be invoked
16671 * from the context of the document.
16672 * @method handleMouseUp
16673 * @param {Event} e the event
16677 handleMouseUp: function(e) {
16680 Roo.QuickTips.enable();
16682 if (! this.dragCurrent) {
16686 clearTimeout(this.clickTimeout);
16688 if (this.dragThreshMet) {
16689 this.fireEvents(e, true);
16699 * Utility to stop event propagation and event default, if these
16700 * features are turned on.
16701 * @method stopEvent
16702 * @param {Event} e the event as returned by this.getEvent()
16705 stopEvent: function(e){
16706 if(this.stopPropagation) {
16707 e.stopPropagation();
16710 if (this.preventDefault) {
16711 e.preventDefault();
16716 * Internal function to clean up event handlers after the drag
16717 * operation is complete
16719 * @param {Event} e the event
16723 stopDrag: function(e) {
16724 // Fire the drag end event for the item that was dragged
16725 if (this.dragCurrent) {
16726 if (this.dragThreshMet) {
16727 this.dragCurrent.b4EndDrag(e);
16728 this.dragCurrent.endDrag(e);
16731 this.dragCurrent.onMouseUp(e);
16734 this.dragCurrent = null;
16735 this.dragOvers = {};
16739 * Internal function to handle the mousemove event. Will be invoked
16740 * from the context of the html element.
16742 * @TODO figure out what we can do about mouse events lost when the
16743 * user drags objects beyond the window boundary. Currently we can
16744 * detect this in internet explorer by verifying that the mouse is
16745 * down during the mousemove event. Firefox doesn't give us the
16746 * button state on the mousemove event.
16747 * @method handleMouseMove
16748 * @param {Event} e the event
16752 handleMouseMove: function(e) {
16753 if (! this.dragCurrent) {
16757 // var button = e.which || e.button;
16759 // check for IE mouseup outside of page boundary
16760 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16762 return this.handleMouseUp(e);
16765 if (!this.dragThreshMet) {
16766 var diffX = Math.abs(this.startX - e.getPageX());
16767 var diffY = Math.abs(this.startY - e.getPageY());
16768 if (diffX > this.clickPixelThresh ||
16769 diffY > this.clickPixelThresh) {
16770 this.startDrag(this.startX, this.startY);
16774 if (this.dragThreshMet) {
16775 this.dragCurrent.b4Drag(e);
16776 this.dragCurrent.onDrag(e);
16777 if(!this.dragCurrent.moveOnly){
16778 this.fireEvents(e, false);
16788 * Iterates over all of the DragDrop elements to find ones we are
16789 * hovering over or dropping on
16790 * @method fireEvents
16791 * @param {Event} e the event
16792 * @param {boolean} isDrop is this a drop op or a mouseover op?
16796 fireEvents: function(e, isDrop) {
16797 var dc = this.dragCurrent;
16799 // If the user did the mouse up outside of the window, we could
16800 // get here even though we have ended the drag.
16801 if (!dc || dc.isLocked()) {
16805 var pt = e.getPoint();
16807 // cache the previous dragOver array
16813 var enterEvts = [];
16815 // Check to see if the object(s) we were hovering over is no longer
16816 // being hovered over so we can fire the onDragOut event
16817 for (var i in this.dragOvers) {
16819 var ddo = this.dragOvers[i];
16821 if (! this.isTypeOfDD(ddo)) {
16825 if (! this.isOverTarget(pt, ddo, this.mode)) {
16826 outEvts.push( ddo );
16829 oldOvers[i] = true;
16830 delete this.dragOvers[i];
16833 for (var sGroup in dc.groups) {
16835 if ("string" != typeof sGroup) {
16839 for (i in this.ids[sGroup]) {
16840 var oDD = this.ids[sGroup][i];
16841 if (! this.isTypeOfDD(oDD)) {
16845 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16846 if (this.isOverTarget(pt, oDD, this.mode)) {
16847 // look for drop interactions
16849 dropEvts.push( oDD );
16850 // look for drag enter and drag over interactions
16853 // initial drag over: dragEnter fires
16854 if (!oldOvers[oDD.id]) {
16855 enterEvts.push( oDD );
16856 // subsequent drag overs: dragOver fires
16858 overEvts.push( oDD );
16861 this.dragOvers[oDD.id] = oDD;
16869 if (outEvts.length) {
16870 dc.b4DragOut(e, outEvts);
16871 dc.onDragOut(e, outEvts);
16874 if (enterEvts.length) {
16875 dc.onDragEnter(e, enterEvts);
16878 if (overEvts.length) {
16879 dc.b4DragOver(e, overEvts);
16880 dc.onDragOver(e, overEvts);
16883 if (dropEvts.length) {
16884 dc.b4DragDrop(e, dropEvts);
16885 dc.onDragDrop(e, dropEvts);
16889 // fire dragout events
16891 for (i=0, len=outEvts.length; i<len; ++i) {
16892 dc.b4DragOut(e, outEvts[i].id);
16893 dc.onDragOut(e, outEvts[i].id);
16896 // fire enter events
16897 for (i=0,len=enterEvts.length; i<len; ++i) {
16898 // dc.b4DragEnter(e, oDD.id);
16899 dc.onDragEnter(e, enterEvts[i].id);
16902 // fire over events
16903 for (i=0,len=overEvts.length; i<len; ++i) {
16904 dc.b4DragOver(e, overEvts[i].id);
16905 dc.onDragOver(e, overEvts[i].id);
16908 // fire drop events
16909 for (i=0, len=dropEvts.length; i<len; ++i) {
16910 dc.b4DragDrop(e, dropEvts[i].id);
16911 dc.onDragDrop(e, dropEvts[i].id);
16916 // notify about a drop that did not find a target
16917 if (isDrop && !dropEvts.length) {
16918 dc.onInvalidDrop(e);
16924 * Helper function for getting the best match from the list of drag
16925 * and drop objects returned by the drag and drop events when we are
16926 * in INTERSECT mode. It returns either the first object that the
16927 * cursor is over, or the object that has the greatest overlap with
16928 * the dragged element.
16929 * @method getBestMatch
16930 * @param {DragDrop[]} dds The array of drag and drop objects
16932 * @return {DragDrop} The best single match
16935 getBestMatch: function(dds) {
16937 // Return null if the input is not what we expect
16938 //if (!dds || !dds.length || dds.length == 0) {
16940 // If there is only one item, it wins
16941 //} else if (dds.length == 1) {
16943 var len = dds.length;
16948 // Loop through the targeted items
16949 for (var i=0; i<len; ++i) {
16951 // If the cursor is over the object, it wins. If the
16952 // cursor is over multiple matches, the first one we come
16954 if (dd.cursorIsOver) {
16957 // Otherwise the object with the most overlap wins
16960 winner.overlap.getArea() < dd.overlap.getArea()) {
16971 * Refreshes the cache of the top-left and bottom-right points of the
16972 * drag and drop objects in the specified group(s). This is in the
16973 * format that is stored in the drag and drop instance, so typical
16976 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16980 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16982 * @TODO this really should be an indexed array. Alternatively this
16983 * method could accept both.
16984 * @method refreshCache
16985 * @param {Object} groups an associative array of groups to refresh
16988 refreshCache: function(groups) {
16989 for (var sGroup in groups) {
16990 if ("string" != typeof sGroup) {
16993 for (var i in this.ids[sGroup]) {
16994 var oDD = this.ids[sGroup][i];
16996 if (this.isTypeOfDD(oDD)) {
16997 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16998 var loc = this.getLocation(oDD);
17000 this.locationCache[oDD.id] = loc;
17002 delete this.locationCache[oDD.id];
17003 // this will unregister the drag and drop object if
17004 // the element is not in a usable state
17013 * This checks to make sure an element exists and is in the DOM. The
17014 * main purpose is to handle cases where innerHTML is used to remove
17015 * drag and drop objects from the DOM. IE provides an 'unspecified
17016 * error' when trying to access the offsetParent of such an element
17018 * @param {HTMLElement} el the element to check
17019 * @return {boolean} true if the element looks usable
17022 verifyEl: function(el) {
17027 parent = el.offsetParent;
17030 parent = el.offsetParent;
17041 * Returns a Region object containing the drag and drop element's position
17042 * and size, including the padding configured for it
17043 * @method getLocation
17044 * @param {DragDrop} oDD the drag and drop object to get the
17046 * @return {Roo.lib.Region} a Region object representing the total area
17047 * the element occupies, including any padding
17048 * the instance is configured for.
17051 getLocation: function(oDD) {
17052 if (! this.isTypeOfDD(oDD)) {
17056 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17059 pos= Roo.lib.Dom.getXY(el);
17067 x2 = x1 + el.offsetWidth;
17069 y2 = y1 + el.offsetHeight;
17071 t = y1 - oDD.padding[0];
17072 r = x2 + oDD.padding[1];
17073 b = y2 + oDD.padding[2];
17074 l = x1 - oDD.padding[3];
17076 return new Roo.lib.Region( t, r, b, l );
17080 * Checks the cursor location to see if it over the target
17081 * @method isOverTarget
17082 * @param {Roo.lib.Point} pt The point to evaluate
17083 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17084 * @return {boolean} true if the mouse is over the target
17088 isOverTarget: function(pt, oTarget, intersect) {
17089 // use cache if available
17090 var loc = this.locationCache[oTarget.id];
17091 if (!loc || !this.useCache) {
17092 loc = this.getLocation(oTarget);
17093 this.locationCache[oTarget.id] = loc;
17101 oTarget.cursorIsOver = loc.contains( pt );
17103 // DragDrop is using this as a sanity check for the initial mousedown
17104 // in this case we are done. In POINT mode, if the drag obj has no
17105 // contraints, we are also done. Otherwise we need to evaluate the
17106 // location of the target as related to the actual location of the
17107 // dragged element.
17108 var dc = this.dragCurrent;
17109 if (!dc || !dc.getTargetCoord ||
17110 (!intersect && !dc.constrainX && !dc.constrainY)) {
17111 return oTarget.cursorIsOver;
17114 oTarget.overlap = null;
17116 // Get the current location of the drag element, this is the
17117 // location of the mouse event less the delta that represents
17118 // where the original mousedown happened on the element. We
17119 // need to consider constraints and ticks as well.
17120 var pos = dc.getTargetCoord(pt.x, pt.y);
17122 var el = dc.getDragEl();
17123 var curRegion = new Roo.lib.Region( pos.y,
17124 pos.x + el.offsetWidth,
17125 pos.y + el.offsetHeight,
17128 var overlap = curRegion.intersect(loc);
17131 oTarget.overlap = overlap;
17132 return (intersect) ? true : oTarget.cursorIsOver;
17139 * unload event handler
17140 * @method _onUnload
17144 _onUnload: function(e, me) {
17145 Roo.dd.DragDropMgr.unregAll();
17149 * Cleans up the drag and drop events and objects.
17154 unregAll: function() {
17156 if (this.dragCurrent) {
17158 this.dragCurrent = null;
17161 this._execOnAll("unreg", []);
17163 for (i in this.elementCache) {
17164 delete this.elementCache[i];
17167 this.elementCache = {};
17172 * A cache of DOM elements
17173 * @property elementCache
17180 * Get the wrapper for the DOM element specified
17181 * @method getElWrapper
17182 * @param {String} id the id of the element to get
17183 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17185 * @deprecated This wrapper isn't that useful
17188 getElWrapper: function(id) {
17189 var oWrapper = this.elementCache[id];
17190 if (!oWrapper || !oWrapper.el) {
17191 oWrapper = this.elementCache[id] =
17192 new this.ElementWrapper(Roo.getDom(id));
17198 * Returns the actual DOM element
17199 * @method getElement
17200 * @param {String} id the id of the elment to get
17201 * @return {Object} The element
17202 * @deprecated use Roo.getDom instead
17205 getElement: function(id) {
17206 return Roo.getDom(id);
17210 * Returns the style property for the DOM element (i.e.,
17211 * document.getElById(id).style)
17213 * @param {String} id the id of the elment to get
17214 * @return {Object} The style property of the element
17215 * @deprecated use Roo.getDom instead
17218 getCss: function(id) {
17219 var el = Roo.getDom(id);
17220 return (el) ? el.style : null;
17224 * Inner class for cached elements
17225 * @class DragDropMgr.ElementWrapper
17230 ElementWrapper: function(el) {
17235 this.el = el || null;
17240 this.id = this.el && el.id;
17242 * A reference to the style property
17245 this.css = this.el && el.style;
17249 * Returns the X position of an html element
17251 * @param el the element for which to get the position
17252 * @return {int} the X coordinate
17254 * @deprecated use Roo.lib.Dom.getX instead
17257 getPosX: function(el) {
17258 return Roo.lib.Dom.getX(el);
17262 * Returns the Y position of an html element
17264 * @param el the element for which to get the position
17265 * @return {int} the Y coordinate
17266 * @deprecated use Roo.lib.Dom.getY instead
17269 getPosY: function(el) {
17270 return Roo.lib.Dom.getY(el);
17274 * Swap two nodes. In IE, we use the native method, for others we
17275 * emulate the IE behavior
17277 * @param n1 the first node to swap
17278 * @param n2 the other node to swap
17281 swapNode: function(n1, n2) {
17285 var p = n2.parentNode;
17286 var s = n2.nextSibling;
17289 p.insertBefore(n1, n2);
17290 } else if (n2 == n1.nextSibling) {
17291 p.insertBefore(n2, n1);
17293 n1.parentNode.replaceChild(n2, n1);
17294 p.insertBefore(n1, s);
17300 * Returns the current scroll position
17301 * @method getScroll
17305 getScroll: function () {
17306 var t, l, dde=document.documentElement, db=document.body;
17307 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17309 l = dde.scrollLeft;
17316 return { top: t, left: l };
17320 * Returns the specified element style property
17322 * @param {HTMLElement} el the element
17323 * @param {string} styleProp the style property
17324 * @return {string} The value of the style property
17325 * @deprecated use Roo.lib.Dom.getStyle
17328 getStyle: function(el, styleProp) {
17329 return Roo.fly(el).getStyle(styleProp);
17333 * Gets the scrollTop
17334 * @method getScrollTop
17335 * @return {int} the document's scrollTop
17338 getScrollTop: function () { return this.getScroll().top; },
17341 * Gets the scrollLeft
17342 * @method getScrollLeft
17343 * @return {int} the document's scrollTop
17346 getScrollLeft: function () { return this.getScroll().left; },
17349 * Sets the x/y position of an element to the location of the
17352 * @param {HTMLElement} moveEl The element to move
17353 * @param {HTMLElement} targetEl The position reference element
17356 moveToEl: function (moveEl, targetEl) {
17357 var aCoord = Roo.lib.Dom.getXY(targetEl);
17358 Roo.lib.Dom.setXY(moveEl, aCoord);
17362 * Numeric array sort function
17363 * @method numericSort
17366 numericSort: function(a, b) { return (a - b); },
17370 * @property _timeoutCount
17377 * Trying to make the load order less important. Without this we get
17378 * an error if this file is loaded before the Event Utility.
17379 * @method _addListeners
17383 _addListeners: function() {
17384 var DDM = Roo.dd.DDM;
17385 if ( Roo.lib.Event && document ) {
17388 if (DDM._timeoutCount > 2000) {
17390 setTimeout(DDM._addListeners, 10);
17391 if (document && document.body) {
17392 DDM._timeoutCount += 1;
17399 * Recursively searches the immediate parent and all child nodes for
17400 * the handle element in order to determine wheter or not it was
17402 * @method handleWasClicked
17403 * @param node the html element to inspect
17406 handleWasClicked: function(node, id) {
17407 if (this.isHandle(id, node.id)) {
17410 // check to see if this is a text node child of the one we want
17411 var p = node.parentNode;
17414 if (this.isHandle(id, p.id)) {
17429 // shorter alias, save a few bytes
17430 Roo.dd.DDM = Roo.dd.DragDropMgr;
17431 Roo.dd.DDM._addListeners();
17435 * Ext JS Library 1.1.1
17436 * Copyright(c) 2006-2007, Ext JS, LLC.
17438 * Originally Released Under LGPL - original licence link has changed is not relivant.
17441 * <script type="text/javascript">
17446 * A DragDrop implementation where the linked element follows the
17447 * mouse cursor during a drag.
17448 * @extends Roo.dd.DragDrop
17450 * @param {String} id the id of the linked element
17451 * @param {String} sGroup the group of related DragDrop items
17452 * @param {object} config an object containing configurable attributes
17453 * Valid properties for DD:
17456 Roo.dd.DD = function(id, sGroup, config) {
17458 this.init(id, sGroup, config);
17462 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17465 * When set to true, the utility automatically tries to scroll the browser
17466 * window wehn a drag and drop element is dragged near the viewport boundary.
17467 * Defaults to true.
17474 * Sets the pointer offset to the distance between the linked element's top
17475 * left corner and the location the element was clicked
17476 * @method autoOffset
17477 * @param {int} iPageX the X coordinate of the click
17478 * @param {int} iPageY the Y coordinate of the click
17480 autoOffset: function(iPageX, iPageY) {
17481 var x = iPageX - this.startPageX;
17482 var y = iPageY - this.startPageY;
17483 this.setDelta(x, y);
17487 * Sets the pointer offset. You can call this directly to force the
17488 * offset to be in a particular location (e.g., pass in 0,0 to set it
17489 * to the center of the object)
17491 * @param {int} iDeltaX the distance from the left
17492 * @param {int} iDeltaY the distance from the top
17494 setDelta: function(iDeltaX, iDeltaY) {
17495 this.deltaX = iDeltaX;
17496 this.deltaY = iDeltaY;
17500 * Sets the drag element to the location of the mousedown or click event,
17501 * maintaining the cursor location relative to the location on the element
17502 * that was clicked. Override this if you want to place the element in a
17503 * location other than where the cursor is.
17504 * @method setDragElPos
17505 * @param {int} iPageX the X coordinate of the mousedown or drag event
17506 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17508 setDragElPos: function(iPageX, iPageY) {
17509 // the first time we do this, we are going to check to make sure
17510 // the element has css positioning
17512 var el = this.getDragEl();
17513 this.alignElWithMouse(el, iPageX, iPageY);
17517 * Sets the element to the location of the mousedown or click event,
17518 * maintaining the cursor location relative to the location on the element
17519 * that was clicked. Override this if you want to place the element in a
17520 * location other than where the cursor is.
17521 * @method alignElWithMouse
17522 * @param {HTMLElement} el the element to move
17523 * @param {int} iPageX the X coordinate of the mousedown or drag event
17524 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17526 alignElWithMouse: function(el, iPageX, iPageY) {
17527 var oCoord = this.getTargetCoord(iPageX, iPageY);
17528 var fly = el.dom ? el : Roo.fly(el);
17529 if (!this.deltaSetXY) {
17530 var aCoord = [oCoord.x, oCoord.y];
17532 var newLeft = fly.getLeft(true);
17533 var newTop = fly.getTop(true);
17534 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17536 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17539 this.cachePosition(oCoord.x, oCoord.y);
17540 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17545 * Saves the most recent position so that we can reset the constraints and
17546 * tick marks on-demand. We need to know this so that we can calculate the
17547 * number of pixels the element is offset from its original position.
17548 * @method cachePosition
17549 * @param iPageX the current x position (optional, this just makes it so we
17550 * don't have to look it up again)
17551 * @param iPageY the current y position (optional, this just makes it so we
17552 * don't have to look it up again)
17554 cachePosition: function(iPageX, iPageY) {
17556 this.lastPageX = iPageX;
17557 this.lastPageY = iPageY;
17559 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17560 this.lastPageX = aCoord[0];
17561 this.lastPageY = aCoord[1];
17566 * Auto-scroll the window if the dragged object has been moved beyond the
17567 * visible window boundary.
17568 * @method autoScroll
17569 * @param {int} x the drag element's x position
17570 * @param {int} y the drag element's y position
17571 * @param {int} h the height of the drag element
17572 * @param {int} w the width of the drag element
17575 autoScroll: function(x, y, h, w) {
17578 // The client height
17579 var clientH = Roo.lib.Dom.getViewWidth();
17581 // The client width
17582 var clientW = Roo.lib.Dom.getViewHeight();
17584 // The amt scrolled down
17585 var st = this.DDM.getScrollTop();
17587 // The amt scrolled right
17588 var sl = this.DDM.getScrollLeft();
17590 // Location of the bottom of the element
17593 // Location of the right of the element
17596 // The distance from the cursor to the bottom of the visible area,
17597 // adjusted so that we don't scroll if the cursor is beyond the
17598 // element drag constraints
17599 var toBot = (clientH + st - y - this.deltaY);
17601 // The distance from the cursor to the right of the visible area
17602 var toRight = (clientW + sl - x - this.deltaX);
17605 // How close to the edge the cursor must be before we scroll
17606 // var thresh = (document.all) ? 100 : 40;
17609 // How many pixels to scroll per autoscroll op. This helps to reduce
17610 // clunky scrolling. IE is more sensitive about this ... it needs this
17611 // value to be higher.
17612 var scrAmt = (document.all) ? 80 : 30;
17614 // Scroll down if we are near the bottom of the visible page and the
17615 // obj extends below the crease
17616 if ( bot > clientH && toBot < thresh ) {
17617 window.scrollTo(sl, st + scrAmt);
17620 // Scroll up if the window is scrolled down and the top of the object
17621 // goes above the top border
17622 if ( y < st && st > 0 && y - st < thresh ) {
17623 window.scrollTo(sl, st - scrAmt);
17626 // Scroll right if the obj is beyond the right border and the cursor is
17627 // near the border.
17628 if ( right > clientW && toRight < thresh ) {
17629 window.scrollTo(sl + scrAmt, st);
17632 // Scroll left if the window has been scrolled to the right and the obj
17633 // extends past the left border
17634 if ( x < sl && sl > 0 && x - sl < thresh ) {
17635 window.scrollTo(sl - scrAmt, st);
17641 * Finds the location the element should be placed if we want to move
17642 * it to where the mouse location less the click offset would place us.
17643 * @method getTargetCoord
17644 * @param {int} iPageX the X coordinate of the click
17645 * @param {int} iPageY the Y coordinate of the click
17646 * @return an object that contains the coordinates (Object.x and Object.y)
17649 getTargetCoord: function(iPageX, iPageY) {
17652 var x = iPageX - this.deltaX;
17653 var y = iPageY - this.deltaY;
17655 if (this.constrainX) {
17656 if (x < this.minX) { x = this.minX; }
17657 if (x > this.maxX) { x = this.maxX; }
17660 if (this.constrainY) {
17661 if (y < this.minY) { y = this.minY; }
17662 if (y > this.maxY) { y = this.maxY; }
17665 x = this.getTick(x, this.xTicks);
17666 y = this.getTick(y, this.yTicks);
17673 * Sets up config options specific to this class. Overrides
17674 * Roo.dd.DragDrop, but all versions of this method through the
17675 * inheritance chain are called
17677 applyConfig: function() {
17678 Roo.dd.DD.superclass.applyConfig.call(this);
17679 this.scroll = (this.config.scroll !== false);
17683 * Event that fires prior to the onMouseDown event. Overrides
17686 b4MouseDown: function(e) {
17687 // this.resetConstraints();
17688 this.autoOffset(e.getPageX(),
17693 * Event that fires prior to the onDrag event. Overrides
17696 b4Drag: function(e) {
17697 this.setDragElPos(e.getPageX(),
17701 toString: function() {
17702 return ("DD " + this.id);
17705 //////////////////////////////////////////////////////////////////////////
17706 // Debugging ygDragDrop events that can be overridden
17707 //////////////////////////////////////////////////////////////////////////
17709 startDrag: function(x, y) {
17712 onDrag: function(e) {
17715 onDragEnter: function(e, id) {
17718 onDragOver: function(e, id) {
17721 onDragOut: function(e, id) {
17724 onDragDrop: function(e, id) {
17727 endDrag: function(e) {
17734 * Ext JS Library 1.1.1
17735 * Copyright(c) 2006-2007, Ext JS, LLC.
17737 * Originally Released Under LGPL - original licence link has changed is not relivant.
17740 * <script type="text/javascript">
17744 * @class Roo.dd.DDProxy
17745 * A DragDrop implementation that inserts an empty, bordered div into
17746 * the document that follows the cursor during drag operations. At the time of
17747 * the click, the frame div is resized to the dimensions of the linked html
17748 * element, and moved to the exact location of the linked element.
17750 * References to the "frame" element refer to the single proxy element that
17751 * was created to be dragged in place of all DDProxy elements on the
17754 * @extends Roo.dd.DD
17756 * @param {String} id the id of the linked html element
17757 * @param {String} sGroup the group of related DragDrop objects
17758 * @param {object} config an object containing configurable attributes
17759 * Valid properties for DDProxy in addition to those in DragDrop:
17760 * resizeFrame, centerFrame, dragElId
17762 Roo.dd.DDProxy = function(id, sGroup, config) {
17764 this.init(id, sGroup, config);
17770 * The default drag frame div id
17771 * @property Roo.dd.DDProxy.dragElId
17775 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17777 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17780 * By default we resize the drag frame to be the same size as the element
17781 * we want to drag (this is to get the frame effect). We can turn it off
17782 * if we want a different behavior.
17783 * @property resizeFrame
17789 * By default the frame is positioned exactly where the drag element is, so
17790 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17791 * you do not have constraints on the obj is to have the drag frame centered
17792 * around the cursor. Set centerFrame to true for this effect.
17793 * @property centerFrame
17796 centerFrame: false,
17799 * Creates the proxy element if it does not yet exist
17800 * @method createFrame
17802 createFrame: function() {
17804 var body = document.body;
17806 if (!body || !body.firstChild) {
17807 setTimeout( function() { self.createFrame(); }, 50 );
17811 var div = this.getDragEl();
17814 div = document.createElement("div");
17815 div.id = this.dragElId;
17818 s.position = "absolute";
17819 s.visibility = "hidden";
17821 s.border = "2px solid #aaa";
17824 // appendChild can blow up IE if invoked prior to the window load event
17825 // while rendering a table. It is possible there are other scenarios
17826 // that would cause this to happen as well.
17827 body.insertBefore(div, body.firstChild);
17832 * Initialization for the drag frame element. Must be called in the
17833 * constructor of all subclasses
17834 * @method initFrame
17836 initFrame: function() {
17837 this.createFrame();
17840 applyConfig: function() {
17841 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17843 this.resizeFrame = (this.config.resizeFrame !== false);
17844 this.centerFrame = (this.config.centerFrame);
17845 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17849 * Resizes the drag frame to the dimensions of the clicked object, positions
17850 * it over the object, and finally displays it
17851 * @method showFrame
17852 * @param {int} iPageX X click position
17853 * @param {int} iPageY Y click position
17856 showFrame: function(iPageX, iPageY) {
17857 var el = this.getEl();
17858 var dragEl = this.getDragEl();
17859 var s = dragEl.style;
17861 this._resizeProxy();
17863 if (this.centerFrame) {
17864 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17865 Math.round(parseInt(s.height, 10)/2) );
17868 this.setDragElPos(iPageX, iPageY);
17870 Roo.fly(dragEl).show();
17874 * The proxy is automatically resized to the dimensions of the linked
17875 * element when a drag is initiated, unless resizeFrame is set to false
17876 * @method _resizeProxy
17879 _resizeProxy: function() {
17880 if (this.resizeFrame) {
17881 var el = this.getEl();
17882 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17886 // overrides Roo.dd.DragDrop
17887 b4MouseDown: function(e) {
17888 var x = e.getPageX();
17889 var y = e.getPageY();
17890 this.autoOffset(x, y);
17891 this.setDragElPos(x, y);
17894 // overrides Roo.dd.DragDrop
17895 b4StartDrag: function(x, y) {
17896 // show the drag frame
17897 this.showFrame(x, y);
17900 // overrides Roo.dd.DragDrop
17901 b4EndDrag: function(e) {
17902 Roo.fly(this.getDragEl()).hide();
17905 // overrides Roo.dd.DragDrop
17906 // By default we try to move the element to the last location of the frame.
17907 // This is so that the default behavior mirrors that of Roo.dd.DD.
17908 endDrag: function(e) {
17910 var lel = this.getEl();
17911 var del = this.getDragEl();
17913 // Show the drag frame briefly so we can get its position
17914 del.style.visibility = "";
17917 // Hide the linked element before the move to get around a Safari
17919 lel.style.visibility = "hidden";
17920 Roo.dd.DDM.moveToEl(lel, del);
17921 del.style.visibility = "hidden";
17922 lel.style.visibility = "";
17927 beforeMove : function(){
17931 afterDrag : function(){
17935 toString: function() {
17936 return ("DDProxy " + this.id);
17942 * Ext JS Library 1.1.1
17943 * Copyright(c) 2006-2007, Ext JS, LLC.
17945 * Originally Released Under LGPL - original licence link has changed is not relivant.
17948 * <script type="text/javascript">
17952 * @class Roo.dd.DDTarget
17953 * A DragDrop implementation that does not move, but can be a drop
17954 * target. You would get the same result by simply omitting implementation
17955 * for the event callbacks, but this way we reduce the processing cost of the
17956 * event listener and the callbacks.
17957 * @extends Roo.dd.DragDrop
17959 * @param {String} id the id of the element that is a drop target
17960 * @param {String} sGroup the group of related DragDrop objects
17961 * @param {object} config an object containing configurable attributes
17962 * Valid properties for DDTarget in addition to those in
17966 Roo.dd.DDTarget = function(id, sGroup, config) {
17968 this.initTarget(id, sGroup, config);
17970 if (config.listeners || config.events) {
17971 Roo.dd.DragDrop.superclass.constructor.call(this, {
17972 listeners : config.listeners || {},
17973 events : config.events || {}
17978 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17979 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17980 toString: function() {
17981 return ("DDTarget " + this.id);
17986 * Ext JS Library 1.1.1
17987 * Copyright(c) 2006-2007, Ext JS, LLC.
17989 * Originally Released Under LGPL - original licence link has changed is not relivant.
17992 * <script type="text/javascript">
17997 * @class Roo.dd.ScrollManager
17998 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17999 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
18002 Roo.dd.ScrollManager = function(){
18003 var ddm = Roo.dd.DragDropMgr;
18010 var onStop = function(e){
18015 var triggerRefresh = function(){
18016 if(ddm.dragCurrent){
18017 ddm.refreshCache(ddm.dragCurrent.groups);
18021 var doScroll = function(){
18022 if(ddm.dragCurrent){
18023 var dds = Roo.dd.ScrollManager;
18025 if(proc.el.scroll(proc.dir, dds.increment)){
18029 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18034 var clearProc = function(){
18036 clearInterval(proc.id);
18043 var startProc = function(el, dir){
18044 Roo.log('scroll startproc');
18048 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18051 var onFire = function(e, isDrop){
18053 if(isDrop || !ddm.dragCurrent){ return; }
18054 var dds = Roo.dd.ScrollManager;
18055 if(!dragEl || dragEl != ddm.dragCurrent){
18056 dragEl = ddm.dragCurrent;
18057 // refresh regions on drag start
18058 dds.refreshCache();
18061 var xy = Roo.lib.Event.getXY(e);
18062 var pt = new Roo.lib.Point(xy[0], xy[1]);
18063 for(var id in els){
18064 var el = els[id], r = el._region;
18065 if(r && r.contains(pt) && el.isScrollable()){
18066 if(r.bottom - pt.y <= dds.thresh){
18068 startProc(el, "down");
18071 }else if(r.right - pt.x <= dds.thresh){
18073 startProc(el, "left");
18076 }else if(pt.y - r.top <= dds.thresh){
18078 startProc(el, "up");
18081 }else if(pt.x - r.left <= dds.thresh){
18083 startProc(el, "right");
18092 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18093 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18097 * Registers new overflow element(s) to auto scroll
18098 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18100 register : function(el){
18101 if(el instanceof Array){
18102 for(var i = 0, len = el.length; i < len; i++) {
18103 this.register(el[i]);
18109 Roo.dd.ScrollManager.els = els;
18113 * Unregisters overflow element(s) so they are no longer scrolled
18114 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18116 unregister : function(el){
18117 if(el instanceof Array){
18118 for(var i = 0, len = el.length; i < len; i++) {
18119 this.unregister(el[i]);
18128 * The number of pixels from the edge of a container the pointer needs to be to
18129 * trigger scrolling (defaults to 25)
18135 * The number of pixels to scroll in each scroll increment (defaults to 50)
18141 * The frequency of scrolls in milliseconds (defaults to 500)
18147 * True to animate the scroll (defaults to true)
18153 * The animation duration in seconds -
18154 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18160 * Manually trigger a cache refresh.
18162 refreshCache : function(){
18163 for(var id in els){
18164 if(typeof els[id] == 'object'){ // for people extending the object prototype
18165 els[id]._region = els[id].getRegion();
18172 * Ext JS Library 1.1.1
18173 * Copyright(c) 2006-2007, Ext JS, LLC.
18175 * Originally Released Under LGPL - original licence link has changed is not relivant.
18178 * <script type="text/javascript">
18183 * @class Roo.dd.Registry
18184 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18185 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18188 Roo.dd.Registry = function(){
18191 var autoIdSeed = 0;
18193 var getId = function(el, autogen){
18194 if(typeof el == "string"){
18198 if(!id && autogen !== false){
18199 id = "roodd-" + (++autoIdSeed);
18207 * Register a drag drop element
18208 * @param {String|HTMLElement} element The id or DOM node to register
18209 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18210 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18211 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18212 * populated in the data object (if applicable):
18214 Value Description<br />
18215 --------- ------------------------------------------<br />
18216 handles Array of DOM nodes that trigger dragging<br />
18217 for the element being registered<br />
18218 isHandle True if the element passed in triggers<br />
18219 dragging itself, else false
18222 register : function(el, data){
18224 if(typeof el == "string"){
18225 el = document.getElementById(el);
18228 elements[getId(el)] = data;
18229 if(data.isHandle !== false){
18230 handles[data.ddel.id] = data;
18233 var hs = data.handles;
18234 for(var i = 0, len = hs.length; i < len; i++){
18235 handles[getId(hs[i])] = data;
18241 * Unregister a drag drop element
18242 * @param {String|HTMLElement} element The id or DOM node to unregister
18244 unregister : function(el){
18245 var id = getId(el, false);
18246 var data = elements[id];
18248 delete elements[id];
18250 var hs = data.handles;
18251 for(var i = 0, len = hs.length; i < len; i++){
18252 delete handles[getId(hs[i], false)];
18259 * Returns the handle registered for a DOM Node by id
18260 * @param {String|HTMLElement} id The DOM node or id to look up
18261 * @return {Object} handle The custom handle data
18263 getHandle : function(id){
18264 if(typeof id != "string"){ // must be element?
18267 return handles[id];
18271 * Returns the handle that is registered for the DOM node that is the target of the event
18272 * @param {Event} e The event
18273 * @return {Object} handle The custom handle data
18275 getHandleFromEvent : function(e){
18276 var t = Roo.lib.Event.getTarget(e);
18277 return t ? handles[t.id] : null;
18281 * Returns a custom data object that is registered for a DOM node by id
18282 * @param {String|HTMLElement} id The DOM node or id to look up
18283 * @return {Object} data The custom data
18285 getTarget : function(id){
18286 if(typeof id != "string"){ // must be element?
18289 return elements[id];
18293 * Returns a custom data object that is registered for the DOM node that is the target of the event
18294 * @param {Event} e The event
18295 * @return {Object} data The custom data
18297 getTargetFromEvent : function(e){
18298 var t = Roo.lib.Event.getTarget(e);
18299 return t ? elements[t.id] || handles[t.id] : null;
18304 * Ext JS Library 1.1.1
18305 * Copyright(c) 2006-2007, Ext JS, LLC.
18307 * Originally Released Under LGPL - original licence link has changed is not relivant.
18310 * <script type="text/javascript">
18315 * @class Roo.dd.StatusProxy
18316 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18317 * default drag proxy used by all Roo.dd components.
18319 * @param {Object} config
18321 Roo.dd.StatusProxy = function(config){
18322 Roo.apply(this, config);
18323 this.id = this.id || Roo.id();
18324 this.el = new Roo.Layer({
18326 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18327 {tag: "div", cls: "x-dd-drop-icon"},
18328 {tag: "div", cls: "x-dd-drag-ghost"}
18331 shadow: !config || config.shadow !== false
18333 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18334 this.dropStatus = this.dropNotAllowed;
18337 Roo.dd.StatusProxy.prototype = {
18339 * @cfg {String} dropAllowed
18340 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18342 dropAllowed : "x-dd-drop-ok",
18344 * @cfg {String} dropNotAllowed
18345 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18347 dropNotAllowed : "x-dd-drop-nodrop",
18350 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18351 * over the current target element.
18352 * @param {String} cssClass The css class for the new drop status indicator image
18354 setStatus : function(cssClass){
18355 cssClass = cssClass || this.dropNotAllowed;
18356 if(this.dropStatus != cssClass){
18357 this.el.replaceClass(this.dropStatus, cssClass);
18358 this.dropStatus = cssClass;
18363 * Resets the status indicator to the default dropNotAllowed value
18364 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18366 reset : function(clearGhost){
18367 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18368 this.dropStatus = this.dropNotAllowed;
18370 this.ghost.update("");
18375 * Updates the contents of the ghost element
18376 * @param {String} html The html that will replace the current innerHTML of the ghost element
18378 update : function(html){
18379 if(typeof html == "string"){
18380 this.ghost.update(html);
18382 this.ghost.update("");
18383 html.style.margin = "0";
18384 this.ghost.dom.appendChild(html);
18386 // ensure float = none set?? cant remember why though.
18387 var el = this.ghost.dom.firstChild;
18389 Roo.fly(el).setStyle('float', 'none');
18394 * Returns the underlying proxy {@link Roo.Layer}
18395 * @return {Roo.Layer} el
18397 getEl : function(){
18402 * Returns the ghost element
18403 * @return {Roo.Element} el
18405 getGhost : function(){
18411 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18413 hide : function(clear){
18421 * Stops the repair animation if it's currently running
18424 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18430 * Displays this proxy
18437 * Force the Layer to sync its shadow and shim positions to the element
18444 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18445 * invalid drop operation by the item being dragged.
18446 * @param {Array} xy The XY position of the element ([x, y])
18447 * @param {Function} callback The function to call after the repair is complete
18448 * @param {Object} scope The scope in which to execute the callback
18450 repair : function(xy, callback, scope){
18451 this.callback = callback;
18452 this.scope = scope;
18453 if(xy && this.animRepair !== false){
18454 this.el.addClass("x-dd-drag-repair");
18455 this.el.hideUnders(true);
18456 this.anim = this.el.shift({
18457 duration: this.repairDuration || .5,
18461 callback: this.afterRepair,
18465 this.afterRepair();
18470 afterRepair : function(){
18472 if(typeof this.callback == "function"){
18473 this.callback.call(this.scope || this);
18475 this.callback = null;
18480 * Ext JS Library 1.1.1
18481 * Copyright(c) 2006-2007, Ext JS, LLC.
18483 * Originally Released Under LGPL - original licence link has changed is not relivant.
18486 * <script type="text/javascript">
18490 * @class Roo.dd.DragSource
18491 * @extends Roo.dd.DDProxy
18492 * A simple class that provides the basic implementation needed to make any element draggable.
18494 * @param {String/HTMLElement/Element} el The container element
18495 * @param {Object} config
18497 Roo.dd.DragSource = function(el, config){
18498 this.el = Roo.get(el);
18499 this.dragData = {};
18501 Roo.apply(this, config);
18504 this.proxy = new Roo.dd.StatusProxy();
18507 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18508 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18510 this.dragging = false;
18513 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18515 * @cfg {String} dropAllowed
18516 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18518 dropAllowed : "x-dd-drop-ok",
18520 * @cfg {String} dropNotAllowed
18521 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18523 dropNotAllowed : "x-dd-drop-nodrop",
18526 * Returns the data object associated with this drag source
18527 * @return {Object} data An object containing arbitrary data
18529 getDragData : function(e){
18530 return this.dragData;
18534 onDragEnter : function(e, id){
18535 var target = Roo.dd.DragDropMgr.getDDById(id);
18536 this.cachedTarget = target;
18537 if(this.beforeDragEnter(target, e, id) !== false){
18538 if(target.isNotifyTarget){
18539 var status = target.notifyEnter(this, e, this.dragData);
18540 this.proxy.setStatus(status);
18542 this.proxy.setStatus(this.dropAllowed);
18545 if(this.afterDragEnter){
18547 * An empty function by default, but provided so that you can perform a custom action
18548 * when the dragged item enters the drop target by providing an implementation.
18549 * @param {Roo.dd.DragDrop} target The drop target
18550 * @param {Event} e The event object
18551 * @param {String} id The id of the dragged element
18552 * @method afterDragEnter
18554 this.afterDragEnter(target, e, id);
18560 * An empty function by default, but provided so that you can perform a custom action
18561 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18562 * @param {Roo.dd.DragDrop} target The drop target
18563 * @param {Event} e The event object
18564 * @param {String} id The id of the dragged element
18565 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18567 beforeDragEnter : function(target, e, id){
18572 alignElWithMouse: function() {
18573 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18578 onDragOver : function(e, id){
18579 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18580 if(this.beforeDragOver(target, e, id) !== false){
18581 if(target.isNotifyTarget){
18582 var status = target.notifyOver(this, e, this.dragData);
18583 this.proxy.setStatus(status);
18586 if(this.afterDragOver){
18588 * An empty function by default, but provided so that you can perform a custom action
18589 * while the dragged item is over the drop target by providing an implementation.
18590 * @param {Roo.dd.DragDrop} target The drop target
18591 * @param {Event} e The event object
18592 * @param {String} id The id of the dragged element
18593 * @method afterDragOver
18595 this.afterDragOver(target, e, id);
18601 * An empty function by default, but provided so that you can perform a custom action
18602 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18603 * @param {Roo.dd.DragDrop} target The drop target
18604 * @param {Event} e The event object
18605 * @param {String} id The id of the dragged element
18606 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18608 beforeDragOver : function(target, e, id){
18613 onDragOut : function(e, id){
18614 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18615 if(this.beforeDragOut(target, e, id) !== false){
18616 if(target.isNotifyTarget){
18617 target.notifyOut(this, e, this.dragData);
18619 this.proxy.reset();
18620 if(this.afterDragOut){
18622 * An empty function by default, but provided so that you can perform a custom action
18623 * after the dragged item is dragged out of the target without dropping.
18624 * @param {Roo.dd.DragDrop} target The drop target
18625 * @param {Event} e The event object
18626 * @param {String} id The id of the dragged element
18627 * @method afterDragOut
18629 this.afterDragOut(target, e, id);
18632 this.cachedTarget = null;
18636 * An empty function by default, but provided so that you can perform a custom action before the dragged
18637 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18638 * @param {Roo.dd.DragDrop} target The drop target
18639 * @param {Event} e The event object
18640 * @param {String} id The id of the dragged element
18641 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18643 beforeDragOut : function(target, e, id){
18648 onDragDrop : function(e, id){
18649 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18650 if(this.beforeDragDrop(target, e, id) !== false){
18651 if(target.isNotifyTarget){
18652 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18653 this.onValidDrop(target, e, id);
18655 this.onInvalidDrop(target, e, id);
18658 this.onValidDrop(target, e, id);
18661 if(this.afterDragDrop){
18663 * An empty function by default, but provided so that you can perform a custom action
18664 * after a valid drag drop has occurred by providing an implementation.
18665 * @param {Roo.dd.DragDrop} target The drop target
18666 * @param {Event} e The event object
18667 * @param {String} id The id of the dropped element
18668 * @method afterDragDrop
18670 this.afterDragDrop(target, e, id);
18673 delete this.cachedTarget;
18677 * An empty function by default, but provided so that you can perform a custom action before the dragged
18678 * item is dropped onto the target and optionally cancel the onDragDrop.
18679 * @param {Roo.dd.DragDrop} target The drop target
18680 * @param {Event} e The event object
18681 * @param {String} id The id of the dragged element
18682 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18684 beforeDragDrop : function(target, e, id){
18689 onValidDrop : function(target, e, id){
18691 if(this.afterValidDrop){
18693 * An empty function by default, but provided so that you can perform a custom action
18694 * after a valid drop has occurred by providing an implementation.
18695 * @param {Object} target The target DD
18696 * @param {Event} e The event object
18697 * @param {String} id The id of the dropped element
18698 * @method afterInvalidDrop
18700 this.afterValidDrop(target, e, id);
18705 getRepairXY : function(e, data){
18706 return this.el.getXY();
18710 onInvalidDrop : function(target, e, id){
18711 this.beforeInvalidDrop(target, e, id);
18712 if(this.cachedTarget){
18713 if(this.cachedTarget.isNotifyTarget){
18714 this.cachedTarget.notifyOut(this, e, this.dragData);
18716 this.cacheTarget = null;
18718 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18720 if(this.afterInvalidDrop){
18722 * An empty function by default, but provided so that you can perform a custom action
18723 * after an invalid drop has occurred by providing an implementation.
18724 * @param {Event} e The event object
18725 * @param {String} id The id of the dropped element
18726 * @method afterInvalidDrop
18728 this.afterInvalidDrop(e, id);
18733 afterRepair : function(){
18735 this.el.highlight(this.hlColor || "c3daf9");
18737 this.dragging = false;
18741 * An empty function by default, but provided so that you can perform a custom action after an invalid
18742 * drop has occurred.
18743 * @param {Roo.dd.DragDrop} target The drop target
18744 * @param {Event} e The event object
18745 * @param {String} id The id of the dragged element
18746 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18748 beforeInvalidDrop : function(target, e, id){
18753 handleMouseDown : function(e){
18754 if(this.dragging) {
18757 var data = this.getDragData(e);
18758 if(data && this.onBeforeDrag(data, e) !== false){
18759 this.dragData = data;
18761 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18766 * An empty function by default, but provided so that you can perform a custom action before the initial
18767 * drag event begins and optionally cancel it.
18768 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18769 * @param {Event} e The event object
18770 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18772 onBeforeDrag : function(data, e){
18777 * An empty function by default, but provided so that you can perform a custom action once the initial
18778 * drag event has begun. The drag cannot be canceled from this function.
18779 * @param {Number} x The x position of the click on the dragged object
18780 * @param {Number} y The y position of the click on the dragged object
18782 onStartDrag : Roo.emptyFn,
18784 // private - YUI override
18785 startDrag : function(x, y){
18786 this.proxy.reset();
18787 this.dragging = true;
18788 this.proxy.update("");
18789 this.onInitDrag(x, y);
18794 onInitDrag : function(x, y){
18795 var clone = this.el.dom.cloneNode(true);
18796 clone.id = Roo.id(); // prevent duplicate ids
18797 this.proxy.update(clone);
18798 this.onStartDrag(x, y);
18803 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18804 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18806 getProxy : function(){
18811 * Hides the drag source's {@link Roo.dd.StatusProxy}
18813 hideProxy : function(){
18815 this.proxy.reset(true);
18816 this.dragging = false;
18820 triggerCacheRefresh : function(){
18821 Roo.dd.DDM.refreshCache(this.groups);
18824 // private - override to prevent hiding
18825 b4EndDrag: function(e) {
18828 // private - override to prevent moving
18829 endDrag : function(e){
18830 this.onEndDrag(this.dragData, e);
18834 onEndDrag : function(data, e){
18837 // private - pin to cursor
18838 autoOffset : function(x, y) {
18839 this.setDelta(-12, -20);
18843 * Ext JS Library 1.1.1
18844 * Copyright(c) 2006-2007, Ext JS, LLC.
18846 * Originally Released Under LGPL - original licence link has changed is not relivant.
18849 * <script type="text/javascript">
18854 * @class Roo.dd.DropTarget
18855 * @extends Roo.dd.DDTarget
18856 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18857 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18859 * @param {String/HTMLElement/Element} el The container element
18860 * @param {Object} config
18862 Roo.dd.DropTarget = function(el, config){
18863 this.el = Roo.get(el);
18865 var listeners = false; ;
18866 if (config && config.listeners) {
18867 listeners= config.listeners;
18868 delete config.listeners;
18870 Roo.apply(this, config);
18872 if(this.containerScroll){
18873 Roo.dd.ScrollManager.register(this.el);
18877 * @scope Roo.dd.DropTarget
18882 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18883 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18884 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18886 * IMPORTANT : it should set this.overClass and this.dropAllowed
18888 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18889 * @param {Event} e The event
18890 * @param {Object} data An object containing arbitrary data supplied by the drag source
18896 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18897 * This method will be called on every mouse movement while the drag source is over the drop target.
18898 * This default implementation simply returns the dropAllowed config value.
18900 * IMPORTANT : it should set this.dropAllowed
18902 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18903 * @param {Event} e The event
18904 * @param {Object} data An object containing arbitrary data supplied by the drag source
18910 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18911 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18912 * overClass (if any) from the drop element.
18914 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18915 * @param {Event} e The event
18916 * @param {Object} data An object containing arbitrary data supplied by the drag source
18922 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18923 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18924 * implementation that does something to process the drop event and returns true so that the drag source's
18925 * repair action does not run.
18927 * IMPORTANT : it should set this.success
18929 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18930 * @param {Event} e The event
18931 * @param {Object} data An object containing arbitrary data supplied by the drag source
18937 Roo.dd.DropTarget.superclass.constructor.call( this,
18939 this.ddGroup || this.group,
18942 listeners : listeners || {}
18950 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18952 * @cfg {String} overClass
18953 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18956 * @cfg {String} ddGroup
18957 * The drag drop group to handle drop events for
18961 * @cfg {String} dropAllowed
18962 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18964 dropAllowed : "x-dd-drop-ok",
18966 * @cfg {String} dropNotAllowed
18967 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18969 dropNotAllowed : "x-dd-drop-nodrop",
18971 * @cfg {boolean} success
18972 * set this after drop listener..
18976 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18977 * if the drop point is valid for over/enter..
18984 isNotifyTarget : true,
18989 notifyEnter : function(dd, e, data)
18992 this.fireEvent('enter', dd, e, data);
18993 if(this.overClass){
18994 this.el.addClass(this.overClass);
18996 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18997 this.valid ? this.dropAllowed : this.dropNotAllowed
19004 notifyOver : function(dd, e, data)
19007 this.fireEvent('over', dd, e, data);
19008 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19009 this.valid ? this.dropAllowed : this.dropNotAllowed
19016 notifyOut : function(dd, e, data)
19018 this.fireEvent('out', dd, e, data);
19019 if(this.overClass){
19020 this.el.removeClass(this.overClass);
19027 notifyDrop : function(dd, e, data)
19029 this.success = false;
19030 this.fireEvent('drop', dd, e, data);
19031 return this.success;
19035 * Ext JS Library 1.1.1
19036 * Copyright(c) 2006-2007, Ext JS, LLC.
19038 * Originally Released Under LGPL - original licence link has changed is not relivant.
19041 * <script type="text/javascript">
19046 * @class Roo.dd.DragZone
19047 * @extends Roo.dd.DragSource
19048 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19049 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19051 * @param {String/HTMLElement/Element} el The container element
19052 * @param {Object} config
19054 Roo.dd.DragZone = function(el, config){
19055 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19056 if(this.containerScroll){
19057 Roo.dd.ScrollManager.register(this.el);
19061 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19063 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19064 * for auto scrolling during drag operations.
19067 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19068 * method after a failed drop (defaults to "c3daf9" - light blue)
19072 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19073 * for a valid target to drag based on the mouse down. Override this method
19074 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19075 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19076 * @param {EventObject} e The mouse down event
19077 * @return {Object} The dragData
19079 getDragData : function(e){
19080 return Roo.dd.Registry.getHandleFromEvent(e);
19084 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19085 * this.dragData.ddel
19086 * @param {Number} x The x position of the click on the dragged object
19087 * @param {Number} y The y position of the click on the dragged object
19088 * @return {Boolean} true to continue the drag, false to cancel
19090 onInitDrag : function(x, y){
19091 this.proxy.update(this.dragData.ddel.cloneNode(true));
19092 this.onStartDrag(x, y);
19097 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19099 afterRepair : function(){
19101 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19103 this.dragging = false;
19107 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19108 * the XY of this.dragData.ddel
19109 * @param {EventObject} e The mouse up event
19110 * @return {Array} The xy location (e.g. [100, 200])
19112 getRepairXY : function(e){
19113 return Roo.Element.fly(this.dragData.ddel).getXY();
19117 * Ext JS Library 1.1.1
19118 * Copyright(c) 2006-2007, Ext JS, LLC.
19120 * Originally Released Under LGPL - original licence link has changed is not relivant.
19123 * <script type="text/javascript">
19126 * @class Roo.dd.DropZone
19127 * @extends Roo.dd.DropTarget
19128 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19129 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19131 * @param {String/HTMLElement/Element} el The container element
19132 * @param {Object} config
19134 Roo.dd.DropZone = function(el, config){
19135 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19138 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19140 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19141 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19142 * provide your own custom lookup.
19143 * @param {Event} e The event
19144 * @return {Object} data The custom data
19146 getTargetFromEvent : function(e){
19147 return Roo.dd.Registry.getTargetFromEvent(e);
19151 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19152 * that it has registered. This method has no default implementation and should be overridden to provide
19153 * node-specific processing if necessary.
19154 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19155 * {@link #getTargetFromEvent} for this node)
19156 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19157 * @param {Event} e The event
19158 * @param {Object} data An object containing arbitrary data supplied by the drag source
19160 onNodeEnter : function(n, dd, e, data){
19165 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19166 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19167 * overridden to provide the proper feedback.
19168 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19169 * {@link #getTargetFromEvent} for this node)
19170 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19171 * @param {Event} e The event
19172 * @param {Object} data An object containing arbitrary data supplied by the drag source
19173 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19174 * underlying {@link Roo.dd.StatusProxy} can be updated
19176 onNodeOver : function(n, dd, e, data){
19177 return this.dropAllowed;
19181 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19182 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19183 * node-specific processing if necessary.
19184 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19185 * {@link #getTargetFromEvent} for this node)
19186 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19187 * @param {Event} e The event
19188 * @param {Object} data An object containing arbitrary data supplied by the drag source
19190 onNodeOut : function(n, dd, e, data){
19195 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19196 * the drop node. The default implementation returns false, so it should be overridden to provide the
19197 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19198 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19199 * {@link #getTargetFromEvent} for this node)
19200 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19201 * @param {Event} e The event
19202 * @param {Object} data An object containing arbitrary data supplied by the drag source
19203 * @return {Boolean} True if the drop was valid, else false
19205 onNodeDrop : function(n, dd, e, data){
19210 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19211 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19212 * it should be overridden to provide the proper feedback if necessary.
19213 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19214 * @param {Event} e The event
19215 * @param {Object} data An object containing arbitrary data supplied by the drag source
19216 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19217 * underlying {@link Roo.dd.StatusProxy} can be updated
19219 onContainerOver : function(dd, e, data){
19220 return this.dropNotAllowed;
19224 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19225 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19226 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19227 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19228 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19229 * @param {Event} e The event
19230 * @param {Object} data An object containing arbitrary data supplied by the drag source
19231 * @return {Boolean} True if the drop was valid, else false
19233 onContainerDrop : function(dd, e, data){
19238 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19239 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19240 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19241 * you should override this method and provide a custom implementation.
19242 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19243 * @param {Event} e The event
19244 * @param {Object} data An object containing arbitrary data supplied by the drag source
19245 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19246 * underlying {@link Roo.dd.StatusProxy} can be updated
19248 notifyEnter : function(dd, e, data){
19249 return this.dropNotAllowed;
19253 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19254 * This method will be called on every mouse movement while the drag source is over the drop zone.
19255 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19256 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19257 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19258 * registered node, it will call {@link #onContainerOver}.
19259 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19260 * @param {Event} e The event
19261 * @param {Object} data An object containing arbitrary data supplied by the drag source
19262 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19263 * underlying {@link Roo.dd.StatusProxy} can be updated
19265 notifyOver : function(dd, e, data){
19266 var n = this.getTargetFromEvent(e);
19267 if(!n){ // not over valid drop target
19268 if(this.lastOverNode){
19269 this.onNodeOut(this.lastOverNode, dd, e, data);
19270 this.lastOverNode = null;
19272 return this.onContainerOver(dd, e, data);
19274 if(this.lastOverNode != n){
19275 if(this.lastOverNode){
19276 this.onNodeOut(this.lastOverNode, dd, e, data);
19278 this.onNodeEnter(n, dd, e, data);
19279 this.lastOverNode = n;
19281 return this.onNodeOver(n, dd, e, data);
19285 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19286 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19287 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19288 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19289 * @param {Event} e The event
19290 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19292 notifyOut : function(dd, e, data){
19293 if(this.lastOverNode){
19294 this.onNodeOut(this.lastOverNode, dd, e, data);
19295 this.lastOverNode = null;
19300 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19301 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19302 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19303 * otherwise it will call {@link #onContainerDrop}.
19304 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19305 * @param {Event} e The event
19306 * @param {Object} data An object containing arbitrary data supplied by the drag source
19307 * @return {Boolean} True if the drop was valid, else false
19309 notifyDrop : function(dd, e, data){
19310 if(this.lastOverNode){
19311 this.onNodeOut(this.lastOverNode, dd, e, data);
19312 this.lastOverNode = null;
19314 var n = this.getTargetFromEvent(e);
19316 this.onNodeDrop(n, dd, e, data) :
19317 this.onContainerDrop(dd, e, data);
19321 triggerCacheRefresh : function(){
19322 Roo.dd.DDM.refreshCache(this.groups);
19326 * Ext JS Library 1.1.1
19327 * Copyright(c) 2006-2007, Ext JS, LLC.
19329 * Originally Released Under LGPL - original licence link has changed is not relivant.
19332 * <script type="text/javascript">
19337 * @class Roo.data.SortTypes
19339 * Defines the default sorting (casting?) comparison functions used when sorting data.
19341 Roo.data.SortTypes = {
19343 * Default sort that does nothing
19344 * @param {Mixed} s The value being converted
19345 * @return {Mixed} The comparison value
19347 none : function(s){
19352 * The regular expression used to strip tags
19356 stripTagsRE : /<\/?[^>]+>/gi,
19359 * Strips all HTML tags to sort on text only
19360 * @param {Mixed} s The value being converted
19361 * @return {String} The comparison value
19363 asText : function(s){
19364 return String(s).replace(this.stripTagsRE, "");
19368 * Strips all HTML tags to sort on text only - Case insensitive
19369 * @param {Mixed} s The value being converted
19370 * @return {String} The comparison value
19372 asUCText : function(s){
19373 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19377 * Case insensitive string
19378 * @param {Mixed} s The value being converted
19379 * @return {String} The comparison value
19381 asUCString : function(s) {
19382 return String(s).toUpperCase();
19387 * @param {Mixed} s The value being converted
19388 * @return {Number} The comparison value
19390 asDate : function(s) {
19394 if(s instanceof Date){
19395 return s.getTime();
19397 return Date.parse(String(s));
19402 * @param {Mixed} s The value being converted
19403 * @return {Float} The comparison value
19405 asFloat : function(s) {
19406 var val = parseFloat(String(s).replace(/,/g, ""));
19407 if(isNaN(val)) val = 0;
19413 * @param {Mixed} s The value being converted
19414 * @return {Number} The comparison value
19416 asInt : function(s) {
19417 var val = parseInt(String(s).replace(/,/g, ""));
19418 if(isNaN(val)) val = 0;
19423 * Ext JS Library 1.1.1
19424 * Copyright(c) 2006-2007, Ext JS, LLC.
19426 * Originally Released Under LGPL - original licence link has changed is not relivant.
19429 * <script type="text/javascript">
19433 * @class Roo.data.Record
19434 * Instances of this class encapsulate both record <em>definition</em> information, and record
19435 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19436 * to access Records cached in an {@link Roo.data.Store} object.<br>
19438 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19439 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19442 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19444 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19445 * {@link #create}. The parameters are the same.
19446 * @param {Array} data An associative Array of data values keyed by the field name.
19447 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19448 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19449 * not specified an integer id is generated.
19451 Roo.data.Record = function(data, id){
19452 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19457 * Generate a constructor for a specific record layout.
19458 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19459 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19460 * Each field definition object may contain the following properties: <ul>
19461 * <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,
19462 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19463 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19464 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19465 * is being used, then this is a string containing the javascript expression to reference the data relative to
19466 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19467 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19468 * this may be omitted.</p></li>
19469 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19470 * <ul><li>auto (Default, implies no conversion)</li>
19475 * <li>date</li></ul></p></li>
19476 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19477 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19478 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19479 * by the Reader into an object that will be stored in the Record. It is passed the
19480 * following parameters:<ul>
19481 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19483 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19485 * <br>usage:<br><pre><code>
19486 var TopicRecord = Roo.data.Record.create(
19487 {name: 'title', mapping: 'topic_title'},
19488 {name: 'author', mapping: 'username'},
19489 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19490 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19491 {name: 'lastPoster', mapping: 'user2'},
19492 {name: 'excerpt', mapping: 'post_text'}
19495 var myNewRecord = new TopicRecord({
19496 title: 'Do my job please',
19499 lastPost: new Date(),
19500 lastPoster: 'Animal',
19501 excerpt: 'No way dude!'
19503 myStore.add(myNewRecord);
19508 Roo.data.Record.create = function(o){
19509 var f = function(){
19510 f.superclass.constructor.apply(this, arguments);
19512 Roo.extend(f, Roo.data.Record);
19513 var p = f.prototype;
19514 p.fields = new Roo.util.MixedCollection(false, function(field){
19517 for(var i = 0, len = o.length; i < len; i++){
19518 p.fields.add(new Roo.data.Field(o[i]));
19520 f.getField = function(name){
19521 return p.fields.get(name);
19526 Roo.data.Record.AUTO_ID = 1000;
19527 Roo.data.Record.EDIT = 'edit';
19528 Roo.data.Record.REJECT = 'reject';
19529 Roo.data.Record.COMMIT = 'commit';
19531 Roo.data.Record.prototype = {
19533 * Readonly flag - true if this record has been modified.
19542 join : function(store){
19543 this.store = store;
19547 * Set the named field to the specified value.
19548 * @param {String} name The name of the field to set.
19549 * @param {Object} value The value to set the field to.
19551 set : function(name, value){
19552 if(this.data[name] == value){
19556 if(!this.modified){
19557 this.modified = {};
19559 if(typeof this.modified[name] == 'undefined'){
19560 this.modified[name] = this.data[name];
19562 this.data[name] = value;
19563 if(!this.editing && this.store){
19564 this.store.afterEdit(this);
19569 * Get the value of the named field.
19570 * @param {String} name The name of the field to get the value of.
19571 * @return {Object} The value of the field.
19573 get : function(name){
19574 return this.data[name];
19578 beginEdit : function(){
19579 this.editing = true;
19580 this.modified = {};
19584 cancelEdit : function(){
19585 this.editing = false;
19586 delete this.modified;
19590 endEdit : function(){
19591 this.editing = false;
19592 if(this.dirty && this.store){
19593 this.store.afterEdit(this);
19598 * Usually called by the {@link Roo.data.Store} which owns the Record.
19599 * Rejects all changes made to the Record since either creation, or the last commit operation.
19600 * Modified fields are reverted to their original values.
19602 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19603 * of reject operations.
19605 reject : function(){
19606 var m = this.modified;
19608 if(typeof m[n] != "function"){
19609 this.data[n] = m[n];
19612 this.dirty = false;
19613 delete this.modified;
19614 this.editing = false;
19616 this.store.afterReject(this);
19621 * Usually called by the {@link Roo.data.Store} which owns the Record.
19622 * Commits all changes made to the Record since either creation, or the last commit operation.
19624 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19625 * of commit operations.
19627 commit : function(){
19628 this.dirty = false;
19629 delete this.modified;
19630 this.editing = false;
19632 this.store.afterCommit(this);
19637 hasError : function(){
19638 return this.error != null;
19642 clearError : function(){
19647 * Creates a copy of this record.
19648 * @param {String} id (optional) A new record id if you don't want to use this record's id
19651 copy : function(newId) {
19652 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19656 * Ext JS Library 1.1.1
19657 * Copyright(c) 2006-2007, Ext JS, LLC.
19659 * Originally Released Under LGPL - original licence link has changed is not relivant.
19662 * <script type="text/javascript">
19668 * @class Roo.data.Store
19669 * @extends Roo.util.Observable
19670 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19671 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19673 * 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
19674 * has no knowledge of the format of the data returned by the Proxy.<br>
19676 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19677 * instances from the data object. These records are cached and made available through accessor functions.
19679 * Creates a new Store.
19680 * @param {Object} config A config object containing the objects needed for the Store to access data,
19681 * and read the data into Records.
19683 Roo.data.Store = function(config){
19684 this.data = new Roo.util.MixedCollection(false);
19685 this.data.getKey = function(o){
19688 this.baseParams = {};
19690 this.paramNames = {
19695 "multisort" : "_multisort"
19698 if(config && config.data){
19699 this.inlineData = config.data;
19700 delete config.data;
19703 Roo.apply(this, config);
19705 if(this.reader){ // reader passed
19706 this.reader = Roo.factory(this.reader, Roo.data);
19707 this.reader.xmodule = this.xmodule || false;
19708 if(!this.recordType){
19709 this.recordType = this.reader.recordType;
19711 if(this.reader.onMetaChange){
19712 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19716 if(this.recordType){
19717 this.fields = this.recordType.prototype.fields;
19719 this.modified = [];
19723 * @event datachanged
19724 * Fires when the data cache has changed, and a widget which is using this Store
19725 * as a Record cache should refresh its view.
19726 * @param {Store} this
19728 datachanged : true,
19730 * @event metachange
19731 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19732 * @param {Store} this
19733 * @param {Object} meta The JSON metadata
19738 * Fires when Records have been added to the Store
19739 * @param {Store} this
19740 * @param {Roo.data.Record[]} records The array of Records added
19741 * @param {Number} index The index at which the record(s) were added
19746 * Fires when a Record has been removed from the Store
19747 * @param {Store} this
19748 * @param {Roo.data.Record} record The Record that was removed
19749 * @param {Number} index The index at which the record was removed
19754 * Fires when a Record has been updated
19755 * @param {Store} this
19756 * @param {Roo.data.Record} record The Record that was updated
19757 * @param {String} operation The update operation being performed. Value may be one of:
19759 Roo.data.Record.EDIT
19760 Roo.data.Record.REJECT
19761 Roo.data.Record.COMMIT
19767 * Fires when the data cache has been cleared.
19768 * @param {Store} this
19772 * @event beforeload
19773 * Fires before a request is made for a new data object. If the beforeload handler returns false
19774 * the load action will be canceled.
19775 * @param {Store} this
19776 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19780 * @event beforeloadadd
19781 * Fires after a new set of Records has been loaded.
19782 * @param {Store} this
19783 * @param {Roo.data.Record[]} records The Records that were loaded
19784 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19786 beforeloadadd : true,
19789 * Fires after a new set of Records has been loaded, before they are added to the store.
19790 * @param {Store} this
19791 * @param {Roo.data.Record[]} records The Records that were loaded
19792 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19793 * @params {Object} return from reader
19797 * @event loadexception
19798 * Fires if an exception occurs in the Proxy during loading.
19799 * Called with the signature of the Proxy's "loadexception" event.
19800 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19803 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19804 * @param {Object} load options
19805 * @param {Object} jsonData from your request (normally this contains the Exception)
19807 loadexception : true
19811 this.proxy = Roo.factory(this.proxy, Roo.data);
19812 this.proxy.xmodule = this.xmodule || false;
19813 this.relayEvents(this.proxy, ["loadexception"]);
19815 this.sortToggle = {};
19816 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19818 Roo.data.Store.superclass.constructor.call(this);
19820 if(this.inlineData){
19821 this.loadData(this.inlineData);
19822 delete this.inlineData;
19826 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19828 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19829 * without a remote query - used by combo/forms at present.
19833 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19836 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19839 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19840 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19843 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19844 * on any HTTP request
19847 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19850 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19854 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19855 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19857 remoteSort : false,
19860 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19861 * loaded or when a record is removed. (defaults to false).
19863 pruneModifiedRecords : false,
19866 lastOptions : null,
19869 * Add Records to the Store and fires the add event.
19870 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19872 add : function(records){
19873 records = [].concat(records);
19874 for(var i = 0, len = records.length; i < len; i++){
19875 records[i].join(this);
19877 var index = this.data.length;
19878 this.data.addAll(records);
19879 this.fireEvent("add", this, records, index);
19883 * Remove a Record from the Store and fires the remove event.
19884 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19886 remove : function(record){
19887 var index = this.data.indexOf(record);
19888 this.data.removeAt(index);
19889 if(this.pruneModifiedRecords){
19890 this.modified.remove(record);
19892 this.fireEvent("remove", this, record, index);
19896 * Remove all Records from the Store and fires the clear event.
19898 removeAll : function(){
19900 if(this.pruneModifiedRecords){
19901 this.modified = [];
19903 this.fireEvent("clear", this);
19907 * Inserts Records to the Store at the given index and fires the add event.
19908 * @param {Number} index The start index at which to insert the passed Records.
19909 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19911 insert : function(index, records){
19912 records = [].concat(records);
19913 for(var i = 0, len = records.length; i < len; i++){
19914 this.data.insert(index, records[i]);
19915 records[i].join(this);
19917 this.fireEvent("add", this, records, index);
19921 * Get the index within the cache of the passed Record.
19922 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19923 * @return {Number} The index of the passed Record. Returns -1 if not found.
19925 indexOf : function(record){
19926 return this.data.indexOf(record);
19930 * Get the index within the cache of the Record with the passed id.
19931 * @param {String} id The id of the Record to find.
19932 * @return {Number} The index of the Record. Returns -1 if not found.
19934 indexOfId : function(id){
19935 return this.data.indexOfKey(id);
19939 * Get the Record with the specified id.
19940 * @param {String} id The id of the Record to find.
19941 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19943 getById : function(id){
19944 return this.data.key(id);
19948 * Get the Record at the specified index.
19949 * @param {Number} index The index of the Record to find.
19950 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19952 getAt : function(index){
19953 return this.data.itemAt(index);
19957 * Returns a range of Records between specified indices.
19958 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19959 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19960 * @return {Roo.data.Record[]} An array of Records
19962 getRange : function(start, end){
19963 return this.data.getRange(start, end);
19967 storeOptions : function(o){
19968 o = Roo.apply({}, o);
19971 this.lastOptions = o;
19975 * Loads the Record cache from the configured Proxy using the configured Reader.
19977 * If using remote paging, then the first load call must specify the <em>start</em>
19978 * and <em>limit</em> properties in the options.params property to establish the initial
19979 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19981 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19982 * and this call will return before the new data has been loaded. Perform any post-processing
19983 * in a callback function, or in a "load" event handler.</strong>
19985 * @param {Object} options An object containing properties which control loading options:<ul>
19986 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19987 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19988 * passed the following arguments:<ul>
19989 * <li>r : Roo.data.Record[]</li>
19990 * <li>options: Options object from the load call</li>
19991 * <li>success: Boolean success indicator</li></ul></li>
19992 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19993 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19996 load : function(options){
19997 options = options || {};
19998 if(this.fireEvent("beforeload", this, options) !== false){
19999 this.storeOptions(options);
20000 var p = Roo.apply(options.params || {}, this.baseParams);
20001 // if meta was not loaded from remote source.. try requesting it.
20002 if (!this.reader.metaFromRemote) {
20003 p._requestMeta = 1;
20005 if(this.sortInfo && this.remoteSort){
20006 var pn = this.paramNames;
20007 p[pn["sort"]] = this.sortInfo.field;
20008 p[pn["dir"]] = this.sortInfo.direction;
20010 if (this.multiSort) {
20011 var pn = this.paramNames;
20012 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
20015 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20020 * Reloads the Record cache from the configured Proxy using the configured Reader and
20021 * the options from the last load operation performed.
20022 * @param {Object} options (optional) An object containing properties which may override the options
20023 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20024 * the most recently used options are reused).
20026 reload : function(options){
20027 this.load(Roo.applyIf(options||{}, this.lastOptions));
20031 // Called as a callback by the Reader during a load operation.
20032 loadRecords : function(o, options, success){
20033 if(!o || success === false){
20034 if(success !== false){
20035 this.fireEvent("load", this, [], options, o);
20037 if(options.callback){
20038 options.callback.call(options.scope || this, [], options, false);
20042 // if data returned failure - throw an exception.
20043 if (o.success === false) {
20044 // show a message if no listener is registered.
20045 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
20046 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
20048 // loadmask wil be hooked into this..
20049 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
20052 var r = o.records, t = o.totalRecords || r.length;
20054 this.fireEvent("beforeloadadd", this, r, options, o);
20056 if(!options || options.add !== true){
20057 if(this.pruneModifiedRecords){
20058 this.modified = [];
20060 for(var i = 0, len = r.length; i < len; i++){
20064 this.data = this.snapshot;
20065 delete this.snapshot;
20068 this.data.addAll(r);
20069 this.totalLength = t;
20071 this.fireEvent("datachanged", this);
20073 this.totalLength = Math.max(t, this.data.length+r.length);
20076 this.fireEvent("load", this, r, options, o);
20077 if(options.callback){
20078 options.callback.call(options.scope || this, r, options, true);
20084 * Loads data from a passed data block. A Reader which understands the format of the data
20085 * must have been configured in the constructor.
20086 * @param {Object} data The data block from which to read the Records. The format of the data expected
20087 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20088 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20090 loadData : function(o, append){
20091 var r = this.reader.readRecords(o);
20092 this.loadRecords(r, {add: append}, true);
20096 * Gets the number of cached records.
20098 * <em>If using paging, this may not be the total size of the dataset. If the data object
20099 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20100 * the data set size</em>
20102 getCount : function(){
20103 return this.data.length || 0;
20107 * Gets the total number of records in the dataset as returned by the server.
20109 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20110 * the dataset size</em>
20112 getTotalCount : function(){
20113 return this.totalLength || 0;
20117 * Returns the sort state of the Store as an object with two properties:
20119 field {String} The name of the field by which the Records are sorted
20120 direction {String} The sort order, "ASC" or "DESC"
20123 getSortState : function(){
20124 return this.sortInfo;
20128 applySort : function(){
20129 if(this.sortInfo && !this.remoteSort){
20130 var s = this.sortInfo, f = s.field;
20131 var st = this.fields.get(f).sortType;
20132 var fn = function(r1, r2){
20133 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20134 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20136 this.data.sort(s.direction, fn);
20137 if(this.snapshot && this.snapshot != this.data){
20138 this.snapshot.sort(s.direction, fn);
20144 * Sets the default sort column and order to be used by the next load operation.
20145 * @param {String} fieldName The name of the field to sort by.
20146 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20148 setDefaultSort : function(field, dir){
20149 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20153 * Sort the Records.
20154 * If remote sorting is used, the sort is performed on the server, and the cache is
20155 * reloaded. If local sorting is used, the cache is sorted internally.
20156 * @param {String} fieldName The name of the field to sort by.
20157 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20159 sort : function(fieldName, dir){
20160 var f = this.fields.get(fieldName);
20162 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20164 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20165 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20170 this.sortToggle[f.name] = dir;
20171 this.sortInfo = {field: f.name, direction: dir};
20172 if(!this.remoteSort){
20174 this.fireEvent("datachanged", this);
20176 this.load(this.lastOptions);
20181 * Calls the specified function for each of the Records in the cache.
20182 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20183 * Returning <em>false</em> aborts and exits the iteration.
20184 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20186 each : function(fn, scope){
20187 this.data.each(fn, scope);
20191 * Gets all records modified since the last commit. Modified records are persisted across load operations
20192 * (e.g., during paging).
20193 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20195 getModifiedRecords : function(){
20196 return this.modified;
20200 createFilterFn : function(property, value, anyMatch){
20201 if(!value.exec){ // not a regex
20202 value = String(value);
20203 if(value.length == 0){
20206 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20208 return function(r){
20209 return value.test(r.data[property]);
20214 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20215 * @param {String} property A field on your records
20216 * @param {Number} start The record index to start at (defaults to 0)
20217 * @param {Number} end The last record index to include (defaults to length - 1)
20218 * @return {Number} The sum
20220 sum : function(property, start, end){
20221 var rs = this.data.items, v = 0;
20222 start = start || 0;
20223 end = (end || end === 0) ? end : rs.length-1;
20225 for(var i = start; i <= end; i++){
20226 v += (rs[i].data[property] || 0);
20232 * Filter the records by a specified property.
20233 * @param {String} field A field on your records
20234 * @param {String/RegExp} value Either a string that the field
20235 * should start with or a RegExp to test against the field
20236 * @param {Boolean} anyMatch True to match any part not just the beginning
20238 filter : function(property, value, anyMatch){
20239 var fn = this.createFilterFn(property, value, anyMatch);
20240 return fn ? this.filterBy(fn) : this.clearFilter();
20244 * Filter by a function. The specified function will be called with each
20245 * record in this data source. If the function returns true the record is included,
20246 * otherwise it is filtered.
20247 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20248 * @param {Object} scope (optional) The scope of the function (defaults to this)
20250 filterBy : function(fn, scope){
20251 this.snapshot = this.snapshot || this.data;
20252 this.data = this.queryBy(fn, scope||this);
20253 this.fireEvent("datachanged", this);
20257 * Query the records by a specified property.
20258 * @param {String} field A field on your records
20259 * @param {String/RegExp} value Either a string that the field
20260 * should start with or a RegExp to test against the field
20261 * @param {Boolean} anyMatch True to match any part not just the beginning
20262 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20264 query : function(property, value, anyMatch){
20265 var fn = this.createFilterFn(property, value, anyMatch);
20266 return fn ? this.queryBy(fn) : this.data.clone();
20270 * Query by a function. The specified function will be called with each
20271 * record in this data source. If the function returns true the record is included
20273 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20274 * @param {Object} scope (optional) The scope of the function (defaults to this)
20275 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20277 queryBy : function(fn, scope){
20278 var data = this.snapshot || this.data;
20279 return data.filterBy(fn, scope||this);
20283 * Collects unique values for a particular dataIndex from this store.
20284 * @param {String} dataIndex The property to collect
20285 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20286 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20287 * @return {Array} An array of the unique values
20289 collect : function(dataIndex, allowNull, bypassFilter){
20290 var d = (bypassFilter === true && this.snapshot) ?
20291 this.snapshot.items : this.data.items;
20292 var v, sv, r = [], l = {};
20293 for(var i = 0, len = d.length; i < len; i++){
20294 v = d[i].data[dataIndex];
20296 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20305 * Revert to a view of the Record cache with no filtering applied.
20306 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20308 clearFilter : function(suppressEvent){
20309 if(this.snapshot && this.snapshot != this.data){
20310 this.data = this.snapshot;
20311 delete this.snapshot;
20312 if(suppressEvent !== true){
20313 this.fireEvent("datachanged", this);
20319 afterEdit : function(record){
20320 if(this.modified.indexOf(record) == -1){
20321 this.modified.push(record);
20323 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20327 afterReject : function(record){
20328 this.modified.remove(record);
20329 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20333 afterCommit : function(record){
20334 this.modified.remove(record);
20335 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20339 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20340 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20342 commitChanges : function(){
20343 var m = this.modified.slice(0);
20344 this.modified = [];
20345 for(var i = 0, len = m.length; i < len; i++){
20351 * Cancel outstanding changes on all changed records.
20353 rejectChanges : function(){
20354 var m = this.modified.slice(0);
20355 this.modified = [];
20356 for(var i = 0, len = m.length; i < len; i++){
20361 onMetaChange : function(meta, rtype, o){
20362 this.recordType = rtype;
20363 this.fields = rtype.prototype.fields;
20364 delete this.snapshot;
20365 this.sortInfo = meta.sortInfo || this.sortInfo;
20366 this.modified = [];
20367 this.fireEvent('metachange', this, this.reader.meta);
20371 * Ext JS Library 1.1.1
20372 * Copyright(c) 2006-2007, Ext JS, LLC.
20374 * Originally Released Under LGPL - original licence link has changed is not relivant.
20377 * <script type="text/javascript">
20381 * @class Roo.data.SimpleStore
20382 * @extends Roo.data.Store
20383 * Small helper class to make creating Stores from Array data easier.
20384 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20385 * @cfg {Array} fields An array of field definition objects, or field name strings.
20386 * @cfg {Array} data The multi-dimensional array of data
20388 * @param {Object} config
20390 Roo.data.SimpleStore = function(config){
20391 Roo.data.SimpleStore.superclass.constructor.call(this, {
20393 reader: new Roo.data.ArrayReader({
20396 Roo.data.Record.create(config.fields)
20398 proxy : new Roo.data.MemoryProxy(config.data)
20402 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
20404 * Ext JS Library 1.1.1
20405 * Copyright(c) 2006-2007, Ext JS, LLC.
20407 * Originally Released Under LGPL - original licence link has changed is not relivant.
20410 * <script type="text/javascript">
20415 * @extends Roo.data.Store
20416 * @class Roo.data.JsonStore
20417 * Small helper class to make creating Stores for JSON data easier. <br/>
20419 var store = new Roo.data.JsonStore({
20420 url: 'get-images.php',
20422 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20425 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20426 * JsonReader and HttpProxy (unless inline data is provided).</b>
20427 * @cfg {Array} fields An array of field definition objects, or field name strings.
20429 * @param {Object} config
20431 Roo.data.JsonStore = function(c){
20432 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20433 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20434 reader: new Roo.data.JsonReader(c, c.fields)
20437 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20439 * Ext JS Library 1.1.1
20440 * Copyright(c) 2006-2007, Ext JS, LLC.
20442 * Originally Released Under LGPL - original licence link has changed is not relivant.
20445 * <script type="text/javascript">
20449 Roo.data.Field = function(config){
20450 if(typeof config == "string"){
20451 config = {name: config};
20453 Roo.apply(this, config);
20456 this.type = "auto";
20459 var st = Roo.data.SortTypes;
20460 // named sortTypes are supported, here we look them up
20461 if(typeof this.sortType == "string"){
20462 this.sortType = st[this.sortType];
20465 // set default sortType for strings and dates
20466 if(!this.sortType){
20469 this.sortType = st.asUCString;
20472 this.sortType = st.asDate;
20475 this.sortType = st.none;
20480 var stripRe = /[\$,%]/g;
20482 // prebuilt conversion function for this field, instead of
20483 // switching every time we're reading a value
20485 var cv, dateFormat = this.dateFormat;
20490 cv = function(v){ return v; };
20493 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20497 return v !== undefined && v !== null && v !== '' ?
20498 parseInt(String(v).replace(stripRe, ""), 10) : '';
20503 return v !== undefined && v !== null && v !== '' ?
20504 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20509 cv = function(v){ return v === true || v === "true" || v == 1; };
20516 if(v instanceof Date){
20520 if(dateFormat == "timestamp"){
20521 return new Date(v*1000);
20523 return Date.parseDate(v, dateFormat);
20525 var parsed = Date.parse(v);
20526 return parsed ? new Date(parsed) : null;
20535 Roo.data.Field.prototype = {
20543 * Ext JS Library 1.1.1
20544 * Copyright(c) 2006-2007, Ext JS, LLC.
20546 * Originally Released Under LGPL - original licence link has changed is not relivant.
20549 * <script type="text/javascript">
20552 // Base class for reading structured data from a data source. This class is intended to be
20553 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20556 * @class Roo.data.DataReader
20557 * Base class for reading structured data from a data source. This class is intended to be
20558 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20561 Roo.data.DataReader = function(meta, recordType){
20565 this.recordType = recordType instanceof Array ?
20566 Roo.data.Record.create(recordType) : recordType;
20569 Roo.data.DataReader.prototype = {
20571 * Create an empty record
20572 * @param {Object} data (optional) - overlay some values
20573 * @return {Roo.data.Record} record created.
20575 newRow : function(d) {
20577 this.recordType.prototype.fields.each(function(c) {
20579 case 'int' : da[c.name] = 0; break;
20580 case 'date' : da[c.name] = new Date(); break;
20581 case 'float' : da[c.name] = 0.0; break;
20582 case 'boolean' : da[c.name] = false; break;
20583 default : da[c.name] = ""; break;
20587 return new this.recordType(Roo.apply(da, d));
20592 * Ext JS Library 1.1.1
20593 * Copyright(c) 2006-2007, Ext JS, LLC.
20595 * Originally Released Under LGPL - original licence link has changed is not relivant.
20598 * <script type="text/javascript">
20602 * @class Roo.data.DataProxy
20603 * @extends Roo.data.Observable
20604 * This class is an abstract base class for implementations which provide retrieval of
20605 * unformatted data objects.<br>
20607 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20608 * (of the appropriate type which knows how to parse the data object) to provide a block of
20609 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20611 * Custom implementations must implement the load method as described in
20612 * {@link Roo.data.HttpProxy#load}.
20614 Roo.data.DataProxy = function(){
20617 * @event beforeload
20618 * Fires before a network request is made to retrieve a data object.
20619 * @param {Object} This DataProxy object.
20620 * @param {Object} params The params parameter to the load function.
20625 * Fires before the load method's callback is called.
20626 * @param {Object} This DataProxy object.
20627 * @param {Object} o The data object.
20628 * @param {Object} arg The callback argument object passed to the load function.
20632 * @event loadexception
20633 * Fires if an Exception occurs during data retrieval.
20634 * @param {Object} This DataProxy object.
20635 * @param {Object} o The data object.
20636 * @param {Object} arg The callback argument object passed to the load function.
20637 * @param {Object} e The Exception.
20639 loadexception : true
20641 Roo.data.DataProxy.superclass.constructor.call(this);
20644 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20647 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20651 * Ext JS Library 1.1.1
20652 * Copyright(c) 2006-2007, Ext JS, LLC.
20654 * Originally Released Under LGPL - original licence link has changed is not relivant.
20657 * <script type="text/javascript">
20660 * @class Roo.data.MemoryProxy
20661 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20662 * to the Reader when its load method is called.
20664 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20666 Roo.data.MemoryProxy = function(data){
20670 Roo.data.MemoryProxy.superclass.constructor.call(this);
20674 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20676 * Load data from the requested source (in this case an in-memory
20677 * data object passed to the constructor), read the data object into
20678 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20679 * process that block using the passed callback.
20680 * @param {Object} params This parameter is not used by the MemoryProxy class.
20681 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20682 * object into a block of Roo.data.Records.
20683 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20684 * The function must be passed <ul>
20685 * <li>The Record block object</li>
20686 * <li>The "arg" argument from the load function</li>
20687 * <li>A boolean success indicator</li>
20689 * @param {Object} scope The scope in which to call the callback
20690 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20692 load : function(params, reader, callback, scope, arg){
20693 params = params || {};
20696 result = reader.readRecords(this.data);
20698 this.fireEvent("loadexception", this, arg, null, e);
20699 callback.call(scope, null, arg, false);
20702 callback.call(scope, result, arg, true);
20706 update : function(params, records){
20711 * Ext JS Library 1.1.1
20712 * Copyright(c) 2006-2007, Ext JS, LLC.
20714 * Originally Released Under LGPL - original licence link has changed is not relivant.
20717 * <script type="text/javascript">
20720 * @class Roo.data.HttpProxy
20721 * @extends Roo.data.DataProxy
20722 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20723 * configured to reference a certain URL.<br><br>
20725 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20726 * from which the running page was served.<br><br>
20728 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20730 * Be aware that to enable the browser to parse an XML document, the server must set
20731 * the Content-Type header in the HTTP response to "text/xml".
20733 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20734 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20735 * will be used to make the request.
20737 Roo.data.HttpProxy = function(conn){
20738 Roo.data.HttpProxy.superclass.constructor.call(this);
20739 // is conn a conn config or a real conn?
20741 this.useAjax = !conn || !conn.events;
20745 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20746 // thse are take from connection...
20749 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20752 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20753 * extra parameters to each request made by this object. (defaults to undefined)
20756 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20757 * to each request made by this object. (defaults to undefined)
20760 * @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)
20763 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20766 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20772 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20776 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20777 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20778 * a finer-grained basis than the DataProxy events.
20780 getConnection : function(){
20781 return this.useAjax ? Roo.Ajax : this.conn;
20785 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20786 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20787 * process that block using the passed callback.
20788 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20789 * for the request to the remote server.
20790 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20791 * object into a block of Roo.data.Records.
20792 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20793 * The function must be passed <ul>
20794 * <li>The Record block object</li>
20795 * <li>The "arg" argument from the load function</li>
20796 * <li>A boolean success indicator</li>
20798 * @param {Object} scope The scope in which to call the callback
20799 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20801 load : function(params, reader, callback, scope, arg){
20802 if(this.fireEvent("beforeload", this, params) !== false){
20804 params : params || {},
20806 callback : callback,
20811 callback : this.loadResponse,
20815 Roo.applyIf(o, this.conn);
20816 if(this.activeRequest){
20817 Roo.Ajax.abort(this.activeRequest);
20819 this.activeRequest = Roo.Ajax.request(o);
20821 this.conn.request(o);
20824 callback.call(scope||this, null, arg, false);
20829 loadResponse : function(o, success, response){
20830 delete this.activeRequest;
20832 this.fireEvent("loadexception", this, o, response);
20833 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20838 result = o.reader.read(response);
20840 this.fireEvent("loadexception", this, o, response, e);
20841 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20845 this.fireEvent("load", this, o, o.request.arg);
20846 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20850 update : function(dataSet){
20855 updateResponse : function(dataSet){
20860 * Ext JS Library 1.1.1
20861 * Copyright(c) 2006-2007, Ext JS, LLC.
20863 * Originally Released Under LGPL - original licence link has changed is not relivant.
20866 * <script type="text/javascript">
20870 * @class Roo.data.ScriptTagProxy
20871 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20872 * other than the originating domain of the running page.<br><br>
20874 * <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
20875 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20877 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20878 * source code that is used as the source inside a <script> tag.<br><br>
20880 * In order for the browser to process the returned data, the server must wrap the data object
20881 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20882 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20883 * depending on whether the callback name was passed:
20886 boolean scriptTag = false;
20887 String cb = request.getParameter("callback");
20890 response.setContentType("text/javascript");
20892 response.setContentType("application/x-json");
20894 Writer out = response.getWriter();
20896 out.write(cb + "(");
20898 out.print(dataBlock.toJsonString());
20905 * @param {Object} config A configuration object.
20907 Roo.data.ScriptTagProxy = function(config){
20908 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20909 Roo.apply(this, config);
20910 this.head = document.getElementsByTagName("head")[0];
20913 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20915 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20917 * @cfg {String} url The URL from which to request the data object.
20920 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20924 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20925 * the server the name of the callback function set up by the load call to process the returned data object.
20926 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20927 * javascript output which calls this named function passing the data object as its only parameter.
20929 callbackParam : "callback",
20931 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20932 * name to the request.
20937 * Load data from the configured URL, read the data object into
20938 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20939 * process that block using the passed callback.
20940 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20941 * for the request to the remote server.
20942 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20943 * object into a block of Roo.data.Records.
20944 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20945 * The function must be passed <ul>
20946 * <li>The Record block object</li>
20947 * <li>The "arg" argument from the load function</li>
20948 * <li>A boolean success indicator</li>
20950 * @param {Object} scope The scope in which to call the callback
20951 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20953 load : function(params, reader, callback, scope, arg){
20954 if(this.fireEvent("beforeload", this, params) !== false){
20956 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20958 var url = this.url;
20959 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20961 url += "&_dc=" + (new Date().getTime());
20963 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20966 cb : "stcCallback"+transId,
20967 scriptId : "stcScript"+transId,
20971 callback : callback,
20977 window[trans.cb] = function(o){
20978 conn.handleResponse(o, trans);
20981 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20983 if(this.autoAbort !== false){
20987 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20989 var script = document.createElement("script");
20990 script.setAttribute("src", url);
20991 script.setAttribute("type", "text/javascript");
20992 script.setAttribute("id", trans.scriptId);
20993 this.head.appendChild(script);
20995 this.trans = trans;
20997 callback.call(scope||this, null, arg, false);
21002 isLoading : function(){
21003 return this.trans ? true : false;
21007 * Abort the current server request.
21009 abort : function(){
21010 if(this.isLoading()){
21011 this.destroyTrans(this.trans);
21016 destroyTrans : function(trans, isLoaded){
21017 this.head.removeChild(document.getElementById(trans.scriptId));
21018 clearTimeout(trans.timeoutId);
21020 window[trans.cb] = undefined;
21022 delete window[trans.cb];
21025 // if hasn't been loaded, wait for load to remove it to prevent script error
21026 window[trans.cb] = function(){
21027 window[trans.cb] = undefined;
21029 delete window[trans.cb];
21036 handleResponse : function(o, trans){
21037 this.trans = false;
21038 this.destroyTrans(trans, true);
21041 result = trans.reader.readRecords(o);
21043 this.fireEvent("loadexception", this, o, trans.arg, e);
21044 trans.callback.call(trans.scope||window, null, trans.arg, false);
21047 this.fireEvent("load", this, o, trans.arg);
21048 trans.callback.call(trans.scope||window, result, trans.arg, true);
21052 handleFailure : function(trans){
21053 this.trans = false;
21054 this.destroyTrans(trans, false);
21055 this.fireEvent("loadexception", this, null, trans.arg);
21056 trans.callback.call(trans.scope||window, null, trans.arg, false);
21060 * Ext JS Library 1.1.1
21061 * Copyright(c) 2006-2007, Ext JS, LLC.
21063 * Originally Released Under LGPL - original licence link has changed is not relivant.
21066 * <script type="text/javascript">
21070 * @class Roo.data.JsonReader
21071 * @extends Roo.data.DataReader
21072 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21073 * based on mappings in a provided Roo.data.Record constructor.
21075 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21076 * in the reply previously.
21081 var RecordDef = Roo.data.Record.create([
21082 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21083 {name: 'occupation'} // This field will use "occupation" as the mapping.
21085 var myReader = new Roo.data.JsonReader({
21086 totalProperty: "results", // The property which contains the total dataset size (optional)
21087 root: "rows", // The property which contains an Array of row objects
21088 id: "id" // The property within each row object that provides an ID for the record (optional)
21092 * This would consume a JSON file like this:
21094 { 'results': 2, 'rows': [
21095 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21096 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21099 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21100 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21101 * paged from the remote server.
21102 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21103 * @cfg {String} root name of the property which contains the Array of row objects.
21104 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21106 * Create a new JsonReader
21107 * @param {Object} meta Metadata configuration options
21108 * @param {Object} recordType Either an Array of field definition objects,
21109 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21111 Roo.data.JsonReader = function(meta, recordType){
21114 // set some defaults:
21115 Roo.applyIf(meta, {
21116 totalProperty: 'total',
21117 successProperty : 'success',
21122 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21124 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21127 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21128 * Used by Store query builder to append _requestMeta to params.
21131 metaFromRemote : false,
21133 * This method is only used by a DataProxy which has retrieved data from a remote server.
21134 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21135 * @return {Object} data A data block which is used by an Roo.data.Store object as
21136 * a cache of Roo.data.Records.
21138 read : function(response){
21139 var json = response.responseText;
21141 var o = /* eval:var:o */ eval("("+json+")");
21143 throw {message: "JsonReader.read: Json object not found"};
21149 this.metaFromRemote = true;
21150 this.meta = o.metaData;
21151 this.recordType = Roo.data.Record.create(o.metaData.fields);
21152 this.onMetaChange(this.meta, this.recordType, o);
21154 return this.readRecords(o);
21157 // private function a store will implement
21158 onMetaChange : function(meta, recordType, o){
21165 simpleAccess: function(obj, subsc) {
21172 getJsonAccessor: function(){
21174 return function(expr) {
21176 return(re.test(expr))
21177 ? new Function("obj", "return obj." + expr)
21182 return Roo.emptyFn;
21187 * Create a data block containing Roo.data.Records from an XML document.
21188 * @param {Object} o An object which contains an Array of row objects in the property specified
21189 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21190 * which contains the total size of the dataset.
21191 * @return {Object} data A data block which is used by an Roo.data.Store object as
21192 * a cache of Roo.data.Records.
21194 readRecords : function(o){
21196 * After any data loads, the raw JSON data is available for further custom processing.
21200 var s = this.meta, Record = this.recordType,
21201 f = Record.prototype.fields, fi = f.items, fl = f.length;
21203 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21205 if(s.totalProperty) {
21206 this.getTotal = this.getJsonAccessor(s.totalProperty);
21208 if(s.successProperty) {
21209 this.getSuccess = this.getJsonAccessor(s.successProperty);
21211 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21213 var g = this.getJsonAccessor(s.id);
21214 this.getId = function(rec) {
21216 return (r === undefined || r === "") ? null : r;
21219 this.getId = function(){return null;};
21222 for(var jj = 0; jj < fl; jj++){
21224 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21225 this.ef[jj] = this.getJsonAccessor(map);
21229 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21230 if(s.totalProperty){
21231 var vt = parseInt(this.getTotal(o), 10);
21236 if(s.successProperty){
21237 var vs = this.getSuccess(o);
21238 if(vs === false || vs === 'false'){
21243 for(var i = 0; i < c; i++){
21246 var id = this.getId(n);
21247 for(var j = 0; j < fl; j++){
21249 var v = this.ef[j](n);
21251 Roo.log('missing convert for ' + f.name);
21255 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21257 var record = new Record(values, id);
21259 records[i] = record;
21265 totalRecords : totalRecords
21270 * Ext JS Library 1.1.1
21271 * Copyright(c) 2006-2007, Ext JS, LLC.
21273 * Originally Released Under LGPL - original licence link has changed is not relivant.
21276 * <script type="text/javascript">
21280 * @class Roo.data.XmlReader
21281 * @extends Roo.data.DataReader
21282 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21283 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21285 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21286 * header in the HTTP response must be set to "text/xml".</em>
21290 var RecordDef = Roo.data.Record.create([
21291 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21292 {name: 'occupation'} // This field will use "occupation" as the mapping.
21294 var myReader = new Roo.data.XmlReader({
21295 totalRecords: "results", // The element which contains the total dataset size (optional)
21296 record: "row", // The repeated element which contains row information
21297 id: "id" // The element within the row that provides an ID for the record (optional)
21301 * This would consume an XML file like this:
21305 <results>2</results>
21308 <name>Bill</name>
21309 <occupation>Gardener</occupation>
21313 <name>Ben</name>
21314 <occupation>Horticulturalist</occupation>
21318 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21319 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21320 * paged from the remote server.
21321 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21322 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21323 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21324 * a record identifier value.
21326 * Create a new XmlReader
21327 * @param {Object} meta Metadata configuration options
21328 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21329 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21330 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21332 Roo.data.XmlReader = function(meta, recordType){
21334 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21336 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21338 * This method is only used by a DataProxy which has retrieved data from a remote server.
21339 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21340 * to contain a method called 'responseXML' that returns an XML document object.
21341 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21342 * a cache of Roo.data.Records.
21344 read : function(response){
21345 var doc = response.responseXML;
21347 throw {message: "XmlReader.read: XML Document not available"};
21349 return this.readRecords(doc);
21353 * Create a data block containing Roo.data.Records from an XML document.
21354 * @param {Object} doc A parsed XML document.
21355 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21356 * a cache of Roo.data.Records.
21358 readRecords : function(doc){
21360 * After any data loads/reads, the raw XML Document is available for further custom processing.
21361 * @type XMLDocument
21363 this.xmlData = doc;
21364 var root = doc.documentElement || doc;
21365 var q = Roo.DomQuery;
21366 var recordType = this.recordType, fields = recordType.prototype.fields;
21367 var sid = this.meta.id;
21368 var totalRecords = 0, success = true;
21369 if(this.meta.totalRecords){
21370 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21373 if(this.meta.success){
21374 var sv = q.selectValue(this.meta.success, root, true);
21375 success = sv !== false && sv !== 'false';
21378 var ns = q.select(this.meta.record, root);
21379 for(var i = 0, len = ns.length; i < len; i++) {
21382 var id = sid ? q.selectValue(sid, n) : undefined;
21383 for(var j = 0, jlen = fields.length; j < jlen; j++){
21384 var f = fields.items[j];
21385 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21387 values[f.name] = v;
21389 var record = new recordType(values, id);
21391 records[records.length] = record;
21397 totalRecords : totalRecords || records.length
21402 * Ext JS Library 1.1.1
21403 * Copyright(c) 2006-2007, Ext JS, LLC.
21405 * Originally Released Under LGPL - original licence link has changed is not relivant.
21408 * <script type="text/javascript">
21412 * @class Roo.data.ArrayReader
21413 * @extends Roo.data.DataReader
21414 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21415 * Each element of that Array represents a row of data fields. The
21416 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21417 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21421 var RecordDef = Roo.data.Record.create([
21422 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21423 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21425 var myReader = new Roo.data.ArrayReader({
21426 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21430 * This would consume an Array like this:
21432 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21434 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21436 * Create a new JsonReader
21437 * @param {Object} meta Metadata configuration options.
21438 * @param {Object} recordType Either an Array of field definition objects
21439 * as specified to {@link Roo.data.Record#create},
21440 * or an {@link Roo.data.Record} object
21441 * created using {@link Roo.data.Record#create}.
21443 Roo.data.ArrayReader = function(meta, recordType){
21444 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21447 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21449 * Create a data block containing Roo.data.Records from an XML document.
21450 * @param {Object} o An Array of row objects which represents the dataset.
21451 * @return {Object} data A data block which is used by an Roo.data.Store object as
21452 * a cache of Roo.data.Records.
21454 readRecords : function(o){
21455 var sid = this.meta ? this.meta.id : null;
21456 var recordType = this.recordType, fields = recordType.prototype.fields;
21459 for(var i = 0; i < root.length; i++){
21462 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21463 for(var j = 0, jlen = fields.length; j < jlen; j++){
21464 var f = fields.items[j];
21465 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21466 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21468 values[f.name] = v;
21470 var record = new recordType(values, id);
21472 records[records.length] = record;
21476 totalRecords : records.length
21481 * Ext JS Library 1.1.1
21482 * Copyright(c) 2006-2007, Ext JS, LLC.
21484 * Originally Released Under LGPL - original licence link has changed is not relivant.
21487 * <script type="text/javascript">
21492 * @class Roo.data.Tree
21493 * @extends Roo.util.Observable
21494 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21495 * in the tree have most standard DOM functionality.
21497 * @param {Node} root (optional) The root node
21499 Roo.data.Tree = function(root){
21500 this.nodeHash = {};
21502 * The root node for this tree
21507 this.setRootNode(root);
21512 * Fires when a new child node is appended to a node in this tree.
21513 * @param {Tree} tree The owner tree
21514 * @param {Node} parent The parent node
21515 * @param {Node} node The newly appended node
21516 * @param {Number} index The index of the newly appended node
21521 * Fires when a child node is removed from a node in this tree.
21522 * @param {Tree} tree The owner tree
21523 * @param {Node} parent The parent node
21524 * @param {Node} node The child node removed
21529 * Fires when a node is moved to a new location in the tree
21530 * @param {Tree} tree The owner tree
21531 * @param {Node} node The node moved
21532 * @param {Node} oldParent The old parent of this node
21533 * @param {Node} newParent The new parent of this node
21534 * @param {Number} index The index it was moved to
21539 * Fires when a new child node is inserted in a node in this tree.
21540 * @param {Tree} tree The owner tree
21541 * @param {Node} parent The parent node
21542 * @param {Node} node The child node inserted
21543 * @param {Node} refNode The child node the node was inserted before
21547 * @event beforeappend
21548 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21549 * @param {Tree} tree The owner tree
21550 * @param {Node} parent The parent node
21551 * @param {Node} node The child node to be appended
21553 "beforeappend" : true,
21555 * @event beforeremove
21556 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21557 * @param {Tree} tree The owner tree
21558 * @param {Node} parent The parent node
21559 * @param {Node} node The child node to be removed
21561 "beforeremove" : true,
21563 * @event beforemove
21564 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21565 * @param {Tree} tree The owner tree
21566 * @param {Node} node The node being moved
21567 * @param {Node} oldParent The parent of the node
21568 * @param {Node} newParent The new parent the node is moving to
21569 * @param {Number} index The index it is being moved to
21571 "beforemove" : true,
21573 * @event beforeinsert
21574 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21575 * @param {Tree} tree The owner tree
21576 * @param {Node} parent The parent node
21577 * @param {Node} node The child node to be inserted
21578 * @param {Node} refNode The child node the node is being inserted before
21580 "beforeinsert" : true
21583 Roo.data.Tree.superclass.constructor.call(this);
21586 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21587 pathSeparator: "/",
21589 proxyNodeEvent : function(){
21590 return this.fireEvent.apply(this, arguments);
21594 * Returns the root node for this tree.
21597 getRootNode : function(){
21602 * Sets the root node for this tree.
21603 * @param {Node} node
21606 setRootNode : function(node){
21608 node.ownerTree = this;
21609 node.isRoot = true;
21610 this.registerNode(node);
21615 * Gets a node in this tree by its id.
21616 * @param {String} id
21619 getNodeById : function(id){
21620 return this.nodeHash[id];
21623 registerNode : function(node){
21624 this.nodeHash[node.id] = node;
21627 unregisterNode : function(node){
21628 delete this.nodeHash[node.id];
21631 toString : function(){
21632 return "[Tree"+(this.id?" "+this.id:"")+"]";
21637 * @class Roo.data.Node
21638 * @extends Roo.util.Observable
21639 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21640 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21642 * @param {Object} attributes The attributes/config for the node
21644 Roo.data.Node = function(attributes){
21646 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21649 this.attributes = attributes || {};
21650 this.leaf = this.attributes.leaf;
21652 * The node id. @type String
21654 this.id = this.attributes.id;
21656 this.id = Roo.id(null, "ynode-");
21657 this.attributes.id = this.id;
21662 * All child nodes of this node. @type Array
21664 this.childNodes = [];
21665 if(!this.childNodes.indexOf){ // indexOf is a must
21666 this.childNodes.indexOf = function(o){
21667 for(var i = 0, len = this.length; i < len; i++){
21676 * The parent node for this node. @type Node
21678 this.parentNode = null;
21680 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21682 this.firstChild = null;
21684 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21686 this.lastChild = null;
21688 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21690 this.previousSibling = null;
21692 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21694 this.nextSibling = null;
21699 * Fires when a new child node is appended
21700 * @param {Tree} tree The owner tree
21701 * @param {Node} this This node
21702 * @param {Node} node The newly appended node
21703 * @param {Number} index The index of the newly appended node
21708 * Fires when a child node is removed
21709 * @param {Tree} tree The owner tree
21710 * @param {Node} this This node
21711 * @param {Node} node The removed node
21716 * Fires when this node is moved to a new location in the tree
21717 * @param {Tree} tree The owner tree
21718 * @param {Node} this This node
21719 * @param {Node} oldParent The old parent of this node
21720 * @param {Node} newParent The new parent of this node
21721 * @param {Number} index The index it was moved to
21726 * Fires when a new child node is inserted.
21727 * @param {Tree} tree The owner tree
21728 * @param {Node} this This node
21729 * @param {Node} node The child node inserted
21730 * @param {Node} refNode The child node the node was inserted before
21734 * @event beforeappend
21735 * Fires before a new child is appended, return false to cancel the append.
21736 * @param {Tree} tree The owner tree
21737 * @param {Node} this This node
21738 * @param {Node} node The child node to be appended
21740 "beforeappend" : true,
21742 * @event beforeremove
21743 * Fires before a child is removed, return false to cancel the remove.
21744 * @param {Tree} tree The owner tree
21745 * @param {Node} this This node
21746 * @param {Node} node The child node to be removed
21748 "beforeremove" : true,
21750 * @event beforemove
21751 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21752 * @param {Tree} tree The owner tree
21753 * @param {Node} this This node
21754 * @param {Node} oldParent The parent of this node
21755 * @param {Node} newParent The new parent this node is moving to
21756 * @param {Number} index The index it is being moved to
21758 "beforemove" : true,
21760 * @event beforeinsert
21761 * Fires before a new child is inserted, return false to cancel the insert.
21762 * @param {Tree} tree The owner tree
21763 * @param {Node} this This node
21764 * @param {Node} node The child node to be inserted
21765 * @param {Node} refNode The child node the node is being inserted before
21767 "beforeinsert" : true
21769 this.listeners = this.attributes.listeners;
21770 Roo.data.Node.superclass.constructor.call(this);
21773 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21774 fireEvent : function(evtName){
21775 // first do standard event for this node
21776 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21779 // then bubble it up to the tree if the event wasn't cancelled
21780 var ot = this.getOwnerTree();
21782 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21790 * Returns true if this node is a leaf
21791 * @return {Boolean}
21793 isLeaf : function(){
21794 return this.leaf === true;
21798 setFirstChild : function(node){
21799 this.firstChild = node;
21803 setLastChild : function(node){
21804 this.lastChild = node;
21809 * Returns true if this node is the last child of its parent
21810 * @return {Boolean}
21812 isLast : function(){
21813 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21817 * Returns true if this node is the first child of its parent
21818 * @return {Boolean}
21820 isFirst : function(){
21821 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21824 hasChildNodes : function(){
21825 return !this.isLeaf() && this.childNodes.length > 0;
21829 * Insert node(s) as the last child node of this node.
21830 * @param {Node/Array} node The node or Array of nodes to append
21831 * @return {Node} The appended node if single append, or null if an array was passed
21833 appendChild : function(node){
21835 if(node instanceof Array){
21837 }else if(arguments.length > 1){
21840 // if passed an array or multiple args do them one by one
21842 for(var i = 0, len = multi.length; i < len; i++) {
21843 this.appendChild(multi[i]);
21846 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21849 var index = this.childNodes.length;
21850 var oldParent = node.parentNode;
21851 // it's a move, make sure we move it cleanly
21853 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21856 oldParent.removeChild(node);
21858 index = this.childNodes.length;
21860 this.setFirstChild(node);
21862 this.childNodes.push(node);
21863 node.parentNode = this;
21864 var ps = this.childNodes[index-1];
21866 node.previousSibling = ps;
21867 ps.nextSibling = node;
21869 node.previousSibling = null;
21871 node.nextSibling = null;
21872 this.setLastChild(node);
21873 node.setOwnerTree(this.getOwnerTree());
21874 this.fireEvent("append", this.ownerTree, this, node, index);
21876 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21883 * Removes a child node from this node.
21884 * @param {Node} node The node to remove
21885 * @return {Node} The removed node
21887 removeChild : function(node){
21888 var index = this.childNodes.indexOf(node);
21892 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21896 // remove it from childNodes collection
21897 this.childNodes.splice(index, 1);
21900 if(node.previousSibling){
21901 node.previousSibling.nextSibling = node.nextSibling;
21903 if(node.nextSibling){
21904 node.nextSibling.previousSibling = node.previousSibling;
21907 // update child refs
21908 if(this.firstChild == node){
21909 this.setFirstChild(node.nextSibling);
21911 if(this.lastChild == node){
21912 this.setLastChild(node.previousSibling);
21915 node.setOwnerTree(null);
21916 // clear any references from the node
21917 node.parentNode = null;
21918 node.previousSibling = null;
21919 node.nextSibling = null;
21920 this.fireEvent("remove", this.ownerTree, this, node);
21925 * Inserts the first node before the second node in this nodes childNodes collection.
21926 * @param {Node} node The node to insert
21927 * @param {Node} refNode The node to insert before (if null the node is appended)
21928 * @return {Node} The inserted node
21930 insertBefore : function(node, refNode){
21931 if(!refNode){ // like standard Dom, refNode can be null for append
21932 return this.appendChild(node);
21935 if(node == refNode){
21939 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21942 var index = this.childNodes.indexOf(refNode);
21943 var oldParent = node.parentNode;
21944 var refIndex = index;
21946 // when moving internally, indexes will change after remove
21947 if(oldParent == this && this.childNodes.indexOf(node) < index){
21951 // it's a move, make sure we move it cleanly
21953 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21956 oldParent.removeChild(node);
21959 this.setFirstChild(node);
21961 this.childNodes.splice(refIndex, 0, node);
21962 node.parentNode = this;
21963 var ps = this.childNodes[refIndex-1];
21965 node.previousSibling = ps;
21966 ps.nextSibling = node;
21968 node.previousSibling = null;
21970 node.nextSibling = refNode;
21971 refNode.previousSibling = node;
21972 node.setOwnerTree(this.getOwnerTree());
21973 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21975 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21981 * Returns the child node at the specified index.
21982 * @param {Number} index
21985 item : function(index){
21986 return this.childNodes[index];
21990 * Replaces one child node in this node with another.
21991 * @param {Node} newChild The replacement node
21992 * @param {Node} oldChild The node to replace
21993 * @return {Node} The replaced node
21995 replaceChild : function(newChild, oldChild){
21996 this.insertBefore(newChild, oldChild);
21997 this.removeChild(oldChild);
22002 * Returns the index of a child node
22003 * @param {Node} node
22004 * @return {Number} The index of the node or -1 if it was not found
22006 indexOf : function(child){
22007 return this.childNodes.indexOf(child);
22011 * Returns the tree this node is in.
22014 getOwnerTree : function(){
22015 // if it doesn't have one, look for one
22016 if(!this.ownerTree){
22020 this.ownerTree = p.ownerTree;
22026 return this.ownerTree;
22030 * Returns depth of this node (the root node has a depth of 0)
22033 getDepth : function(){
22036 while(p.parentNode){
22044 setOwnerTree : function(tree){
22045 // if it's move, we need to update everyone
22046 if(tree != this.ownerTree){
22047 if(this.ownerTree){
22048 this.ownerTree.unregisterNode(this);
22050 this.ownerTree = tree;
22051 var cs = this.childNodes;
22052 for(var i = 0, len = cs.length; i < len; i++) {
22053 cs[i].setOwnerTree(tree);
22056 tree.registerNode(this);
22062 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22063 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22064 * @return {String} The path
22066 getPath : function(attr){
22067 attr = attr || "id";
22068 var p = this.parentNode;
22069 var b = [this.attributes[attr]];
22071 b.unshift(p.attributes[attr]);
22074 var sep = this.getOwnerTree().pathSeparator;
22075 return sep + b.join(sep);
22079 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22080 * function call will be the scope provided or the current node. The arguments to the function
22081 * will be the args provided or the current node. If the function returns false at any point,
22082 * the bubble is stopped.
22083 * @param {Function} fn The function to call
22084 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22085 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22087 bubble : function(fn, scope, args){
22090 if(fn.call(scope || p, args || p) === false){
22098 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22099 * function call will be the scope provided or the current node. The arguments to the function
22100 * will be the args provided or the current node. If the function returns false at any point,
22101 * the cascade is stopped on that branch.
22102 * @param {Function} fn The function to call
22103 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22104 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22106 cascade : function(fn, scope, args){
22107 if(fn.call(scope || this, args || this) !== false){
22108 var cs = this.childNodes;
22109 for(var i = 0, len = cs.length; i < len; i++) {
22110 cs[i].cascade(fn, scope, args);
22116 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22117 * function call will be the scope provided or the current node. The arguments to the function
22118 * will be the args provided or the current node. If the function returns false at any point,
22119 * the iteration stops.
22120 * @param {Function} fn The function to call
22121 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22122 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22124 eachChild : function(fn, scope, args){
22125 var cs = this.childNodes;
22126 for(var i = 0, len = cs.length; i < len; i++) {
22127 if(fn.call(scope || this, args || cs[i]) === false){
22134 * Finds the first child that has the attribute with the specified value.
22135 * @param {String} attribute The attribute name
22136 * @param {Mixed} value The value to search for
22137 * @return {Node} The found child or null if none was found
22139 findChild : function(attribute, value){
22140 var cs = this.childNodes;
22141 for(var i = 0, len = cs.length; i < len; i++) {
22142 if(cs[i].attributes[attribute] == value){
22150 * Finds the first child by a custom function. The child matches if the function passed
22152 * @param {Function} fn
22153 * @param {Object} scope (optional)
22154 * @return {Node} The found child or null if none was found
22156 findChildBy : function(fn, scope){
22157 var cs = this.childNodes;
22158 for(var i = 0, len = cs.length; i < len; i++) {
22159 if(fn.call(scope||cs[i], cs[i]) === true){
22167 * Sorts this nodes children using the supplied sort function
22168 * @param {Function} fn
22169 * @param {Object} scope (optional)
22171 sort : function(fn, scope){
22172 var cs = this.childNodes;
22173 var len = cs.length;
22175 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22177 for(var i = 0; i < len; i++){
22179 n.previousSibling = cs[i-1];
22180 n.nextSibling = cs[i+1];
22182 this.setFirstChild(n);
22185 this.setLastChild(n);
22192 * Returns true if this node is an ancestor (at any point) of the passed node.
22193 * @param {Node} node
22194 * @return {Boolean}
22196 contains : function(node){
22197 return node.isAncestor(this);
22201 * Returns true if the passed node is an ancestor (at any point) of this node.
22202 * @param {Node} node
22203 * @return {Boolean}
22205 isAncestor : function(node){
22206 var p = this.parentNode;
22216 toString : function(){
22217 return "[Node"+(this.id?" "+this.id:"")+"]";
22221 * Ext JS Library 1.1.1
22222 * Copyright(c) 2006-2007, Ext JS, LLC.
22224 * Originally Released Under LGPL - original licence link has changed is not relivant.
22227 * <script type="text/javascript">
22232 * @class Roo.ComponentMgr
22233 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22236 Roo.ComponentMgr = function(){
22237 var all = new Roo.util.MixedCollection();
22241 * Registers a component.
22242 * @param {Roo.Component} c The component
22244 register : function(c){
22249 * Unregisters a component.
22250 * @param {Roo.Component} c The component
22252 unregister : function(c){
22257 * Returns a component by id
22258 * @param {String} id The component id
22260 get : function(id){
22261 return all.get(id);
22265 * Registers a function that will be called when a specified component is added to ComponentMgr
22266 * @param {String} id The component id
22267 * @param {Funtction} fn The callback function
22268 * @param {Object} scope The scope of the callback
22270 onAvailable : function(id, fn, scope){
22271 all.on("add", function(index, o){
22273 fn.call(scope || o, o);
22274 all.un("add", fn, scope);
22281 * Ext JS Library 1.1.1
22282 * Copyright(c) 2006-2007, Ext JS, LLC.
22284 * Originally Released Under LGPL - original licence link has changed is not relivant.
22287 * <script type="text/javascript">
22291 * @class Roo.Component
22292 * @extends Roo.util.Observable
22293 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22294 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22295 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22296 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22297 * All visual components (widgets) that require rendering into a layout should subclass Component.
22299 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22300 * 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
22301 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22303 Roo.Component = function(config){
22304 config = config || {};
22305 if(config.tagName || config.dom || typeof config == "string"){ // element object
22306 config = {el: config, id: config.id || config};
22308 this.initialConfig = config;
22310 Roo.apply(this, config);
22314 * Fires after the component is disabled.
22315 * @param {Roo.Component} this
22320 * Fires after the component is enabled.
22321 * @param {Roo.Component} this
22325 * @event beforeshow
22326 * Fires before the component is shown. Return false to stop the show.
22327 * @param {Roo.Component} this
22332 * Fires after the component is shown.
22333 * @param {Roo.Component} this
22337 * @event beforehide
22338 * Fires before the component is hidden. Return false to stop the hide.
22339 * @param {Roo.Component} this
22344 * Fires after the component is hidden.
22345 * @param {Roo.Component} this
22349 * @event beforerender
22350 * Fires before the component is rendered. Return false to stop the render.
22351 * @param {Roo.Component} this
22353 beforerender : true,
22356 * Fires after the component is rendered.
22357 * @param {Roo.Component} this
22361 * @event beforedestroy
22362 * Fires before the component is destroyed. Return false to stop the destroy.
22363 * @param {Roo.Component} this
22365 beforedestroy : true,
22368 * Fires after the component is destroyed.
22369 * @param {Roo.Component} this
22374 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22376 Roo.ComponentMgr.register(this);
22377 Roo.Component.superclass.constructor.call(this);
22378 this.initComponent();
22379 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22380 this.render(this.renderTo);
22381 delete this.renderTo;
22386 Roo.Component.AUTO_ID = 1000;
22388 Roo.extend(Roo.Component, Roo.util.Observable, {
22390 * @scope Roo.Component.prototype
22392 * true if this component is hidden. Read-only.
22397 * true if this component is disabled. Read-only.
22402 * true if this component has been rendered. Read-only.
22406 /** @cfg {String} disableClass
22407 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22409 disabledClass : "x-item-disabled",
22410 /** @cfg {Boolean} allowDomMove
22411 * Whether the component can move the Dom node when rendering (defaults to true).
22413 allowDomMove : true,
22414 /** @cfg {String} hideMode
22415 * How this component should hidden. Supported values are
22416 * "visibility" (css visibility), "offsets" (negative offset position) and
22417 * "display" (css display) - defaults to "display".
22419 hideMode: 'display',
22422 ctype : "Roo.Component",
22425 * @cfg {String} actionMode
22426 * which property holds the element that used for hide() / show() / disable() / enable()
22432 getActionEl : function(){
22433 return this[this.actionMode];
22436 initComponent : Roo.emptyFn,
22438 * If this is a lazy rendering component, render it to its container element.
22439 * @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.
22441 render : function(container, position){
22442 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22443 if(!container && this.el){
22444 this.el = Roo.get(this.el);
22445 container = this.el.dom.parentNode;
22446 this.allowDomMove = false;
22448 this.container = Roo.get(container);
22449 this.rendered = true;
22450 if(position !== undefined){
22451 if(typeof position == 'number'){
22452 position = this.container.dom.childNodes[position];
22454 position = Roo.getDom(position);
22457 this.onRender(this.container, position || null);
22459 this.el.addClass(this.cls);
22463 this.el.applyStyles(this.style);
22466 this.fireEvent("render", this);
22467 this.afterRender(this.container);
22479 // default function is not really useful
22480 onRender : function(ct, position){
22482 this.el = Roo.get(this.el);
22483 if(this.allowDomMove !== false){
22484 ct.dom.insertBefore(this.el.dom, position);
22490 getAutoCreate : function(){
22491 var cfg = typeof this.autoCreate == "object" ?
22492 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22493 if(this.id && !cfg.id){
22500 afterRender : Roo.emptyFn,
22503 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22504 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22506 destroy : function(){
22507 if(this.fireEvent("beforedestroy", this) !== false){
22508 this.purgeListeners();
22509 this.beforeDestroy();
22511 this.el.removeAllListeners();
22513 if(this.actionMode == "container"){
22514 this.container.remove();
22518 Roo.ComponentMgr.unregister(this);
22519 this.fireEvent("destroy", this);
22524 beforeDestroy : function(){
22529 onDestroy : function(){
22534 * Returns the underlying {@link Roo.Element}.
22535 * @return {Roo.Element} The element
22537 getEl : function(){
22542 * Returns the id of this component.
22545 getId : function(){
22550 * Try to focus this component.
22551 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22552 * @return {Roo.Component} this
22554 focus : function(selectText){
22557 if(selectText === true){
22558 this.el.dom.select();
22573 * Disable this component.
22574 * @return {Roo.Component} this
22576 disable : function(){
22580 this.disabled = true;
22581 this.fireEvent("disable", this);
22586 onDisable : function(){
22587 this.getActionEl().addClass(this.disabledClass);
22588 this.el.dom.disabled = true;
22592 * Enable this component.
22593 * @return {Roo.Component} this
22595 enable : function(){
22599 this.disabled = false;
22600 this.fireEvent("enable", this);
22605 onEnable : function(){
22606 this.getActionEl().removeClass(this.disabledClass);
22607 this.el.dom.disabled = false;
22611 * Convenience function for setting disabled/enabled by boolean.
22612 * @param {Boolean} disabled
22614 setDisabled : function(disabled){
22615 this[disabled ? "disable" : "enable"]();
22619 * Show this component.
22620 * @return {Roo.Component} this
22623 if(this.fireEvent("beforeshow", this) !== false){
22624 this.hidden = false;
22628 this.fireEvent("show", this);
22634 onShow : function(){
22635 var ae = this.getActionEl();
22636 if(this.hideMode == 'visibility'){
22637 ae.dom.style.visibility = "visible";
22638 }else if(this.hideMode == 'offsets'){
22639 ae.removeClass('x-hidden');
22641 ae.dom.style.display = "";
22646 * Hide this component.
22647 * @return {Roo.Component} this
22650 if(this.fireEvent("beforehide", this) !== false){
22651 this.hidden = true;
22655 this.fireEvent("hide", this);
22661 onHide : function(){
22662 var ae = this.getActionEl();
22663 if(this.hideMode == 'visibility'){
22664 ae.dom.style.visibility = "hidden";
22665 }else if(this.hideMode == 'offsets'){
22666 ae.addClass('x-hidden');
22668 ae.dom.style.display = "none";
22673 * Convenience function to hide or show this component by boolean.
22674 * @param {Boolean} visible True to show, false to hide
22675 * @return {Roo.Component} this
22677 setVisible: function(visible){
22687 * Returns true if this component is visible.
22689 isVisible : function(){
22690 return this.getActionEl().isVisible();
22693 cloneConfig : function(overrides){
22694 overrides = overrides || {};
22695 var id = overrides.id || Roo.id();
22696 var cfg = Roo.applyIf(overrides, this.initialConfig);
22697 cfg.id = id; // prevent dup id
22698 return new this.constructor(cfg);
22702 * Ext JS Library 1.1.1
22703 * Copyright(c) 2006-2007, Ext JS, LLC.
22705 * Originally Released Under LGPL - original licence link has changed is not relivant.
22708 * <script type="text/javascript">
22713 * @extends Roo.Element
22714 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22715 * automatic maintaining of shadow/shim positions.
22716 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22717 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22718 * you can pass a string with a CSS class name. False turns off the shadow.
22719 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22720 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22721 * @cfg {String} cls CSS class to add to the element
22722 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22723 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22725 * @param {Object} config An object with config options.
22726 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22729 Roo.Layer = function(config, existingEl){
22730 config = config || {};
22731 var dh = Roo.DomHelper;
22732 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22734 this.dom = Roo.getDom(existingEl);
22737 var o = config.dh || {tag: "div", cls: "x-layer"};
22738 this.dom = dh.append(pel, o);
22741 this.addClass(config.cls);
22743 this.constrain = config.constrain !== false;
22744 this.visibilityMode = Roo.Element.VISIBILITY;
22746 this.id = this.dom.id = config.id;
22748 this.id = Roo.id(this.dom);
22750 this.zindex = config.zindex || this.getZIndex();
22751 this.position("absolute", this.zindex);
22753 this.shadowOffset = config.shadowOffset || 4;
22754 this.shadow = new Roo.Shadow({
22755 offset : this.shadowOffset,
22756 mode : config.shadow
22759 this.shadowOffset = 0;
22761 this.useShim = config.shim !== false && Roo.useShims;
22762 this.useDisplay = config.useDisplay;
22766 var supr = Roo.Element.prototype;
22768 // shims are shared among layer to keep from having 100 iframes
22771 Roo.extend(Roo.Layer, Roo.Element, {
22773 getZIndex : function(){
22774 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22777 getShim : function(){
22784 var shim = shims.shift();
22786 shim = this.createShim();
22787 shim.enableDisplayMode('block');
22788 shim.dom.style.display = 'none';
22789 shim.dom.style.visibility = 'visible';
22791 var pn = this.dom.parentNode;
22792 if(shim.dom.parentNode != pn){
22793 pn.insertBefore(shim.dom, this.dom);
22795 shim.setStyle('z-index', this.getZIndex()-2);
22800 hideShim : function(){
22802 this.shim.setDisplayed(false);
22803 shims.push(this.shim);
22808 disableShadow : function(){
22810 this.shadowDisabled = true;
22811 this.shadow.hide();
22812 this.lastShadowOffset = this.shadowOffset;
22813 this.shadowOffset = 0;
22817 enableShadow : function(show){
22819 this.shadowDisabled = false;
22820 this.shadowOffset = this.lastShadowOffset;
22821 delete this.lastShadowOffset;
22829 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22830 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22831 sync : function(doShow){
22832 var sw = this.shadow;
22833 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22834 var sh = this.getShim();
22836 var w = this.getWidth(),
22837 h = this.getHeight();
22839 var l = this.getLeft(true),
22840 t = this.getTop(true);
22842 if(sw && !this.shadowDisabled){
22843 if(doShow && !sw.isVisible()){
22846 sw.realign(l, t, w, h);
22852 // fit the shim behind the shadow, so it is shimmed too
22853 var a = sw.adjusts, s = sh.dom.style;
22854 s.left = (Math.min(l, l+a.l))+"px";
22855 s.top = (Math.min(t, t+a.t))+"px";
22856 s.width = (w+a.w)+"px";
22857 s.height = (h+a.h)+"px";
22864 sh.setLeftTop(l, t);
22871 destroy : function(){
22874 this.shadow.hide();
22876 this.removeAllListeners();
22877 var pn = this.dom.parentNode;
22879 pn.removeChild(this.dom);
22881 Roo.Element.uncache(this.id);
22884 remove : function(){
22889 beginUpdate : function(){
22890 this.updating = true;
22894 endUpdate : function(){
22895 this.updating = false;
22900 hideUnders : function(negOffset){
22902 this.shadow.hide();
22908 constrainXY : function(){
22909 if(this.constrain){
22910 var vw = Roo.lib.Dom.getViewWidth(),
22911 vh = Roo.lib.Dom.getViewHeight();
22912 var s = Roo.get(document).getScroll();
22914 var xy = this.getXY();
22915 var x = xy[0], y = xy[1];
22916 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22917 // only move it if it needs it
22919 // first validate right/bottom
22920 if((x + w) > vw+s.left){
22921 x = vw - w - this.shadowOffset;
22924 if((y + h) > vh+s.top){
22925 y = vh - h - this.shadowOffset;
22928 // then make sure top/left isn't negative
22939 var ay = this.avoidY;
22940 if(y <= ay && (y+h) >= ay){
22946 supr.setXY.call(this, xy);
22952 isVisible : function(){
22953 return this.visible;
22957 showAction : function(){
22958 this.visible = true; // track visibility to prevent getStyle calls
22959 if(this.useDisplay === true){
22960 this.setDisplayed("");
22961 }else if(this.lastXY){
22962 supr.setXY.call(this, this.lastXY);
22963 }else if(this.lastLT){
22964 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22969 hideAction : function(){
22970 this.visible = false;
22971 if(this.useDisplay === true){
22972 this.setDisplayed(false);
22974 this.setLeftTop(-10000,-10000);
22978 // overridden Element method
22979 setVisible : function(v, a, d, c, e){
22984 var cb = function(){
22989 }.createDelegate(this);
22990 supr.setVisible.call(this, true, true, d, cb, e);
22993 this.hideUnders(true);
23002 }.createDelegate(this);
23004 supr.setVisible.call(this, v, a, d, cb, e);
23013 storeXY : function(xy){
23014 delete this.lastLT;
23018 storeLeftTop : function(left, top){
23019 delete this.lastXY;
23020 this.lastLT = [left, top];
23024 beforeFx : function(){
23025 this.beforeAction();
23026 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23030 afterFx : function(){
23031 Roo.Layer.superclass.afterFx.apply(this, arguments);
23032 this.sync(this.isVisible());
23036 beforeAction : function(){
23037 if(!this.updating && this.shadow){
23038 this.shadow.hide();
23042 // overridden Element method
23043 setLeft : function(left){
23044 this.storeLeftTop(left, this.getTop(true));
23045 supr.setLeft.apply(this, arguments);
23049 setTop : function(top){
23050 this.storeLeftTop(this.getLeft(true), top);
23051 supr.setTop.apply(this, arguments);
23055 setLeftTop : function(left, top){
23056 this.storeLeftTop(left, top);
23057 supr.setLeftTop.apply(this, arguments);
23061 setXY : function(xy, a, d, c, e){
23063 this.beforeAction();
23065 var cb = this.createCB(c);
23066 supr.setXY.call(this, xy, a, d, cb, e);
23073 createCB : function(c){
23084 // overridden Element method
23085 setX : function(x, a, d, c, e){
23086 this.setXY([x, this.getY()], a, d, c, e);
23089 // overridden Element method
23090 setY : function(y, a, d, c, e){
23091 this.setXY([this.getX(), y], a, d, c, e);
23094 // overridden Element method
23095 setSize : function(w, h, a, d, c, e){
23096 this.beforeAction();
23097 var cb = this.createCB(c);
23098 supr.setSize.call(this, w, h, a, d, cb, e);
23104 // overridden Element method
23105 setWidth : function(w, a, d, c, e){
23106 this.beforeAction();
23107 var cb = this.createCB(c);
23108 supr.setWidth.call(this, w, a, d, cb, e);
23114 // overridden Element method
23115 setHeight : function(h, a, d, c, e){
23116 this.beforeAction();
23117 var cb = this.createCB(c);
23118 supr.setHeight.call(this, h, a, d, cb, e);
23124 // overridden Element method
23125 setBounds : function(x, y, w, h, a, d, c, e){
23126 this.beforeAction();
23127 var cb = this.createCB(c);
23129 this.storeXY([x, y]);
23130 supr.setXY.call(this, [x, y]);
23131 supr.setSize.call(this, w, h, a, d, cb, e);
23134 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23140 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23141 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23142 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23143 * @param {Number} zindex The new z-index to set
23144 * @return {this} The Layer
23146 setZIndex : function(zindex){
23147 this.zindex = zindex;
23148 this.setStyle("z-index", zindex + 2);
23150 this.shadow.setZIndex(zindex + 1);
23153 this.shim.setStyle("z-index", zindex);
23159 * Ext JS Library 1.1.1
23160 * Copyright(c) 2006-2007, Ext JS, LLC.
23162 * Originally Released Under LGPL - original licence link has changed is not relivant.
23165 * <script type="text/javascript">
23170 * @class Roo.Shadow
23171 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23172 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23173 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23175 * Create a new Shadow
23176 * @param {Object} config The config object
23178 Roo.Shadow = function(config){
23179 Roo.apply(this, config);
23180 if(typeof this.mode != "string"){
23181 this.mode = this.defaultMode;
23183 var o = this.offset, a = {h: 0};
23184 var rad = Math.floor(this.offset/2);
23185 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23191 a.l -= this.offset + rad;
23192 a.t -= this.offset + rad;
23203 a.l -= (this.offset - rad);
23204 a.t -= this.offset + rad;
23206 a.w -= (this.offset - rad)*2;
23217 a.l -= (this.offset - rad);
23218 a.t -= (this.offset - rad);
23220 a.w -= (this.offset + rad + 1);
23221 a.h -= (this.offset + rad);
23230 Roo.Shadow.prototype = {
23232 * @cfg {String} mode
23233 * The shadow display mode. Supports the following options:<br />
23234 * sides: Shadow displays on both sides and bottom only<br />
23235 * frame: Shadow displays equally on all four sides<br />
23236 * drop: Traditional bottom-right drop shadow (default)
23239 * @cfg {String} offset
23240 * The number of pixels to offset the shadow from the element (defaults to 4)
23245 defaultMode: "drop",
23248 * Displays the shadow under the target element
23249 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23251 show : function(target){
23252 target = Roo.get(target);
23254 this.el = Roo.Shadow.Pool.pull();
23255 if(this.el.dom.nextSibling != target.dom){
23256 this.el.insertBefore(target);
23259 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23261 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23264 target.getLeft(true),
23265 target.getTop(true),
23269 this.el.dom.style.display = "block";
23273 * Returns true if the shadow is visible, else false
23275 isVisible : function(){
23276 return this.el ? true : false;
23280 * Direct alignment when values are already available. Show must be called at least once before
23281 * calling this method to ensure it is initialized.
23282 * @param {Number} left The target element left position
23283 * @param {Number} top The target element top position
23284 * @param {Number} width The target element width
23285 * @param {Number} height The target element height
23287 realign : function(l, t, w, h){
23291 var a = this.adjusts, d = this.el.dom, s = d.style;
23293 s.left = (l+a.l)+"px";
23294 s.top = (t+a.t)+"px";
23295 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23297 if(s.width != sws || s.height != shs){
23301 var cn = d.childNodes;
23302 var sww = Math.max(0, (sw-12))+"px";
23303 cn[0].childNodes[1].style.width = sww;
23304 cn[1].childNodes[1].style.width = sww;
23305 cn[2].childNodes[1].style.width = sww;
23306 cn[1].style.height = Math.max(0, (sh-12))+"px";
23312 * Hides this shadow
23316 this.el.dom.style.display = "none";
23317 Roo.Shadow.Pool.push(this.el);
23323 * Adjust the z-index of this shadow
23324 * @param {Number} zindex The new z-index
23326 setZIndex : function(z){
23329 this.el.setStyle("z-index", z);
23334 // Private utility class that manages the internal Shadow cache
23335 Roo.Shadow.Pool = function(){
23337 var markup = Roo.isIE ?
23338 '<div class="x-ie-shadow"></div>' :
23339 '<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>';
23342 var sh = p.shift();
23344 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23345 sh.autoBoxAdjust = false;
23350 push : function(sh){
23356 * Ext JS Library 1.1.1
23357 * Copyright(c) 2006-2007, Ext JS, LLC.
23359 * Originally Released Under LGPL - original licence link has changed is not relivant.
23362 * <script type="text/javascript">
23366 * @class Roo.BoxComponent
23367 * @extends Roo.Component
23368 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23369 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23370 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23371 * layout containers.
23373 * @param {Roo.Element/String/Object} config The configuration options.
23375 Roo.BoxComponent = function(config){
23376 Roo.Component.call(this, config);
23380 * Fires after the component is resized.
23381 * @param {Roo.Component} this
23382 * @param {Number} adjWidth The box-adjusted width that was set
23383 * @param {Number} adjHeight The box-adjusted height that was set
23384 * @param {Number} rawWidth The width that was originally specified
23385 * @param {Number} rawHeight The height that was originally specified
23390 * Fires after the component is moved.
23391 * @param {Roo.Component} this
23392 * @param {Number} x The new x position
23393 * @param {Number} y The new y position
23399 Roo.extend(Roo.BoxComponent, Roo.Component, {
23400 // private, set in afterRender to signify that the component has been rendered
23402 // private, used to defer height settings to subclasses
23403 deferHeight: false,
23404 /** @cfg {Number} width
23405 * width (optional) size of component
23407 /** @cfg {Number} height
23408 * height (optional) size of component
23412 * Sets the width and height of the component. This method fires the resize event. This method can accept
23413 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23414 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23415 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23416 * @return {Roo.BoxComponent} this
23418 setSize : function(w, h){
23419 // support for standard size objects
23420 if(typeof w == 'object'){
23425 if(!this.boxReady){
23431 // prevent recalcs when not needed
23432 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23435 this.lastSize = {width: w, height: h};
23437 var adj = this.adjustSize(w, h);
23438 var aw = adj.width, ah = adj.height;
23439 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23440 var rz = this.getResizeEl();
23441 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23442 rz.setSize(aw, ah);
23443 }else if(!this.deferHeight && ah !== undefined){
23445 }else if(aw !== undefined){
23448 this.onResize(aw, ah, w, h);
23449 this.fireEvent('resize', this, aw, ah, w, h);
23455 * Gets the current size of the component's underlying element.
23456 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23458 getSize : function(){
23459 return this.el.getSize();
23463 * Gets the current XY position of the component's underlying element.
23464 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23465 * @return {Array} The XY position of the element (e.g., [100, 200])
23467 getPosition : function(local){
23468 if(local === true){
23469 return [this.el.getLeft(true), this.el.getTop(true)];
23471 return this.xy || this.el.getXY();
23475 * Gets the current box measurements of the component's underlying element.
23476 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23477 * @returns {Object} box An object in the format {x, y, width, height}
23479 getBox : function(local){
23480 var s = this.el.getSize();
23482 s.x = this.el.getLeft(true);
23483 s.y = this.el.getTop(true);
23485 var xy = this.xy || this.el.getXY();
23493 * Sets the current box measurements of the component's underlying element.
23494 * @param {Object} box An object in the format {x, y, width, height}
23495 * @returns {Roo.BoxComponent} this
23497 updateBox : function(box){
23498 this.setSize(box.width, box.height);
23499 this.setPagePosition(box.x, box.y);
23504 getResizeEl : function(){
23505 return this.resizeEl || this.el;
23509 getPositionEl : function(){
23510 return this.positionEl || this.el;
23514 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23515 * This method fires the move event.
23516 * @param {Number} left The new left
23517 * @param {Number} top The new top
23518 * @returns {Roo.BoxComponent} this
23520 setPosition : function(x, y){
23523 if(!this.boxReady){
23526 var adj = this.adjustPosition(x, y);
23527 var ax = adj.x, ay = adj.y;
23529 var el = this.getPositionEl();
23530 if(ax !== undefined || ay !== undefined){
23531 if(ax !== undefined && ay !== undefined){
23532 el.setLeftTop(ax, ay);
23533 }else if(ax !== undefined){
23535 }else if(ay !== undefined){
23538 this.onPosition(ax, ay);
23539 this.fireEvent('move', this, ax, ay);
23545 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23546 * This method fires the move event.
23547 * @param {Number} x The new x position
23548 * @param {Number} y The new y position
23549 * @returns {Roo.BoxComponent} this
23551 setPagePosition : function(x, y){
23554 if(!this.boxReady){
23557 if(x === undefined || y === undefined){ // cannot translate undefined points
23560 var p = this.el.translatePoints(x, y);
23561 this.setPosition(p.left, p.top);
23566 onRender : function(ct, position){
23567 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23569 this.resizeEl = Roo.get(this.resizeEl);
23571 if(this.positionEl){
23572 this.positionEl = Roo.get(this.positionEl);
23577 afterRender : function(){
23578 Roo.BoxComponent.superclass.afterRender.call(this);
23579 this.boxReady = true;
23580 this.setSize(this.width, this.height);
23581 if(this.x || this.y){
23582 this.setPosition(this.x, this.y);
23584 if(this.pageX || this.pageY){
23585 this.setPagePosition(this.pageX, this.pageY);
23590 * Force the component's size to recalculate based on the underlying element's current height and width.
23591 * @returns {Roo.BoxComponent} this
23593 syncSize : function(){
23594 delete this.lastSize;
23595 this.setSize(this.el.getWidth(), this.el.getHeight());
23600 * Called after the component is resized, this method is empty by default but can be implemented by any
23601 * subclass that needs to perform custom logic after a resize occurs.
23602 * @param {Number} adjWidth The box-adjusted width that was set
23603 * @param {Number} adjHeight The box-adjusted height that was set
23604 * @param {Number} rawWidth The width that was originally specified
23605 * @param {Number} rawHeight The height that was originally specified
23607 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23612 * Called after the component is moved, this method is empty by default but can be implemented by any
23613 * subclass that needs to perform custom logic after a move occurs.
23614 * @param {Number} x The new x position
23615 * @param {Number} y The new y position
23617 onPosition : function(x, y){
23622 adjustSize : function(w, h){
23623 if(this.autoWidth){
23626 if(this.autoHeight){
23629 return {width : w, height: h};
23633 adjustPosition : function(x, y){
23634 return {x : x, y: y};
23638 * Ext JS Library 1.1.1
23639 * Copyright(c) 2006-2007, Ext JS, LLC.
23641 * Originally Released Under LGPL - original licence link has changed is not relivant.
23644 * <script type="text/javascript">
23649 * @class Roo.SplitBar
23650 * @extends Roo.util.Observable
23651 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23655 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23656 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23657 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23658 split.minSize = 100;
23659 split.maxSize = 600;
23660 split.animate = true;
23661 split.on('moved', splitterMoved);
23664 * Create a new SplitBar
23665 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23666 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23667 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23668 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23669 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23670 position of the SplitBar).
23672 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23675 this.el = Roo.get(dragElement, true);
23676 this.el.dom.unselectable = "on";
23678 this.resizingEl = Roo.get(resizingElement, true);
23682 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23683 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23686 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23689 * The minimum size of the resizing element. (Defaults to 0)
23695 * The maximum size of the resizing element. (Defaults to 2000)
23698 this.maxSize = 2000;
23701 * Whether to animate the transition to the new size
23704 this.animate = false;
23707 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23710 this.useShim = false;
23715 if(!existingProxy){
23717 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23719 this.proxy = Roo.get(existingProxy).dom;
23722 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23725 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23728 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23731 this.dragSpecs = {};
23734 * @private The adapter to use to positon and resize elements
23736 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23737 this.adapter.init(this);
23739 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23741 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23742 this.el.addClass("x-splitbar-h");
23745 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23746 this.el.addClass("x-splitbar-v");
23752 * Fires when the splitter is moved (alias for {@link #event-moved})
23753 * @param {Roo.SplitBar} this
23754 * @param {Number} newSize the new width or height
23759 * Fires when the splitter is moved
23760 * @param {Roo.SplitBar} this
23761 * @param {Number} newSize the new width or height
23765 * @event beforeresize
23766 * Fires before the splitter is dragged
23767 * @param {Roo.SplitBar} this
23769 "beforeresize" : true,
23771 "beforeapply" : true
23774 Roo.util.Observable.call(this);
23777 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23778 onStartProxyDrag : function(x, y){
23779 this.fireEvent("beforeresize", this);
23781 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23783 o.enableDisplayMode("block");
23784 // all splitbars share the same overlay
23785 Roo.SplitBar.prototype.overlay = o;
23787 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23788 this.overlay.show();
23789 Roo.get(this.proxy).setDisplayed("block");
23790 var size = this.adapter.getElementSize(this);
23791 this.activeMinSize = this.getMinimumSize();;
23792 this.activeMaxSize = this.getMaximumSize();;
23793 var c1 = size - this.activeMinSize;
23794 var c2 = Math.max(this.activeMaxSize - size, 0);
23795 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23796 this.dd.resetConstraints();
23797 this.dd.setXConstraint(
23798 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23799 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23801 this.dd.setYConstraint(0, 0);
23803 this.dd.resetConstraints();
23804 this.dd.setXConstraint(0, 0);
23805 this.dd.setYConstraint(
23806 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23807 this.placement == Roo.SplitBar.TOP ? c2 : c1
23810 this.dragSpecs.startSize = size;
23811 this.dragSpecs.startPoint = [x, y];
23812 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23816 * @private Called after the drag operation by the DDProxy
23818 onEndProxyDrag : function(e){
23819 Roo.get(this.proxy).setDisplayed(false);
23820 var endPoint = Roo.lib.Event.getXY(e);
23822 this.overlay.hide();
23825 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23826 newSize = this.dragSpecs.startSize +
23827 (this.placement == Roo.SplitBar.LEFT ?
23828 endPoint[0] - this.dragSpecs.startPoint[0] :
23829 this.dragSpecs.startPoint[0] - endPoint[0]
23832 newSize = this.dragSpecs.startSize +
23833 (this.placement == Roo.SplitBar.TOP ?
23834 endPoint[1] - this.dragSpecs.startPoint[1] :
23835 this.dragSpecs.startPoint[1] - endPoint[1]
23838 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23839 if(newSize != this.dragSpecs.startSize){
23840 if(this.fireEvent('beforeapply', this, newSize) !== false){
23841 this.adapter.setElementSize(this, newSize);
23842 this.fireEvent("moved", this, newSize);
23843 this.fireEvent("resize", this, newSize);
23849 * Get the adapter this SplitBar uses
23850 * @return The adapter object
23852 getAdapter : function(){
23853 return this.adapter;
23857 * Set the adapter this SplitBar uses
23858 * @param {Object} adapter A SplitBar adapter object
23860 setAdapter : function(adapter){
23861 this.adapter = adapter;
23862 this.adapter.init(this);
23866 * Gets the minimum size for the resizing element
23867 * @return {Number} The minimum size
23869 getMinimumSize : function(){
23870 return this.minSize;
23874 * Sets the minimum size for the resizing element
23875 * @param {Number} minSize The minimum size
23877 setMinimumSize : function(minSize){
23878 this.minSize = minSize;
23882 * Gets the maximum size for the resizing element
23883 * @return {Number} The maximum size
23885 getMaximumSize : function(){
23886 return this.maxSize;
23890 * Sets the maximum size for the resizing element
23891 * @param {Number} maxSize The maximum size
23893 setMaximumSize : function(maxSize){
23894 this.maxSize = maxSize;
23898 * Sets the initialize size for the resizing element
23899 * @param {Number} size The initial size
23901 setCurrentSize : function(size){
23902 var oldAnimate = this.animate;
23903 this.animate = false;
23904 this.adapter.setElementSize(this, size);
23905 this.animate = oldAnimate;
23909 * Destroy this splitbar.
23910 * @param {Boolean} removeEl True to remove the element
23912 destroy : function(removeEl){
23914 this.shim.remove();
23917 this.proxy.parentNode.removeChild(this.proxy);
23925 * @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.
23927 Roo.SplitBar.createProxy = function(dir){
23928 var proxy = new Roo.Element(document.createElement("div"));
23929 proxy.unselectable();
23930 var cls = 'x-splitbar-proxy';
23931 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23932 document.body.appendChild(proxy.dom);
23937 * @class Roo.SplitBar.BasicLayoutAdapter
23938 * Default Adapter. It assumes the splitter and resizing element are not positioned
23939 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23941 Roo.SplitBar.BasicLayoutAdapter = function(){
23944 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23945 // do nothing for now
23946 init : function(s){
23950 * Called before drag operations to get the current size of the resizing element.
23951 * @param {Roo.SplitBar} s The SplitBar using this adapter
23953 getElementSize : function(s){
23954 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23955 return s.resizingEl.getWidth();
23957 return s.resizingEl.getHeight();
23962 * Called after drag operations to set the size of the resizing element.
23963 * @param {Roo.SplitBar} s The SplitBar using this adapter
23964 * @param {Number} newSize The new size to set
23965 * @param {Function} onComplete A function to be invoked when resizing is complete
23967 setElementSize : function(s, newSize, onComplete){
23968 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23970 s.resizingEl.setWidth(newSize);
23972 onComplete(s, newSize);
23975 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23980 s.resizingEl.setHeight(newSize);
23982 onComplete(s, newSize);
23985 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23992 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23993 * @extends Roo.SplitBar.BasicLayoutAdapter
23994 * Adapter that moves the splitter element to align with the resized sizing element.
23995 * Used with an absolute positioned SplitBar.
23996 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23997 * document.body, make sure you assign an id to the body element.
23999 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24000 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24001 this.container = Roo.get(container);
24004 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24005 init : function(s){
24006 this.basic.init(s);
24009 getElementSize : function(s){
24010 return this.basic.getElementSize(s);
24013 setElementSize : function(s, newSize, onComplete){
24014 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24017 moveSplitter : function(s){
24018 var yes = Roo.SplitBar;
24019 switch(s.placement){
24021 s.el.setX(s.resizingEl.getRight());
24024 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24027 s.el.setY(s.resizingEl.getBottom());
24030 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24037 * Orientation constant - Create a vertical SplitBar
24041 Roo.SplitBar.VERTICAL = 1;
24044 * Orientation constant - Create a horizontal SplitBar
24048 Roo.SplitBar.HORIZONTAL = 2;
24051 * Placement constant - The resizing element is to the left of the splitter element
24055 Roo.SplitBar.LEFT = 1;
24058 * Placement constant - The resizing element is to the right of the splitter element
24062 Roo.SplitBar.RIGHT = 2;
24065 * Placement constant - The resizing element is positioned above the splitter element
24069 Roo.SplitBar.TOP = 3;
24072 * Placement constant - The resizing element is positioned under splitter element
24076 Roo.SplitBar.BOTTOM = 4;
24079 * Ext JS Library 1.1.1
24080 * Copyright(c) 2006-2007, Ext JS, LLC.
24082 * Originally Released Under LGPL - original licence link has changed is not relivant.
24085 * <script type="text/javascript">
24090 * @extends Roo.util.Observable
24091 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24092 * This class also supports single and multi selection modes. <br>
24093 * Create a data model bound view:
24095 var store = new Roo.data.Store(...);
24097 var view = new Roo.View({
24099 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24101 singleSelect: true,
24102 selectedClass: "ydataview-selected",
24106 // listen for node click?
24107 view.on("click", function(vw, index, node, e){
24108 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24112 dataModel.load("foobar.xml");
24114 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24116 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24117 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24119 * Note: old style constructor is still suported (container, template, config)
24122 * Create a new View
24123 * @param {Object} config The config object
24126 Roo.View = function(config, depreciated_tpl, depreciated_config){
24128 if (typeof(depreciated_tpl) == 'undefined') {
24129 // new way.. - universal constructor.
24130 Roo.apply(this, config);
24131 this.el = Roo.get(this.el);
24134 this.el = Roo.get(config);
24135 this.tpl = depreciated_tpl;
24136 Roo.apply(this, depreciated_config);
24138 this.wrapEl = this.el.wrap().wrap();
24139 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24142 if(typeof(this.tpl) == "string"){
24143 this.tpl = new Roo.Template(this.tpl);
24145 // support xtype ctors..
24146 this.tpl = new Roo.factory(this.tpl, Roo);
24150 this.tpl.compile();
24158 * @event beforeclick
24159 * Fires before a click is processed. Returns false to cancel the default action.
24160 * @param {Roo.View} this
24161 * @param {Number} index The index of the target node
24162 * @param {HTMLElement} node The target node
24163 * @param {Roo.EventObject} e The raw event object
24165 "beforeclick" : true,
24168 * Fires when a template node is clicked.
24169 * @param {Roo.View} this
24170 * @param {Number} index The index of the target node
24171 * @param {HTMLElement} node The target node
24172 * @param {Roo.EventObject} e The raw event object
24177 * Fires when a template node is double clicked.
24178 * @param {Roo.View} this
24179 * @param {Number} index The index of the target node
24180 * @param {HTMLElement} node The target node
24181 * @param {Roo.EventObject} e The raw event object
24185 * @event contextmenu
24186 * Fires when a template node is right clicked.
24187 * @param {Roo.View} this
24188 * @param {Number} index The index of the target node
24189 * @param {HTMLElement} node The target node
24190 * @param {Roo.EventObject} e The raw event object
24192 "contextmenu" : true,
24194 * @event selectionchange
24195 * Fires when the selected nodes change.
24196 * @param {Roo.View} this
24197 * @param {Array} selections Array of the selected nodes
24199 "selectionchange" : true,
24202 * @event beforeselect
24203 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24204 * @param {Roo.View} this
24205 * @param {HTMLElement} node The node to be selected
24206 * @param {Array} selections Array of currently selected nodes
24208 "beforeselect" : true,
24210 * @event preparedata
24211 * Fires on every row to render, to allow you to change the data.
24212 * @param {Roo.View} this
24213 * @param {Object} data to be rendered (change this)
24215 "preparedata" : true
24223 "click": this.onClick,
24224 "dblclick": this.onDblClick,
24225 "contextmenu": this.onContextMenu,
24229 this.selections = [];
24231 this.cmp = new Roo.CompositeElementLite([]);
24233 this.store = Roo.factory(this.store, Roo.data);
24234 this.setStore(this.store, true);
24237 if ( this.footer && this.footer.xtype) {
24239 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24241 this.footer.dataSource = this.store
24242 this.footer.container = fctr;
24243 this.footer = Roo.factory(this.footer, Roo);
24244 fctr.insertFirst(this.el);
24246 // this is a bit insane - as the paging toolbar seems to detach the el..
24247 // dom.parentNode.parentNode.parentNode
24248 // they get detached?
24252 Roo.View.superclass.constructor.call(this);
24257 Roo.extend(Roo.View, Roo.util.Observable, {
24260 * @cfg {Roo.data.Store} store Data store to load data from.
24265 * @cfg {String|Roo.Element} el The container element.
24270 * @cfg {String|Roo.Template} tpl The template used by this View
24274 * @cfg {String} dataName the named area of the template to use as the data area
24275 * Works with domtemplates roo-name="name"
24279 * @cfg {String} selectedClass The css class to add to selected nodes
24281 selectedClass : "x-view-selected",
24283 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24288 * @cfg {String} text to display on mask (default Loading)
24292 * @cfg {Boolean} multiSelect Allow multiple selection
24294 multiSelect : false,
24296 * @cfg {Boolean} singleSelect Allow single selection
24298 singleSelect: false,
24301 * @cfg {Boolean} toggleSelect - selecting
24303 toggleSelect : false,
24306 * Returns the element this view is bound to.
24307 * @return {Roo.Element}
24309 getEl : function(){
24310 return this.wrapEl;
24316 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24318 refresh : function(){
24321 // if we are using something like 'domtemplate', then
24322 // the what gets used is:
24323 // t.applySubtemplate(NAME, data, wrapping data..)
24324 // the outer template then get' applied with
24325 // the store 'extra data'
24326 // and the body get's added to the
24327 // roo-name="data" node?
24328 // <span class='roo-tpl-{name}'></span> ?????
24332 this.clearSelections();
24333 this.el.update("");
24335 var records = this.store.getRange();
24336 if(records.length < 1) {
24338 // is this valid?? = should it render a template??
24340 this.el.update(this.emptyText);
24344 if (this.dataName) {
24345 this.el.update(t.apply(this.store.meta)); //????
24346 el = this.el.child('.roo-tpl-' + this.dataName);
24349 for(var i = 0, len = records.length; i < len; i++){
24350 var data = this.prepareData(records[i].data, i, records[i]);
24351 this.fireEvent("preparedata", this, data, i, records[i]);
24352 html[html.length] = Roo.util.Format.trim(
24354 t.applySubtemplate(this.dataName, data, this.store.meta) :
24361 el.update(html.join(""));
24362 this.nodes = el.dom.childNodes;
24363 this.updateIndexes(0);
24367 * Function to override to reformat the data that is sent to
24368 * the template for each node.
24369 * DEPRICATED - use the preparedata event handler.
24370 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24371 * a JSON object for an UpdateManager bound view).
24373 prepareData : function(data, index, record)
24375 this.fireEvent("preparedata", this, data, index, record);
24379 onUpdate : function(ds, record){
24380 this.clearSelections();
24381 var index = this.store.indexOf(record);
24382 var n = this.nodes[index];
24383 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24384 n.parentNode.removeChild(n);
24385 this.updateIndexes(index, index);
24391 onAdd : function(ds, records, index)
24393 this.clearSelections();
24394 if(this.nodes.length == 0){
24398 var n = this.nodes[index];
24399 for(var i = 0, len = records.length; i < len; i++){
24400 var d = this.prepareData(records[i].data, i, records[i]);
24402 this.tpl.insertBefore(n, d);
24405 this.tpl.append(this.el, d);
24408 this.updateIndexes(index);
24411 onRemove : function(ds, record, index){
24412 this.clearSelections();
24413 var el = this.dataName ?
24414 this.el.child('.roo-tpl-' + this.dataName) :
24416 el.dom.removeChild(this.nodes[index]);
24417 this.updateIndexes(index);
24421 * Refresh an individual node.
24422 * @param {Number} index
24424 refreshNode : function(index){
24425 this.onUpdate(this.store, this.store.getAt(index));
24428 updateIndexes : function(startIndex, endIndex){
24429 var ns = this.nodes;
24430 startIndex = startIndex || 0;
24431 endIndex = endIndex || ns.length - 1;
24432 for(var i = startIndex; i <= endIndex; i++){
24433 ns[i].nodeIndex = i;
24438 * Changes the data store this view uses and refresh the view.
24439 * @param {Store} store
24441 setStore : function(store, initial){
24442 if(!initial && this.store){
24443 this.store.un("datachanged", this.refresh);
24444 this.store.un("add", this.onAdd);
24445 this.store.un("remove", this.onRemove);
24446 this.store.un("update", this.onUpdate);
24447 this.store.un("clear", this.refresh);
24448 this.store.un("beforeload", this.onBeforeLoad);
24449 this.store.un("load", this.onLoad);
24450 this.store.un("loadexception", this.onLoad);
24454 store.on("datachanged", this.refresh, this);
24455 store.on("add", this.onAdd, this);
24456 store.on("remove", this.onRemove, this);
24457 store.on("update", this.onUpdate, this);
24458 store.on("clear", this.refresh, this);
24459 store.on("beforeload", this.onBeforeLoad, this);
24460 store.on("load", this.onLoad, this);
24461 store.on("loadexception", this.onLoad, this);
24469 * onbeforeLoad - masks the loading area.
24472 onBeforeLoad : function()
24474 this.el.update("");
24475 this.el.mask(this.mask ? this.mask : "Loading" );
24477 onLoad : function ()
24484 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24485 * @param {HTMLElement} node
24486 * @return {HTMLElement} The template node
24488 findItemFromChild : function(node){
24489 var el = this.dataName ?
24490 this.el.child('.roo-tpl-' + this.dataName,true) :
24493 if(!node || node.parentNode == el){
24496 var p = node.parentNode;
24497 while(p && p != el){
24498 if(p.parentNode == el){
24507 onClick : function(e){
24508 var item = this.findItemFromChild(e.getTarget());
24510 var index = this.indexOf(item);
24511 if(this.onItemClick(item, index, e) !== false){
24512 this.fireEvent("click", this, index, item, e);
24515 this.clearSelections();
24520 onContextMenu : function(e){
24521 var item = this.findItemFromChild(e.getTarget());
24523 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24528 onDblClick : function(e){
24529 var item = this.findItemFromChild(e.getTarget());
24531 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24535 onItemClick : function(item, index, e)
24537 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24540 if (this.toggleSelect) {
24541 var m = this.isSelected(item) ? 'unselect' : 'select';
24544 _t[m](item, true, false);
24547 if(this.multiSelect || this.singleSelect){
24548 if(this.multiSelect && e.shiftKey && this.lastSelection){
24549 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24551 this.select(item, this.multiSelect && e.ctrlKey);
24552 this.lastSelection = item;
24554 e.preventDefault();
24560 * Get the number of selected nodes.
24563 getSelectionCount : function(){
24564 return this.selections.length;
24568 * Get the currently selected nodes.
24569 * @return {Array} An array of HTMLElements
24571 getSelectedNodes : function(){
24572 return this.selections;
24576 * Get the indexes of the selected nodes.
24579 getSelectedIndexes : function(){
24580 var indexes = [], s = this.selections;
24581 for(var i = 0, len = s.length; i < len; i++){
24582 indexes.push(s[i].nodeIndex);
24588 * Clear all selections
24589 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24591 clearSelections : function(suppressEvent){
24592 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24593 this.cmp.elements = this.selections;
24594 this.cmp.removeClass(this.selectedClass);
24595 this.selections = [];
24596 if(!suppressEvent){
24597 this.fireEvent("selectionchange", this, this.selections);
24603 * Returns true if the passed node is selected
24604 * @param {HTMLElement/Number} node The node or node index
24605 * @return {Boolean}
24607 isSelected : function(node){
24608 var s = this.selections;
24612 node = this.getNode(node);
24613 return s.indexOf(node) !== -1;
24618 * @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
24619 * @param {Boolean} keepExisting (optional) true to keep existing selections
24620 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24622 select : function(nodeInfo, keepExisting, suppressEvent){
24623 if(nodeInfo instanceof Array){
24625 this.clearSelections(true);
24627 for(var i = 0, len = nodeInfo.length; i < len; i++){
24628 this.select(nodeInfo[i], true, true);
24632 var node = this.getNode(nodeInfo);
24633 if(!node || this.isSelected(node)){
24634 return; // already selected.
24637 this.clearSelections(true);
24639 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24640 Roo.fly(node).addClass(this.selectedClass);
24641 this.selections.push(node);
24642 if(!suppressEvent){
24643 this.fireEvent("selectionchange", this, this.selections);
24651 * @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
24652 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24653 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24655 unselect : function(nodeInfo, keepExisting, suppressEvent)
24657 if(nodeInfo instanceof Array){
24658 Roo.each(this.selections, function(s) {
24659 this.unselect(s, nodeInfo);
24663 var node = this.getNode(nodeInfo);
24664 if(!node || !this.isSelected(node)){
24665 Roo.log("not selected");
24666 return; // not selected.
24670 Roo.each(this.selections, function(s) {
24672 Roo.fly(node).removeClass(this.selectedClass);
24679 this.selections= ns;
24680 this.fireEvent("selectionchange", this, this.selections);
24684 * Gets a template node.
24685 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24686 * @return {HTMLElement} The node or null if it wasn't found
24688 getNode : function(nodeInfo){
24689 if(typeof nodeInfo == "string"){
24690 return document.getElementById(nodeInfo);
24691 }else if(typeof nodeInfo == "number"){
24692 return this.nodes[nodeInfo];
24698 * Gets a range template nodes.
24699 * @param {Number} startIndex
24700 * @param {Number} endIndex
24701 * @return {Array} An array of nodes
24703 getNodes : function(start, end){
24704 var ns = this.nodes;
24705 start = start || 0;
24706 end = typeof end == "undefined" ? ns.length - 1 : end;
24709 for(var i = start; i <= end; i++){
24713 for(var i = start; i >= end; i--){
24721 * Finds the index of the passed node
24722 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24723 * @return {Number} The index of the node or -1
24725 indexOf : function(node){
24726 node = this.getNode(node);
24727 if(typeof node.nodeIndex == "number"){
24728 return node.nodeIndex;
24730 var ns = this.nodes;
24731 for(var i = 0, len = ns.length; i < len; i++){
24741 * Ext JS Library 1.1.1
24742 * Copyright(c) 2006-2007, Ext JS, LLC.
24744 * Originally Released Under LGPL - original licence link has changed is not relivant.
24747 * <script type="text/javascript">
24751 * @class Roo.JsonView
24752 * @extends Roo.View
24753 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24755 var view = new Roo.JsonView({
24756 container: "my-element",
24757 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24762 // listen for node click?
24763 view.on("click", function(vw, index, node, e){
24764 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24767 // direct load of JSON data
24768 view.load("foobar.php");
24770 // Example from my blog list
24771 var tpl = new Roo.Template(
24772 '<div class="entry">' +
24773 '<a class="entry-title" href="{link}">{title}</a>' +
24774 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24775 "</div><hr />"
24778 var moreView = new Roo.JsonView({
24779 container : "entry-list",
24783 moreView.on("beforerender", this.sortEntries, this);
24785 url: "/blog/get-posts.php",
24786 params: "allposts=true",
24787 text: "Loading Blog Entries..."
24791 * Note: old code is supported with arguments : (container, template, config)
24795 * Create a new JsonView
24797 * @param {Object} config The config object
24800 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24803 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24805 var um = this.el.getUpdateManager();
24806 um.setRenderer(this);
24807 um.on("update", this.onLoad, this);
24808 um.on("failure", this.onLoadException, this);
24811 * @event beforerender
24812 * Fires before rendering of the downloaded JSON data.
24813 * @param {Roo.JsonView} this
24814 * @param {Object} data The JSON data loaded
24818 * Fires when data is loaded.
24819 * @param {Roo.JsonView} this
24820 * @param {Object} data The JSON data loaded
24821 * @param {Object} response The raw Connect response object
24824 * @event loadexception
24825 * Fires when loading fails.
24826 * @param {Roo.JsonView} this
24827 * @param {Object} response The raw Connect response object
24830 'beforerender' : true,
24832 'loadexception' : true
24835 Roo.extend(Roo.JsonView, Roo.View, {
24837 * @type {String} The root property in the loaded JSON object that contains the data
24842 * Refreshes the view.
24844 refresh : function(){
24845 this.clearSelections();
24846 this.el.update("");
24848 var o = this.jsonData;
24849 if(o && o.length > 0){
24850 for(var i = 0, len = o.length; i < len; i++){
24851 var data = this.prepareData(o[i], i, o);
24852 html[html.length] = this.tpl.apply(data);
24855 html.push(this.emptyText);
24857 this.el.update(html.join(""));
24858 this.nodes = this.el.dom.childNodes;
24859 this.updateIndexes(0);
24863 * 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.
24864 * @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:
24867 url: "your-url.php",
24868 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24869 callback: yourFunction,
24870 scope: yourObject, //(optional scope)
24873 text: "Loading...",
24878 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24879 * 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.
24880 * @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}
24881 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24882 * @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.
24885 var um = this.el.getUpdateManager();
24886 um.update.apply(um, arguments);
24889 render : function(el, response){
24890 this.clearSelections();
24891 this.el.update("");
24894 o = Roo.util.JSON.decode(response.responseText);
24897 o = o[this.jsonRoot];
24902 * The current JSON data or null
24905 this.beforeRender();
24910 * Get the number of records in the current JSON dataset
24913 getCount : function(){
24914 return this.jsonData ? this.jsonData.length : 0;
24918 * Returns the JSON object for the specified node(s)
24919 * @param {HTMLElement/Array} node The node or an array of nodes
24920 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24921 * you get the JSON object for the node
24923 getNodeData : function(node){
24924 if(node instanceof Array){
24926 for(var i = 0, len = node.length; i < len; i++){
24927 data.push(this.getNodeData(node[i]));
24931 return this.jsonData[this.indexOf(node)] || null;
24934 beforeRender : function(){
24935 this.snapshot = this.jsonData;
24937 this.sort.apply(this, this.sortInfo);
24939 this.fireEvent("beforerender", this, this.jsonData);
24942 onLoad : function(el, o){
24943 this.fireEvent("load", this, this.jsonData, o);
24946 onLoadException : function(el, o){
24947 this.fireEvent("loadexception", this, o);
24951 * Filter the data by a specific property.
24952 * @param {String} property A property on your JSON objects
24953 * @param {String/RegExp} value Either string that the property values
24954 * should start with, or a RegExp to test against the property
24956 filter : function(property, value){
24959 var ss = this.snapshot;
24960 if(typeof value == "string"){
24961 var vlen = value.length;
24963 this.clearFilter();
24966 value = value.toLowerCase();
24967 for(var i = 0, len = ss.length; i < len; i++){
24969 if(o[property].substr(0, vlen).toLowerCase() == value){
24973 } else if(value.exec){ // regex?
24974 for(var i = 0, len = ss.length; i < len; i++){
24976 if(value.test(o[property])){
24983 this.jsonData = data;
24989 * Filter by a function. The passed function will be called with each
24990 * object in the current dataset. If the function returns true the value is kept,
24991 * otherwise it is filtered.
24992 * @param {Function} fn
24993 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24995 filterBy : function(fn, scope){
24998 var ss = this.snapshot;
24999 for(var i = 0, len = ss.length; i < len; i++){
25001 if(fn.call(scope || this, o)){
25005 this.jsonData = data;
25011 * Clears the current filter.
25013 clearFilter : function(){
25014 if(this.snapshot && this.jsonData != this.snapshot){
25015 this.jsonData = this.snapshot;
25022 * Sorts the data for this view and refreshes it.
25023 * @param {String} property A property on your JSON objects to sort on
25024 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25025 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25027 sort : function(property, dir, sortType){
25028 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25031 var dsc = dir && dir.toLowerCase() == "desc";
25032 var f = function(o1, o2){
25033 var v1 = sortType ? sortType(o1[p]) : o1[p];
25034 var v2 = sortType ? sortType(o2[p]) : o2[p];
25037 return dsc ? +1 : -1;
25038 } else if(v1 > v2){
25039 return dsc ? -1 : +1;
25044 this.jsonData.sort(f);
25046 if(this.jsonData != this.snapshot){
25047 this.snapshot.sort(f);
25053 * Ext JS Library 1.1.1
25054 * Copyright(c) 2006-2007, Ext JS, LLC.
25056 * Originally Released Under LGPL - original licence link has changed is not relivant.
25059 * <script type="text/javascript">
25064 * @class Roo.ColorPalette
25065 * @extends Roo.Component
25066 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25067 * Here's an example of typical usage:
25069 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25070 cp.render('my-div');
25072 cp.on('select', function(palette, selColor){
25073 // do something with selColor
25077 * Create a new ColorPalette
25078 * @param {Object} config The config object
25080 Roo.ColorPalette = function(config){
25081 Roo.ColorPalette.superclass.constructor.call(this, config);
25085 * Fires when a color is selected
25086 * @param {ColorPalette} this
25087 * @param {String} color The 6-digit color hex code (without the # symbol)
25093 this.on("select", this.handler, this.scope, true);
25096 Roo.extend(Roo.ColorPalette, Roo.Component, {
25098 * @cfg {String} itemCls
25099 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25101 itemCls : "x-color-palette",
25103 * @cfg {String} value
25104 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25105 * the hex codes are case-sensitive.
25108 clickEvent:'click',
25110 ctype: "Roo.ColorPalette",
25113 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25115 allowReselect : false,
25118 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25119 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25120 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25121 * of colors with the width setting until the box is symmetrical.</p>
25122 * <p>You can override individual colors if needed:</p>
25124 var cp = new Roo.ColorPalette();
25125 cp.colors[0] = "FF0000"; // change the first box to red
25128 Or you can provide a custom array of your own for complete control:
25130 var cp = new Roo.ColorPalette();
25131 cp.colors = ["000000", "993300", "333300"];
25136 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25137 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25138 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25139 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25140 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25144 onRender : function(container, position){
25145 var t = new Roo.MasterTemplate(
25146 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25148 var c = this.colors;
25149 for(var i = 0, len = c.length; i < len; i++){
25152 var el = document.createElement("div");
25153 el.className = this.itemCls;
25155 container.dom.insertBefore(el, position);
25156 this.el = Roo.get(el);
25157 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25158 if(this.clickEvent != 'click'){
25159 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25164 afterRender : function(){
25165 Roo.ColorPalette.superclass.afterRender.call(this);
25167 var s = this.value;
25174 handleClick : function(e, t){
25175 e.preventDefault();
25176 if(!this.disabled){
25177 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25178 this.select(c.toUpperCase());
25183 * Selects the specified color in the palette (fires the select event)
25184 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25186 select : function(color){
25187 color = color.replace("#", "");
25188 if(color != this.value || this.allowReselect){
25191 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25193 el.child("a.color-"+color).addClass("x-color-palette-sel");
25194 this.value = color;
25195 this.fireEvent("select", this, color);
25200 * Ext JS Library 1.1.1
25201 * Copyright(c) 2006-2007, Ext JS, LLC.
25203 * Originally Released Under LGPL - original licence link has changed is not relivant.
25206 * <script type="text/javascript">
25210 * @class Roo.DatePicker
25211 * @extends Roo.Component
25212 * Simple date picker class.
25214 * Create a new DatePicker
25215 * @param {Object} config The config object
25217 Roo.DatePicker = function(config){
25218 Roo.DatePicker.superclass.constructor.call(this, config);
25220 this.value = config && config.value ?
25221 config.value.clearTime() : new Date().clearTime();
25226 * Fires when a date is selected
25227 * @param {DatePicker} this
25228 * @param {Date} date The selected date
25232 * @event monthchange
25233 * Fires when the displayed month changes
25234 * @param {DatePicker} this
25235 * @param {Date} date The selected month
25237 'monthchange': true
25241 this.on("select", this.handler, this.scope || this);
25243 // build the disabledDatesRE
25244 if(!this.disabledDatesRE && this.disabledDates){
25245 var dd = this.disabledDates;
25247 for(var i = 0; i < dd.length; i++){
25249 if(i != dd.length-1) re += "|";
25251 this.disabledDatesRE = new RegExp(re + ")");
25255 Roo.extend(Roo.DatePicker, Roo.Component, {
25257 * @cfg {String} todayText
25258 * The text to display on the button that selects the current date (defaults to "Today")
25260 todayText : "Today",
25262 * @cfg {String} okText
25263 * The text to display on the ok button
25265 okText : " OK ", //   to give the user extra clicking room
25267 * @cfg {String} cancelText
25268 * The text to display on the cancel button
25270 cancelText : "Cancel",
25272 * @cfg {String} todayTip
25273 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25275 todayTip : "{0} (Spacebar)",
25277 * @cfg {Date} minDate
25278 * Minimum allowable date (JavaScript date object, defaults to null)
25282 * @cfg {Date} maxDate
25283 * Maximum allowable date (JavaScript date object, defaults to null)
25287 * @cfg {String} minText
25288 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25290 minText : "This date is before the minimum date",
25292 * @cfg {String} maxText
25293 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25295 maxText : "This date is after the maximum date",
25297 * @cfg {String} format
25298 * The default date format string which can be overriden for localization support. The format must be
25299 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25303 * @cfg {Array} disabledDays
25304 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25306 disabledDays : null,
25308 * @cfg {String} disabledDaysText
25309 * The tooltip to display when the date falls on a disabled day (defaults to "")
25311 disabledDaysText : "",
25313 * @cfg {RegExp} disabledDatesRE
25314 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25316 disabledDatesRE : null,
25318 * @cfg {String} disabledDatesText
25319 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25321 disabledDatesText : "",
25323 * @cfg {Boolean} constrainToViewport
25324 * True to constrain the date picker to the viewport (defaults to true)
25326 constrainToViewport : true,
25328 * @cfg {Array} monthNames
25329 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25331 monthNames : Date.monthNames,
25333 * @cfg {Array} dayNames
25334 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25336 dayNames : Date.dayNames,
25338 * @cfg {String} nextText
25339 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25341 nextText: 'Next Month (Control+Right)',
25343 * @cfg {String} prevText
25344 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25346 prevText: 'Previous Month (Control+Left)',
25348 * @cfg {String} monthYearText
25349 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25351 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25353 * @cfg {Number} startDay
25354 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25358 * @cfg {Bool} showClear
25359 * Show a clear button (usefull for date form elements that can be blank.)
25365 * Sets the value of the date field
25366 * @param {Date} value The date to set
25368 setValue : function(value){
25369 var old = this.value;
25371 if (typeof(value) == 'string') {
25373 value = Date.parseDate(value, this.format);
25376 value = new Date();
25379 this.value = value.clearTime(true);
25381 this.update(this.value);
25386 * Gets the current selected value of the date field
25387 * @return {Date} The selected date
25389 getValue : function(){
25394 focus : function(){
25396 this.update(this.activeDate);
25401 onRender : function(container, position){
25404 '<table cellspacing="0">',
25405 '<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>',
25406 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25407 var dn = this.dayNames;
25408 for(var i = 0; i < 7; i++){
25409 var d = this.startDay+i;
25413 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25415 m[m.length] = "</tr></thead><tbody><tr>";
25416 for(var i = 0; i < 42; i++) {
25417 if(i % 7 == 0 && i != 0){
25418 m[m.length] = "</tr><tr>";
25420 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25422 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25423 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25425 var el = document.createElement("div");
25426 el.className = "x-date-picker";
25427 el.innerHTML = m.join("");
25429 container.dom.insertBefore(el, position);
25431 this.el = Roo.get(el);
25432 this.eventEl = Roo.get(el.firstChild);
25434 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25435 handler: this.showPrevMonth,
25437 preventDefault:true,
25441 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25442 handler: this.showNextMonth,
25444 preventDefault:true,
25448 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25450 this.monthPicker = this.el.down('div.x-date-mp');
25451 this.monthPicker.enableDisplayMode('block');
25453 var kn = new Roo.KeyNav(this.eventEl, {
25454 "left" : function(e){
25456 this.showPrevMonth() :
25457 this.update(this.activeDate.add("d", -1));
25460 "right" : function(e){
25462 this.showNextMonth() :
25463 this.update(this.activeDate.add("d", 1));
25466 "up" : function(e){
25468 this.showNextYear() :
25469 this.update(this.activeDate.add("d", -7));
25472 "down" : function(e){
25474 this.showPrevYear() :
25475 this.update(this.activeDate.add("d", 7));
25478 "pageUp" : function(e){
25479 this.showNextMonth();
25482 "pageDown" : function(e){
25483 this.showPrevMonth();
25486 "enter" : function(e){
25487 e.stopPropagation();
25494 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25496 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25498 this.el.unselectable();
25500 this.cells = this.el.select("table.x-date-inner tbody td");
25501 this.textNodes = this.el.query("table.x-date-inner tbody span");
25503 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25505 tooltip: this.monthYearText
25508 this.mbtn.on('click', this.showMonthPicker, this);
25509 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25512 var today = (new Date()).dateFormat(this.format);
25514 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25515 if (this.showClear) {
25516 baseTb.add( new Roo.Toolbar.Fill());
25519 text: String.format(this.todayText, today),
25520 tooltip: String.format(this.todayTip, today),
25521 handler: this.selectToday,
25525 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25528 if (this.showClear) {
25530 baseTb.add( new Roo.Toolbar.Fill());
25533 cls: 'x-btn-icon x-btn-clear',
25534 handler: function() {
25536 this.fireEvent("select", this, '');
25546 this.update(this.value);
25549 createMonthPicker : function(){
25550 if(!this.monthPicker.dom.firstChild){
25551 var buf = ['<table border="0" cellspacing="0">'];
25552 for(var i = 0; i < 6; i++){
25554 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25555 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25557 '<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>' :
25558 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25562 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25564 '</button><button type="button" class="x-date-mp-cancel">',
25566 '</button></td></tr>',
25569 this.monthPicker.update(buf.join(''));
25570 this.monthPicker.on('click', this.onMonthClick, this);
25571 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25573 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25574 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25576 this.mpMonths.each(function(m, a, i){
25579 m.dom.xmonth = 5 + Math.round(i * .5);
25581 m.dom.xmonth = Math.round((i-1) * .5);
25587 showMonthPicker : function(){
25588 this.createMonthPicker();
25589 var size = this.el.getSize();
25590 this.monthPicker.setSize(size);
25591 this.monthPicker.child('table').setSize(size);
25593 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25594 this.updateMPMonth(this.mpSelMonth);
25595 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25596 this.updateMPYear(this.mpSelYear);
25598 this.monthPicker.slideIn('t', {duration:.2});
25601 updateMPYear : function(y){
25603 var ys = this.mpYears.elements;
25604 for(var i = 1; i <= 10; i++){
25605 var td = ys[i-1], y2;
25607 y2 = y + Math.round(i * .5);
25608 td.firstChild.innerHTML = y2;
25611 y2 = y - (5-Math.round(i * .5));
25612 td.firstChild.innerHTML = y2;
25615 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25619 updateMPMonth : function(sm){
25620 this.mpMonths.each(function(m, a, i){
25621 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25625 selectMPMonth: function(m){
25629 onMonthClick : function(e, t){
25631 var el = new Roo.Element(t), pn;
25632 if(el.is('button.x-date-mp-cancel')){
25633 this.hideMonthPicker();
25635 else if(el.is('button.x-date-mp-ok')){
25636 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25637 this.hideMonthPicker();
25639 else if(pn = el.up('td.x-date-mp-month', 2)){
25640 this.mpMonths.removeClass('x-date-mp-sel');
25641 pn.addClass('x-date-mp-sel');
25642 this.mpSelMonth = pn.dom.xmonth;
25644 else if(pn = el.up('td.x-date-mp-year', 2)){
25645 this.mpYears.removeClass('x-date-mp-sel');
25646 pn.addClass('x-date-mp-sel');
25647 this.mpSelYear = pn.dom.xyear;
25649 else if(el.is('a.x-date-mp-prev')){
25650 this.updateMPYear(this.mpyear-10);
25652 else if(el.is('a.x-date-mp-next')){
25653 this.updateMPYear(this.mpyear+10);
25657 onMonthDblClick : function(e, t){
25659 var el = new Roo.Element(t), pn;
25660 if(pn = el.up('td.x-date-mp-month', 2)){
25661 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25662 this.hideMonthPicker();
25664 else if(pn = el.up('td.x-date-mp-year', 2)){
25665 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25666 this.hideMonthPicker();
25670 hideMonthPicker : function(disableAnim){
25671 if(this.monthPicker){
25672 if(disableAnim === true){
25673 this.monthPicker.hide();
25675 this.monthPicker.slideOut('t', {duration:.2});
25681 showPrevMonth : function(e){
25682 this.update(this.activeDate.add("mo", -1));
25686 showNextMonth : function(e){
25687 this.update(this.activeDate.add("mo", 1));
25691 showPrevYear : function(){
25692 this.update(this.activeDate.add("y", -1));
25696 showNextYear : function(){
25697 this.update(this.activeDate.add("y", 1));
25701 handleMouseWheel : function(e){
25702 var delta = e.getWheelDelta();
25704 this.showPrevMonth();
25706 } else if(delta < 0){
25707 this.showNextMonth();
25713 handleDateClick : function(e, t){
25715 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25716 this.setValue(new Date(t.dateValue));
25717 this.fireEvent("select", this, this.value);
25722 selectToday : function(){
25723 this.setValue(new Date().clearTime());
25724 this.fireEvent("select", this, this.value);
25728 update : function(date)
25730 var vd = this.activeDate;
25731 this.activeDate = date;
25733 var t = date.getTime();
25734 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25735 this.cells.removeClass("x-date-selected");
25736 this.cells.each(function(c){
25737 if(c.dom.firstChild.dateValue == t){
25738 c.addClass("x-date-selected");
25739 setTimeout(function(){
25740 try{c.dom.firstChild.focus();}catch(e){}
25749 var days = date.getDaysInMonth();
25750 var firstOfMonth = date.getFirstDateOfMonth();
25751 var startingPos = firstOfMonth.getDay()-this.startDay;
25753 if(startingPos <= this.startDay){
25757 var pm = date.add("mo", -1);
25758 var prevStart = pm.getDaysInMonth()-startingPos;
25760 var cells = this.cells.elements;
25761 var textEls = this.textNodes;
25762 days += startingPos;
25764 // convert everything to numbers so it's fast
25765 var day = 86400000;
25766 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25767 var today = new Date().clearTime().getTime();
25768 var sel = date.clearTime().getTime();
25769 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25770 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25771 var ddMatch = this.disabledDatesRE;
25772 var ddText = this.disabledDatesText;
25773 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25774 var ddaysText = this.disabledDaysText;
25775 var format = this.format;
25777 var setCellClass = function(cal, cell){
25779 var t = d.getTime();
25780 cell.firstChild.dateValue = t;
25782 cell.className += " x-date-today";
25783 cell.title = cal.todayText;
25786 cell.className += " x-date-selected";
25787 setTimeout(function(){
25788 try{cell.firstChild.focus();}catch(e){}
25793 cell.className = " x-date-disabled";
25794 cell.title = cal.minText;
25798 cell.className = " x-date-disabled";
25799 cell.title = cal.maxText;
25803 if(ddays.indexOf(d.getDay()) != -1){
25804 cell.title = ddaysText;
25805 cell.className = " x-date-disabled";
25808 if(ddMatch && format){
25809 var fvalue = d.dateFormat(format);
25810 if(ddMatch.test(fvalue)){
25811 cell.title = ddText.replace("%0", fvalue);
25812 cell.className = " x-date-disabled";
25818 for(; i < startingPos; i++) {
25819 textEls[i].innerHTML = (++prevStart);
25820 d.setDate(d.getDate()+1);
25821 cells[i].className = "x-date-prevday";
25822 setCellClass(this, cells[i]);
25824 for(; i < days; i++){
25825 intDay = i - startingPos + 1;
25826 textEls[i].innerHTML = (intDay);
25827 d.setDate(d.getDate()+1);
25828 cells[i].className = "x-date-active";
25829 setCellClass(this, cells[i]);
25832 for(; i < 42; i++) {
25833 textEls[i].innerHTML = (++extraDays);
25834 d.setDate(d.getDate()+1);
25835 cells[i].className = "x-date-nextday";
25836 setCellClass(this, cells[i]);
25839 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25840 this.fireEvent('monthchange', this, date);
25842 if(!this.internalRender){
25843 var main = this.el.dom.firstChild;
25844 var w = main.offsetWidth;
25845 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25846 Roo.fly(main).setWidth(w);
25847 this.internalRender = true;
25848 // opera does not respect the auto grow header center column
25849 // then, after it gets a width opera refuses to recalculate
25850 // without a second pass
25851 if(Roo.isOpera && !this.secondPass){
25852 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25853 this.secondPass = true;
25854 this.update.defer(10, this, [date]);
25862 * Ext JS Library 1.1.1
25863 * Copyright(c) 2006-2007, Ext JS, LLC.
25865 * Originally Released Under LGPL - original licence link has changed is not relivant.
25868 * <script type="text/javascript">
25871 * @class Roo.TabPanel
25872 * @extends Roo.util.Observable
25873 * A lightweight tab container.
25877 // basic tabs 1, built from existing content
25878 var tabs = new Roo.TabPanel("tabs1");
25879 tabs.addTab("script", "View Script");
25880 tabs.addTab("markup", "View Markup");
25881 tabs.activate("script");
25883 // more advanced tabs, built from javascript
25884 var jtabs = new Roo.TabPanel("jtabs");
25885 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25887 // set up the UpdateManager
25888 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25889 var updater = tab2.getUpdateManager();
25890 updater.setDefaultUrl("ajax1.htm");
25891 tab2.on('activate', updater.refresh, updater, true);
25893 // Use setUrl for Ajax loading
25894 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25895 tab3.setUrl("ajax2.htm", null, true);
25898 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25901 jtabs.activate("jtabs-1");
25904 * Create a new TabPanel.
25905 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25906 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25908 Roo.TabPanel = function(container, config){
25910 * The container element for this TabPanel.
25911 * @type Roo.Element
25913 this.el = Roo.get(container, true);
25915 if(typeof config == "boolean"){
25916 this.tabPosition = config ? "bottom" : "top";
25918 Roo.apply(this, config);
25921 if(this.tabPosition == "bottom"){
25922 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25923 this.el.addClass("x-tabs-bottom");
25925 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25926 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25927 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25929 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25931 if(this.tabPosition != "bottom"){
25932 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25933 * @type Roo.Element
25935 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25936 this.el.addClass("x-tabs-top");
25940 this.bodyEl.setStyle("position", "relative");
25942 this.active = null;
25943 this.activateDelegate = this.activate.createDelegate(this);
25948 * Fires when the active tab changes
25949 * @param {Roo.TabPanel} this
25950 * @param {Roo.TabPanelItem} activePanel The new active tab
25954 * @event beforetabchange
25955 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25956 * @param {Roo.TabPanel} this
25957 * @param {Object} e Set cancel to true on this object to cancel the tab change
25958 * @param {Roo.TabPanelItem} tab The tab being changed to
25960 "beforetabchange" : true
25963 Roo.EventManager.onWindowResize(this.onResize, this);
25964 this.cpad = this.el.getPadding("lr");
25965 this.hiddenCount = 0;
25968 // toolbar on the tabbar support...
25969 if (this.toolbar) {
25970 var tcfg = this.toolbar;
25971 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25972 this.toolbar = new Roo.Toolbar(tcfg);
25973 if (Roo.isSafari) {
25974 var tbl = tcfg.container.child('table', true);
25975 tbl.setAttribute('width', '100%');
25982 Roo.TabPanel.superclass.constructor.call(this);
25985 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25987 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25989 tabPosition : "top",
25991 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25993 currentTabWidth : 0,
25995 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25999 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26003 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26005 preferredTabWidth : 175,
26007 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26009 resizeTabs : false,
26011 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26013 monitorResize : true,
26015 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26020 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26021 * @param {String} id The id of the div to use <b>or create</b>
26022 * @param {String} text The text for the tab
26023 * @param {String} content (optional) Content to put in the TabPanelItem body
26024 * @param {Boolean} closable (optional) True to create a close icon on the tab
26025 * @return {Roo.TabPanelItem} The created TabPanelItem
26027 addTab : function(id, text, content, closable){
26028 var item = new Roo.TabPanelItem(this, id, text, closable);
26029 this.addTabItem(item);
26031 item.setContent(content);
26037 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26038 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26039 * @return {Roo.TabPanelItem}
26041 getTab : function(id){
26042 return this.items[id];
26046 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26047 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26049 hideTab : function(id){
26050 var t = this.items[id];
26053 this.hiddenCount++;
26054 this.autoSizeTabs();
26059 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26060 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26062 unhideTab : function(id){
26063 var t = this.items[id];
26065 t.setHidden(false);
26066 this.hiddenCount--;
26067 this.autoSizeTabs();
26072 * Adds an existing {@link Roo.TabPanelItem}.
26073 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26075 addTabItem : function(item){
26076 this.items[item.id] = item;
26077 this.items.push(item);
26078 if(this.resizeTabs){
26079 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26080 this.autoSizeTabs();
26087 * Removes a {@link Roo.TabPanelItem}.
26088 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26090 removeTab : function(id){
26091 var items = this.items;
26092 var tab = items[id];
26093 if(!tab) { return; }
26094 var index = items.indexOf(tab);
26095 if(this.active == tab && items.length > 1){
26096 var newTab = this.getNextAvailable(index);
26101 this.stripEl.dom.removeChild(tab.pnode.dom);
26102 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26103 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26105 items.splice(index, 1);
26106 delete this.items[tab.id];
26107 tab.fireEvent("close", tab);
26108 tab.purgeListeners();
26109 this.autoSizeTabs();
26112 getNextAvailable : function(start){
26113 var items = this.items;
26115 // look for a next tab that will slide over to
26116 // replace the one being removed
26117 while(index < items.length){
26118 var item = items[++index];
26119 if(item && !item.isHidden()){
26123 // if one isn't found select the previous tab (on the left)
26126 var item = items[--index];
26127 if(item && !item.isHidden()){
26135 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26136 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26138 disableTab : function(id){
26139 var tab = this.items[id];
26140 if(tab && this.active != tab){
26146 * Enables a {@link Roo.TabPanelItem} that is disabled.
26147 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26149 enableTab : function(id){
26150 var tab = this.items[id];
26155 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26156 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26157 * @return {Roo.TabPanelItem} The TabPanelItem.
26159 activate : function(id){
26160 var tab = this.items[id];
26164 if(tab == this.active || tab.disabled){
26168 this.fireEvent("beforetabchange", this, e, tab);
26169 if(e.cancel !== true && !tab.disabled){
26171 this.active.hide();
26173 this.active = this.items[id];
26174 this.active.show();
26175 this.fireEvent("tabchange", this, this.active);
26181 * Gets the active {@link Roo.TabPanelItem}.
26182 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26184 getActiveTab : function(){
26185 return this.active;
26189 * Updates the tab body element to fit the height of the container element
26190 * for overflow scrolling
26191 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26193 syncHeight : function(targetHeight){
26194 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26195 var bm = this.bodyEl.getMargins();
26196 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26197 this.bodyEl.setHeight(newHeight);
26201 onResize : function(){
26202 if(this.monitorResize){
26203 this.autoSizeTabs();
26208 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26210 beginUpdate : function(){
26211 this.updating = true;
26215 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26217 endUpdate : function(){
26218 this.updating = false;
26219 this.autoSizeTabs();
26223 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26225 autoSizeTabs : function(){
26226 var count = this.items.length;
26227 var vcount = count - this.hiddenCount;
26228 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26229 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26230 var availWidth = Math.floor(w / vcount);
26231 var b = this.stripBody;
26232 if(b.getWidth() > w){
26233 var tabs = this.items;
26234 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26235 if(availWidth < this.minTabWidth){
26236 /*if(!this.sleft){ // incomplete scrolling code
26237 this.createScrollButtons();
26240 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26243 if(this.currentTabWidth < this.preferredTabWidth){
26244 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26250 * Returns the number of tabs in this TabPanel.
26253 getCount : function(){
26254 return this.items.length;
26258 * Resizes all the tabs to the passed width
26259 * @param {Number} The new width
26261 setTabWidth : function(width){
26262 this.currentTabWidth = width;
26263 for(var i = 0, len = this.items.length; i < len; i++) {
26264 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26269 * Destroys this TabPanel
26270 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26272 destroy : function(removeEl){
26273 Roo.EventManager.removeResizeListener(this.onResize, this);
26274 for(var i = 0, len = this.items.length; i < len; i++){
26275 this.items[i].purgeListeners();
26277 if(removeEl === true){
26278 this.el.update("");
26285 * @class Roo.TabPanelItem
26286 * @extends Roo.util.Observable
26287 * Represents an individual item (tab plus body) in a TabPanel.
26288 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26289 * @param {String} id The id of this TabPanelItem
26290 * @param {String} text The text for the tab of this TabPanelItem
26291 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26293 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26295 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26296 * @type Roo.TabPanel
26298 this.tabPanel = tabPanel;
26300 * The id for this TabPanelItem
26305 this.disabled = false;
26309 this.loaded = false;
26310 this.closable = closable;
26313 * The body element for this TabPanelItem.
26314 * @type Roo.Element
26316 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26317 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26318 this.bodyEl.setStyle("display", "block");
26319 this.bodyEl.setStyle("zoom", "1");
26322 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26324 this.el = Roo.get(els.el, true);
26325 this.inner = Roo.get(els.inner, true);
26326 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26327 this.pnode = Roo.get(els.el.parentNode, true);
26328 this.el.on("mousedown", this.onTabMouseDown, this);
26329 this.el.on("click", this.onTabClick, this);
26332 var c = Roo.get(els.close, true);
26333 c.dom.title = this.closeText;
26334 c.addClassOnOver("close-over");
26335 c.on("click", this.closeClick, this);
26341 * Fires when this tab becomes the active tab.
26342 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26343 * @param {Roo.TabPanelItem} this
26347 * @event beforeclose
26348 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26349 * @param {Roo.TabPanelItem} this
26350 * @param {Object} e Set cancel to true on this object to cancel the close.
26352 "beforeclose": true,
26355 * Fires when this tab is closed.
26356 * @param {Roo.TabPanelItem} this
26360 * @event deactivate
26361 * Fires when this tab is no longer the active tab.
26362 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26363 * @param {Roo.TabPanelItem} this
26365 "deactivate" : true
26367 this.hidden = false;
26369 Roo.TabPanelItem.superclass.constructor.call(this);
26372 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26373 purgeListeners : function(){
26374 Roo.util.Observable.prototype.purgeListeners.call(this);
26375 this.el.removeAllListeners();
26378 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26381 this.pnode.addClass("on");
26384 this.tabPanel.stripWrap.repaint();
26386 this.fireEvent("activate", this.tabPanel, this);
26390 * Returns true if this tab is the active tab.
26391 * @return {Boolean}
26393 isActive : function(){
26394 return this.tabPanel.getActiveTab() == this;
26398 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26401 this.pnode.removeClass("on");
26403 this.fireEvent("deactivate", this.tabPanel, this);
26406 hideAction : function(){
26407 this.bodyEl.hide();
26408 this.bodyEl.setStyle("position", "absolute");
26409 this.bodyEl.setLeft("-20000px");
26410 this.bodyEl.setTop("-20000px");
26413 showAction : function(){
26414 this.bodyEl.setStyle("position", "relative");
26415 this.bodyEl.setTop("");
26416 this.bodyEl.setLeft("");
26417 this.bodyEl.show();
26421 * Set the tooltip for the tab.
26422 * @param {String} tooltip The tab's tooltip
26424 setTooltip : function(text){
26425 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26426 this.textEl.dom.qtip = text;
26427 this.textEl.dom.removeAttribute('title');
26429 this.textEl.dom.title = text;
26433 onTabClick : function(e){
26434 e.preventDefault();
26435 this.tabPanel.activate(this.id);
26438 onTabMouseDown : function(e){
26439 e.preventDefault();
26440 this.tabPanel.activate(this.id);
26443 getWidth : function(){
26444 return this.inner.getWidth();
26447 setWidth : function(width){
26448 var iwidth = width - this.pnode.getPadding("lr");
26449 this.inner.setWidth(iwidth);
26450 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26451 this.pnode.setWidth(width);
26455 * Show or hide the tab
26456 * @param {Boolean} hidden True to hide or false to show.
26458 setHidden : function(hidden){
26459 this.hidden = hidden;
26460 this.pnode.setStyle("display", hidden ? "none" : "");
26464 * Returns true if this tab is "hidden"
26465 * @return {Boolean}
26467 isHidden : function(){
26468 return this.hidden;
26472 * Returns the text for this tab
26475 getText : function(){
26479 autoSize : function(){
26480 //this.el.beginMeasure();
26481 this.textEl.setWidth(1);
26482 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26483 //this.el.endMeasure();
26487 * Sets the text for the tab (Note: this also sets the tooltip text)
26488 * @param {String} text The tab's text and tooltip
26490 setText : function(text){
26492 this.textEl.update(text);
26493 this.setTooltip(text);
26494 if(!this.tabPanel.resizeTabs){
26499 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26501 activate : function(){
26502 this.tabPanel.activate(this.id);
26506 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26508 disable : function(){
26509 if(this.tabPanel.active != this){
26510 this.disabled = true;
26511 this.pnode.addClass("disabled");
26516 * Enables this TabPanelItem if it was previously disabled.
26518 enable : function(){
26519 this.disabled = false;
26520 this.pnode.removeClass("disabled");
26524 * Sets the content for this TabPanelItem.
26525 * @param {String} content The content
26526 * @param {Boolean} loadScripts true to look for and load scripts
26528 setContent : function(content, loadScripts){
26529 this.bodyEl.update(content, loadScripts);
26533 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26534 * @return {Roo.UpdateManager} The UpdateManager
26536 getUpdateManager : function(){
26537 return this.bodyEl.getUpdateManager();
26541 * Set a URL to be used to load the content for this TabPanelItem.
26542 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26543 * @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)
26544 * @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)
26545 * @return {Roo.UpdateManager} The UpdateManager
26547 setUrl : function(url, params, loadOnce){
26548 if(this.refreshDelegate){
26549 this.un('activate', this.refreshDelegate);
26551 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26552 this.on("activate", this.refreshDelegate);
26553 return this.bodyEl.getUpdateManager();
26557 _handleRefresh : function(url, params, loadOnce){
26558 if(!loadOnce || !this.loaded){
26559 var updater = this.bodyEl.getUpdateManager();
26560 updater.update(url, params, this._setLoaded.createDelegate(this));
26565 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26566 * Will fail silently if the setUrl method has not been called.
26567 * This does not activate the panel, just updates its content.
26569 refresh : function(){
26570 if(this.refreshDelegate){
26571 this.loaded = false;
26572 this.refreshDelegate();
26577 _setLoaded : function(){
26578 this.loaded = true;
26582 closeClick : function(e){
26585 this.fireEvent("beforeclose", this, o);
26586 if(o.cancel !== true){
26587 this.tabPanel.removeTab(this.id);
26591 * The text displayed in the tooltip for the close icon.
26594 closeText : "Close this tab"
26598 Roo.TabPanel.prototype.createStrip = function(container){
26599 var strip = document.createElement("div");
26600 strip.className = "x-tabs-wrap";
26601 container.appendChild(strip);
26605 Roo.TabPanel.prototype.createStripList = function(strip){
26606 // div wrapper for retard IE
26607 // returns the "tr" element.
26608 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26609 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26610 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26611 return strip.firstChild.firstChild.firstChild.firstChild;
26614 Roo.TabPanel.prototype.createBody = function(container){
26615 var body = document.createElement("div");
26616 Roo.id(body, "tab-body");
26617 Roo.fly(body).addClass("x-tabs-body");
26618 container.appendChild(body);
26622 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26623 var body = Roo.getDom(id);
26625 body = document.createElement("div");
26628 Roo.fly(body).addClass("x-tabs-item-body");
26629 bodyEl.insertBefore(body, bodyEl.firstChild);
26633 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26634 var td = document.createElement("td");
26635 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26636 //stripEl.appendChild(td);
26638 td.className = "x-tabs-closable";
26639 if(!this.closeTpl){
26640 this.closeTpl = new Roo.Template(
26641 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26642 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26643 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26646 var el = this.closeTpl.overwrite(td, {"text": text});
26647 var close = el.getElementsByTagName("div")[0];
26648 var inner = el.getElementsByTagName("em")[0];
26649 return {"el": el, "close": close, "inner": inner};
26652 this.tabTpl = new Roo.Template(
26653 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26654 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26657 var el = this.tabTpl.overwrite(td, {"text": text});
26658 var inner = el.getElementsByTagName("em")[0];
26659 return {"el": el, "inner": inner};
26663 * Ext JS Library 1.1.1
26664 * Copyright(c) 2006-2007, Ext JS, LLC.
26666 * Originally Released Under LGPL - original licence link has changed is not relivant.
26669 * <script type="text/javascript">
26673 * @class Roo.Button
26674 * @extends Roo.util.Observable
26675 * Simple Button class
26676 * @cfg {String} text The button text
26677 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26678 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26679 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26680 * @cfg {Object} scope The scope of the handler
26681 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26682 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26683 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26684 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26685 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26686 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26687 applies if enableToggle = true)
26688 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26689 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26690 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26692 * Create a new button
26693 * @param {Object} config The config object
26695 Roo.Button = function(renderTo, config)
26699 renderTo = config.renderTo || false;
26702 Roo.apply(this, config);
26706 * Fires when this button is clicked
26707 * @param {Button} this
26708 * @param {EventObject} e The click event
26713 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26714 * @param {Button} this
26715 * @param {Boolean} pressed
26720 * Fires when the mouse hovers over the button
26721 * @param {Button} this
26722 * @param {Event} e The event object
26724 'mouseover' : true,
26727 * Fires when the mouse exits the button
26728 * @param {Button} this
26729 * @param {Event} e The event object
26734 * Fires when the button is rendered
26735 * @param {Button} this
26740 this.menu = Roo.menu.MenuMgr.get(this.menu);
26742 // register listeners first!! - so render can be captured..
26743 Roo.util.Observable.call(this);
26745 this.render(renderTo);
26751 Roo.extend(Roo.Button, Roo.util.Observable, {
26757 * Read-only. True if this button is hidden
26762 * Read-only. True if this button is disabled
26767 * Read-only. True if this button is pressed (only if enableToggle = true)
26773 * @cfg {Number} tabIndex
26774 * The DOM tabIndex for this button (defaults to undefined)
26776 tabIndex : undefined,
26779 * @cfg {Boolean} enableToggle
26780 * True to enable pressed/not pressed toggling (defaults to false)
26782 enableToggle: false,
26784 * @cfg {Mixed} menu
26785 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26789 * @cfg {String} menuAlign
26790 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26792 menuAlign : "tl-bl?",
26795 * @cfg {String} iconCls
26796 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26798 iconCls : undefined,
26800 * @cfg {String} type
26801 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26806 menuClassTarget: 'tr',
26809 * @cfg {String} clickEvent
26810 * The type of event to map to the button's event handler (defaults to 'click')
26812 clickEvent : 'click',
26815 * @cfg {Boolean} handleMouseEvents
26816 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26818 handleMouseEvents : true,
26821 * @cfg {String} tooltipType
26822 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26824 tooltipType : 'qtip',
26827 * @cfg {String} cls
26828 * A CSS class to apply to the button's main element.
26832 * @cfg {Roo.Template} template (Optional)
26833 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26834 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26835 * require code modifications if required elements (e.g. a button) aren't present.
26839 render : function(renderTo){
26841 if(this.hideParent){
26842 this.parentEl = Roo.get(renderTo);
26844 if(!this.dhconfig){
26845 if(!this.template){
26846 if(!Roo.Button.buttonTemplate){
26847 // hideous table template
26848 Roo.Button.buttonTemplate = new Roo.Template(
26849 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26850 '<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>',
26851 "</tr></tbody></table>");
26853 this.template = Roo.Button.buttonTemplate;
26855 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26856 var btnEl = btn.child("button:first");
26857 btnEl.on('focus', this.onFocus, this);
26858 btnEl.on('blur', this.onBlur, this);
26860 btn.addClass(this.cls);
26863 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26866 btnEl.addClass(this.iconCls);
26868 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26871 if(this.tabIndex !== undefined){
26872 btnEl.dom.tabIndex = this.tabIndex;
26875 if(typeof this.tooltip == 'object'){
26876 Roo.QuickTips.tips(Roo.apply({
26880 btnEl.dom[this.tooltipType] = this.tooltip;
26884 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26888 this.el.dom.id = this.el.id = this.id;
26891 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26892 this.menu.on("show", this.onMenuShow, this);
26893 this.menu.on("hide", this.onMenuHide, this);
26895 btn.addClass("x-btn");
26896 if(Roo.isIE && !Roo.isIE7){
26897 this.autoWidth.defer(1, this);
26901 if(this.handleMouseEvents){
26902 btn.on("mouseover", this.onMouseOver, this);
26903 btn.on("mouseout", this.onMouseOut, this);
26904 btn.on("mousedown", this.onMouseDown, this);
26906 btn.on(this.clickEvent, this.onClick, this);
26907 //btn.on("mouseup", this.onMouseUp, this);
26914 Roo.ButtonToggleMgr.register(this);
26916 this.el.addClass("x-btn-pressed");
26919 var repeater = new Roo.util.ClickRepeater(btn,
26920 typeof this.repeat == "object" ? this.repeat : {}
26922 repeater.on("click", this.onClick, this);
26925 this.fireEvent('render', this);
26929 * Returns the button's underlying element
26930 * @return {Roo.Element} The element
26932 getEl : function(){
26937 * Destroys this Button and removes any listeners.
26939 destroy : function(){
26940 Roo.ButtonToggleMgr.unregister(this);
26941 this.el.removeAllListeners();
26942 this.purgeListeners();
26947 autoWidth : function(){
26949 this.el.setWidth("auto");
26950 if(Roo.isIE7 && Roo.isStrict){
26951 var ib = this.el.child('button');
26952 if(ib && ib.getWidth() > 20){
26954 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26959 this.el.beginMeasure();
26961 if(this.el.getWidth() < this.minWidth){
26962 this.el.setWidth(this.minWidth);
26965 this.el.endMeasure();
26972 * Assigns this button's click handler
26973 * @param {Function} handler The function to call when the button is clicked
26974 * @param {Object} scope (optional) Scope for the function passed in
26976 setHandler : function(handler, scope){
26977 this.handler = handler;
26978 this.scope = scope;
26982 * Sets this button's text
26983 * @param {String} text The button text
26985 setText : function(text){
26988 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26994 * Gets the text for this button
26995 * @return {String} The button text
26997 getText : function(){
27005 this.hidden = false;
27007 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27015 this.hidden = true;
27017 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27022 * Convenience function for boolean show/hide
27023 * @param {Boolean} visible True to show, false to hide
27025 setVisible: function(visible){
27034 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27035 * @param {Boolean} state (optional) Force a particular state
27037 toggle : function(state){
27038 state = state === undefined ? !this.pressed : state;
27039 if(state != this.pressed){
27041 this.el.addClass("x-btn-pressed");
27042 this.pressed = true;
27043 this.fireEvent("toggle", this, true);
27045 this.el.removeClass("x-btn-pressed");
27046 this.pressed = false;
27047 this.fireEvent("toggle", this, false);
27049 if(this.toggleHandler){
27050 this.toggleHandler.call(this.scope || this, this, state);
27058 focus : function(){
27059 this.el.child('button:first').focus();
27063 * Disable this button
27065 disable : function(){
27067 this.el.addClass("x-btn-disabled");
27069 this.disabled = true;
27073 * Enable this button
27075 enable : function(){
27077 this.el.removeClass("x-btn-disabled");
27079 this.disabled = false;
27083 * Convenience function for boolean enable/disable
27084 * @param {Boolean} enabled True to enable, false to disable
27086 setDisabled : function(v){
27087 this[v !== true ? "enable" : "disable"]();
27091 onClick : function(e){
27093 e.preventDefault();
27098 if(!this.disabled){
27099 if(this.enableToggle){
27102 if(this.menu && !this.menu.isVisible()){
27103 this.menu.show(this.el, this.menuAlign);
27105 this.fireEvent("click", this, e);
27107 this.el.removeClass("x-btn-over");
27108 this.handler.call(this.scope || this, this, e);
27113 onMouseOver : function(e){
27114 if(!this.disabled){
27115 this.el.addClass("x-btn-over");
27116 this.fireEvent('mouseover', this, e);
27120 onMouseOut : function(e){
27121 if(!e.within(this.el, true)){
27122 this.el.removeClass("x-btn-over");
27123 this.fireEvent('mouseout', this, e);
27127 onFocus : function(e){
27128 if(!this.disabled){
27129 this.el.addClass("x-btn-focus");
27133 onBlur : function(e){
27134 this.el.removeClass("x-btn-focus");
27137 onMouseDown : function(e){
27138 if(!this.disabled && e.button == 0){
27139 this.el.addClass("x-btn-click");
27140 Roo.get(document).on('mouseup', this.onMouseUp, this);
27144 onMouseUp : function(e){
27146 this.el.removeClass("x-btn-click");
27147 Roo.get(document).un('mouseup', this.onMouseUp, this);
27151 onMenuShow : function(e){
27152 this.el.addClass("x-btn-menu-active");
27155 onMenuHide : function(e){
27156 this.el.removeClass("x-btn-menu-active");
27160 // Private utility class used by Button
27161 Roo.ButtonToggleMgr = function(){
27164 function toggleGroup(btn, state){
27166 var g = groups[btn.toggleGroup];
27167 for(var i = 0, l = g.length; i < l; i++){
27169 g[i].toggle(false);
27176 register : function(btn){
27177 if(!btn.toggleGroup){
27180 var g = groups[btn.toggleGroup];
27182 g = groups[btn.toggleGroup] = [];
27185 btn.on("toggle", toggleGroup);
27188 unregister : function(btn){
27189 if(!btn.toggleGroup){
27192 var g = groups[btn.toggleGroup];
27195 btn.un("toggle", toggleGroup);
27201 * Ext JS Library 1.1.1
27202 * Copyright(c) 2006-2007, Ext JS, LLC.
27204 * Originally Released Under LGPL - original licence link has changed is not relivant.
27207 * <script type="text/javascript">
27211 * @class Roo.SplitButton
27212 * @extends Roo.Button
27213 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27214 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27215 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27216 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27217 * @cfg {String} arrowTooltip The title attribute of the arrow
27219 * Create a new menu button
27220 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27221 * @param {Object} config The config object
27223 Roo.SplitButton = function(renderTo, config){
27224 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27226 * @event arrowclick
27227 * Fires when this button's arrow is clicked
27228 * @param {SplitButton} this
27229 * @param {EventObject} e The click event
27231 this.addEvents({"arrowclick":true});
27234 Roo.extend(Roo.SplitButton, Roo.Button, {
27235 render : function(renderTo){
27236 // this is one sweet looking template!
27237 var tpl = new Roo.Template(
27238 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27239 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27240 '<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>',
27241 "</tbody></table></td><td>",
27242 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27243 '<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>',
27244 "</tbody></table></td></tr></table>"
27246 var btn = tpl.append(renderTo, [this.text, this.type], true);
27247 var btnEl = btn.child("button");
27249 btn.addClass(this.cls);
27252 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27255 btnEl.addClass(this.iconCls);
27257 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27261 if(this.handleMouseEvents){
27262 btn.on("mouseover", this.onMouseOver, this);
27263 btn.on("mouseout", this.onMouseOut, this);
27264 btn.on("mousedown", this.onMouseDown, this);
27265 btn.on("mouseup", this.onMouseUp, this);
27267 btn.on(this.clickEvent, this.onClick, this);
27269 if(typeof this.tooltip == 'object'){
27270 Roo.QuickTips.tips(Roo.apply({
27274 btnEl.dom[this.tooltipType] = this.tooltip;
27277 if(this.arrowTooltip){
27278 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27287 this.el.addClass("x-btn-pressed");
27289 if(Roo.isIE && !Roo.isIE7){
27290 this.autoWidth.defer(1, this);
27295 this.menu.on("show", this.onMenuShow, this);
27296 this.menu.on("hide", this.onMenuHide, this);
27298 this.fireEvent('render', this);
27302 autoWidth : function(){
27304 var tbl = this.el.child("table:first");
27305 var tbl2 = this.el.child("table:last");
27306 this.el.setWidth("auto");
27307 tbl.setWidth("auto");
27308 if(Roo.isIE7 && Roo.isStrict){
27309 var ib = this.el.child('button:first');
27310 if(ib && ib.getWidth() > 20){
27312 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27317 this.el.beginMeasure();
27319 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27320 tbl.setWidth(this.minWidth-tbl2.getWidth());
27323 this.el.endMeasure();
27326 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27330 * Sets this button's click handler
27331 * @param {Function} handler The function to call when the button is clicked
27332 * @param {Object} scope (optional) Scope for the function passed above
27334 setHandler : function(handler, scope){
27335 this.handler = handler;
27336 this.scope = scope;
27340 * Sets this button's arrow click handler
27341 * @param {Function} handler The function to call when the arrow is clicked
27342 * @param {Object} scope (optional) Scope for the function passed above
27344 setArrowHandler : function(handler, scope){
27345 this.arrowHandler = handler;
27346 this.scope = scope;
27352 focus : function(){
27354 this.el.child("button:first").focus();
27359 onClick : function(e){
27360 e.preventDefault();
27361 if(!this.disabled){
27362 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27363 if(this.menu && !this.menu.isVisible()){
27364 this.menu.show(this.el, this.menuAlign);
27366 this.fireEvent("arrowclick", this, e);
27367 if(this.arrowHandler){
27368 this.arrowHandler.call(this.scope || this, this, e);
27371 this.fireEvent("click", this, e);
27373 this.handler.call(this.scope || this, this, e);
27379 onMouseDown : function(e){
27380 if(!this.disabled){
27381 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27385 onMouseUp : function(e){
27386 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27391 // backwards compat
27392 Roo.MenuButton = Roo.SplitButton;/*
27394 * Ext JS Library 1.1.1
27395 * Copyright(c) 2006-2007, Ext JS, LLC.
27397 * Originally Released Under LGPL - original licence link has changed is not relivant.
27400 * <script type="text/javascript">
27404 * @class Roo.Toolbar
27405 * Basic Toolbar class.
27407 * Creates a new Toolbar
27408 * @param {Object} container The config object
27410 Roo.Toolbar = function(container, buttons, config)
27412 /// old consturctor format still supported..
27413 if(container instanceof Array){ // omit the container for later rendering
27414 buttons = container;
27418 if (typeof(container) == 'object' && container.xtype) {
27419 config = container;
27420 container = config.container;
27421 buttons = config.buttons || []; // not really - use items!!
27424 if (config && config.items) {
27425 xitems = config.items;
27426 delete config.items;
27428 Roo.apply(this, config);
27429 this.buttons = buttons;
27432 this.render(container);
27434 this.xitems = xitems;
27435 Roo.each(xitems, function(b) {
27441 Roo.Toolbar.prototype = {
27443 * @cfg {Array} items
27444 * array of button configs or elements to add (will be converted to a MixedCollection)
27448 * @cfg {String/HTMLElement/Element} container
27449 * The id or element that will contain the toolbar
27452 render : function(ct){
27453 this.el = Roo.get(ct);
27455 this.el.addClass(this.cls);
27457 // using a table allows for vertical alignment
27458 // 100% width is needed by Safari...
27459 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27460 this.tr = this.el.child("tr", true);
27462 this.items = new Roo.util.MixedCollection(false, function(o){
27463 return o.id || ("item" + (++autoId));
27466 this.add.apply(this, this.buttons);
27467 delete this.buttons;
27472 * Adds element(s) to the toolbar -- this function takes a variable number of
27473 * arguments of mixed type and adds them to the toolbar.
27474 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27476 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27477 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27478 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27479 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27480 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27481 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27482 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27483 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27484 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27486 * @param {Mixed} arg2
27487 * @param {Mixed} etc.
27490 var a = arguments, l = a.length;
27491 for(var i = 0; i < l; i++){
27496 _add : function(el) {
27499 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27502 if (el.applyTo){ // some kind of form field
27503 return this.addField(el);
27505 if (el.render){ // some kind of Toolbar.Item
27506 return this.addItem(el);
27508 if (typeof el == "string"){ // string
27509 if(el == "separator" || el == "-"){
27510 return this.addSeparator();
27513 return this.addSpacer();
27516 return this.addFill();
27518 return this.addText(el);
27521 if(el.tagName){ // element
27522 return this.addElement(el);
27524 if(typeof el == "object"){ // must be button config?
27525 return this.addButton(el);
27527 // and now what?!?!
27533 * Add an Xtype element
27534 * @param {Object} xtype Xtype Object
27535 * @return {Object} created Object
27537 addxtype : function(e){
27538 return this.add(e);
27542 * Returns the Element for this toolbar.
27543 * @return {Roo.Element}
27545 getEl : function(){
27551 * @return {Roo.Toolbar.Item} The separator item
27553 addSeparator : function(){
27554 return this.addItem(new Roo.Toolbar.Separator());
27558 * Adds a spacer element
27559 * @return {Roo.Toolbar.Spacer} The spacer item
27561 addSpacer : function(){
27562 return this.addItem(new Roo.Toolbar.Spacer());
27566 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27567 * @return {Roo.Toolbar.Fill} The fill item
27569 addFill : function(){
27570 return this.addItem(new Roo.Toolbar.Fill());
27574 * Adds any standard HTML element to the toolbar
27575 * @param {String/HTMLElement/Element} el The element or id of the element to add
27576 * @return {Roo.Toolbar.Item} The element's item
27578 addElement : function(el){
27579 return this.addItem(new Roo.Toolbar.Item(el));
27582 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27583 * @type Roo.util.MixedCollection
27588 * Adds any Toolbar.Item or subclass
27589 * @param {Roo.Toolbar.Item} item
27590 * @return {Roo.Toolbar.Item} The item
27592 addItem : function(item){
27593 var td = this.nextBlock();
27595 this.items.add(item);
27600 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27601 * @param {Object/Array} config A button config or array of configs
27602 * @return {Roo.Toolbar.Button/Array}
27604 addButton : function(config){
27605 if(config instanceof Array){
27607 for(var i = 0, len = config.length; i < len; i++) {
27608 buttons.push(this.addButton(config[i]));
27613 if(!(config instanceof Roo.Toolbar.Button)){
27615 new Roo.Toolbar.SplitButton(config) :
27616 new Roo.Toolbar.Button(config);
27618 var td = this.nextBlock();
27625 * Adds text to the toolbar
27626 * @param {String} text The text to add
27627 * @return {Roo.Toolbar.Item} The element's item
27629 addText : function(text){
27630 return this.addItem(new Roo.Toolbar.TextItem(text));
27634 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27635 * @param {Number} index The index where the item is to be inserted
27636 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27637 * @return {Roo.Toolbar.Button/Item}
27639 insertButton : function(index, item){
27640 if(item instanceof Array){
27642 for(var i = 0, len = item.length; i < len; i++) {
27643 buttons.push(this.insertButton(index + i, item[i]));
27647 if (!(item instanceof Roo.Toolbar.Button)){
27648 item = new Roo.Toolbar.Button(item);
27650 var td = document.createElement("td");
27651 this.tr.insertBefore(td, this.tr.childNodes[index]);
27653 this.items.insert(index, item);
27658 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27659 * @param {Object} config
27660 * @return {Roo.Toolbar.Item} The element's item
27662 addDom : function(config, returnEl){
27663 var td = this.nextBlock();
27664 Roo.DomHelper.overwrite(td, config);
27665 var ti = new Roo.Toolbar.Item(td.firstChild);
27667 this.items.add(ti);
27672 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27673 * @type Roo.util.MixedCollection
27678 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27679 * Note: the field should not have been rendered yet. For a field that has already been
27680 * rendered, use {@link #addElement}.
27681 * @param {Roo.form.Field} field
27682 * @return {Roo.ToolbarItem}
27686 addField : function(field) {
27687 if (!this.fields) {
27689 this.fields = new Roo.util.MixedCollection(false, function(o){
27690 return o.id || ("item" + (++autoId));
27695 var td = this.nextBlock();
27697 var ti = new Roo.Toolbar.Item(td.firstChild);
27699 this.items.add(ti);
27700 this.fields.add(field);
27711 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27712 this.el.child('div').hide();
27720 this.el.child('div').show();
27724 nextBlock : function(){
27725 var td = document.createElement("td");
27726 this.tr.appendChild(td);
27731 destroy : function(){
27732 if(this.items){ // rendered?
27733 Roo.destroy.apply(Roo, this.items.items);
27735 if(this.fields){ // rendered?
27736 Roo.destroy.apply(Roo, this.fields.items);
27738 Roo.Element.uncache(this.el, this.tr);
27743 * @class Roo.Toolbar.Item
27744 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27746 * Creates a new Item
27747 * @param {HTMLElement} el
27749 Roo.Toolbar.Item = function(el){
27750 this.el = Roo.getDom(el);
27751 this.id = Roo.id(this.el);
27752 this.hidden = false;
27755 Roo.Toolbar.Item.prototype = {
27758 * Get this item's HTML Element
27759 * @return {HTMLElement}
27761 getEl : function(){
27766 render : function(td){
27768 td.appendChild(this.el);
27772 * Removes and destroys this item.
27774 destroy : function(){
27775 this.td.parentNode.removeChild(this.td);
27782 this.hidden = false;
27783 this.td.style.display = "";
27790 this.hidden = true;
27791 this.td.style.display = "none";
27795 * Convenience function for boolean show/hide.
27796 * @param {Boolean} visible true to show/false to hide
27798 setVisible: function(visible){
27807 * Try to focus this item.
27809 focus : function(){
27810 Roo.fly(this.el).focus();
27814 * Disables this item.
27816 disable : function(){
27817 Roo.fly(this.td).addClass("x-item-disabled");
27818 this.disabled = true;
27819 this.el.disabled = true;
27823 * Enables this item.
27825 enable : function(){
27826 Roo.fly(this.td).removeClass("x-item-disabled");
27827 this.disabled = false;
27828 this.el.disabled = false;
27834 * @class Roo.Toolbar.Separator
27835 * @extends Roo.Toolbar.Item
27836 * A simple toolbar separator class
27838 * Creates a new Separator
27840 Roo.Toolbar.Separator = function(){
27841 var s = document.createElement("span");
27842 s.className = "ytb-sep";
27843 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27845 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27846 enable:Roo.emptyFn,
27847 disable:Roo.emptyFn,
27852 * @class Roo.Toolbar.Spacer
27853 * @extends Roo.Toolbar.Item
27854 * A simple element that adds extra horizontal space to a toolbar.
27856 * Creates a new Spacer
27858 Roo.Toolbar.Spacer = function(){
27859 var s = document.createElement("div");
27860 s.className = "ytb-spacer";
27861 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27863 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27864 enable:Roo.emptyFn,
27865 disable:Roo.emptyFn,
27870 * @class Roo.Toolbar.Fill
27871 * @extends Roo.Toolbar.Spacer
27872 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27874 * Creates a new Spacer
27876 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27878 render : function(td){
27879 td.style.width = '100%';
27880 Roo.Toolbar.Fill.superclass.render.call(this, td);
27885 * @class Roo.Toolbar.TextItem
27886 * @extends Roo.Toolbar.Item
27887 * A simple class that renders text directly into a toolbar.
27889 * Creates a new TextItem
27890 * @param {String} text
27892 Roo.Toolbar.TextItem = function(text){
27893 if (typeof(text) == 'object') {
27896 var s = document.createElement("span");
27897 s.className = "ytb-text";
27898 s.innerHTML = text;
27899 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27901 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27902 enable:Roo.emptyFn,
27903 disable:Roo.emptyFn,
27908 * @class Roo.Toolbar.Button
27909 * @extends Roo.Button
27910 * A button that renders into a toolbar.
27912 * Creates a new Button
27913 * @param {Object} config A standard {@link Roo.Button} config object
27915 Roo.Toolbar.Button = function(config){
27916 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27918 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27919 render : function(td){
27921 Roo.Toolbar.Button.superclass.render.call(this, td);
27925 * Removes and destroys this button
27927 destroy : function(){
27928 Roo.Toolbar.Button.superclass.destroy.call(this);
27929 this.td.parentNode.removeChild(this.td);
27933 * Shows this button
27936 this.hidden = false;
27937 this.td.style.display = "";
27941 * Hides this button
27944 this.hidden = true;
27945 this.td.style.display = "none";
27949 * Disables this item
27951 disable : function(){
27952 Roo.fly(this.td).addClass("x-item-disabled");
27953 this.disabled = true;
27957 * Enables this item
27959 enable : function(){
27960 Roo.fly(this.td).removeClass("x-item-disabled");
27961 this.disabled = false;
27964 // backwards compat
27965 Roo.ToolbarButton = Roo.Toolbar.Button;
27968 * @class Roo.Toolbar.SplitButton
27969 * @extends Roo.SplitButton
27970 * A menu button that renders into a toolbar.
27972 * Creates a new SplitButton
27973 * @param {Object} config A standard {@link Roo.SplitButton} config object
27975 Roo.Toolbar.SplitButton = function(config){
27976 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27978 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27979 render : function(td){
27981 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27985 * Removes and destroys this button
27987 destroy : function(){
27988 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27989 this.td.parentNode.removeChild(this.td);
27993 * Shows this button
27996 this.hidden = false;
27997 this.td.style.display = "";
28001 * Hides this button
28004 this.hidden = true;
28005 this.td.style.display = "none";
28009 // backwards compat
28010 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28012 * Ext JS Library 1.1.1
28013 * Copyright(c) 2006-2007, Ext JS, LLC.
28015 * Originally Released Under LGPL - original licence link has changed is not relivant.
28018 * <script type="text/javascript">
28022 * @class Roo.PagingToolbar
28023 * @extends Roo.Toolbar
28024 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28026 * Create a new PagingToolbar
28027 * @param {Object} config The config object
28029 Roo.PagingToolbar = function(el, ds, config)
28031 // old args format still supported... - xtype is prefered..
28032 if (typeof(el) == 'object' && el.xtype) {
28033 // created from xtype...
28035 ds = el.dataSource;
28036 el = config.container;
28039 if (config.items) {
28040 items = config.items;
28044 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28047 this.renderButtons(this.el);
28050 // supprot items array.
28052 Roo.each(items, function(e) {
28053 this.add(Roo.factory(e));
28058 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28060 * @cfg {Roo.data.Store} dataSource
28061 * The underlying data store providing the paged data
28064 * @cfg {String/HTMLElement/Element} container
28065 * container The id or element that will contain the toolbar
28068 * @cfg {Boolean} displayInfo
28069 * True to display the displayMsg (defaults to false)
28072 * @cfg {Number} pageSize
28073 * The number of records to display per page (defaults to 20)
28077 * @cfg {String} displayMsg
28078 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28080 displayMsg : 'Displaying {0} - {1} of {2}',
28082 * @cfg {String} emptyMsg
28083 * The message to display when no records are found (defaults to "No data to display")
28085 emptyMsg : 'No data to display',
28087 * Customizable piece of the default paging text (defaults to "Page")
28090 beforePageText : "Page",
28092 * Customizable piece of the default paging text (defaults to "of %0")
28095 afterPageText : "of {0}",
28097 * Customizable piece of the default paging text (defaults to "First Page")
28100 firstText : "First Page",
28102 * Customizable piece of the default paging text (defaults to "Previous Page")
28105 prevText : "Previous Page",
28107 * Customizable piece of the default paging text (defaults to "Next Page")
28110 nextText : "Next Page",
28112 * Customizable piece of the default paging text (defaults to "Last Page")
28115 lastText : "Last Page",
28117 * Customizable piece of the default paging text (defaults to "Refresh")
28120 refreshText : "Refresh",
28123 renderButtons : function(el){
28124 Roo.PagingToolbar.superclass.render.call(this, el);
28125 this.first = this.addButton({
28126 tooltip: this.firstText,
28127 cls: "x-btn-icon x-grid-page-first",
28129 handler: this.onClick.createDelegate(this, ["first"])
28131 this.prev = this.addButton({
28132 tooltip: this.prevText,
28133 cls: "x-btn-icon x-grid-page-prev",
28135 handler: this.onClick.createDelegate(this, ["prev"])
28137 //this.addSeparator();
28138 this.add(this.beforePageText);
28139 this.field = Roo.get(this.addDom({
28144 cls: "x-grid-page-number"
28146 this.field.on("keydown", this.onPagingKeydown, this);
28147 this.field.on("focus", function(){this.dom.select();});
28148 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28149 this.field.setHeight(18);
28150 //this.addSeparator();
28151 this.next = this.addButton({
28152 tooltip: this.nextText,
28153 cls: "x-btn-icon x-grid-page-next",
28155 handler: this.onClick.createDelegate(this, ["next"])
28157 this.last = this.addButton({
28158 tooltip: this.lastText,
28159 cls: "x-btn-icon x-grid-page-last",
28161 handler: this.onClick.createDelegate(this, ["last"])
28163 //this.addSeparator();
28164 this.loading = this.addButton({
28165 tooltip: this.refreshText,
28166 cls: "x-btn-icon x-grid-loading",
28167 handler: this.onClick.createDelegate(this, ["refresh"])
28170 if(this.displayInfo){
28171 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28176 updateInfo : function(){
28177 if(this.displayEl){
28178 var count = this.ds.getCount();
28179 var msg = count == 0 ?
28183 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28185 this.displayEl.update(msg);
28190 onLoad : function(ds, r, o){
28191 this.cursor = o.params ? o.params.start : 0;
28192 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28194 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28195 this.field.dom.value = ap;
28196 this.first.setDisabled(ap == 1);
28197 this.prev.setDisabled(ap == 1);
28198 this.next.setDisabled(ap == ps);
28199 this.last.setDisabled(ap == ps);
28200 this.loading.enable();
28205 getPageData : function(){
28206 var total = this.ds.getTotalCount();
28209 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28210 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28215 onLoadError : function(){
28216 this.loading.enable();
28220 onPagingKeydown : function(e){
28221 var k = e.getKey();
28222 var d = this.getPageData();
28224 var v = this.field.dom.value, pageNum;
28225 if(!v || isNaN(pageNum = parseInt(v, 10))){
28226 this.field.dom.value = d.activePage;
28229 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28230 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28233 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))
28235 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28236 this.field.dom.value = pageNum;
28237 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28240 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28242 var v = this.field.dom.value, pageNum;
28243 var increment = (e.shiftKey) ? 10 : 1;
28244 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28246 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28247 this.field.dom.value = d.activePage;
28250 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28252 this.field.dom.value = parseInt(v, 10) + increment;
28253 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28254 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28261 beforeLoad : function(){
28263 this.loading.disable();
28268 onClick : function(which){
28272 ds.load({params:{start: 0, limit: this.pageSize}});
28275 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28278 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28281 var total = ds.getTotalCount();
28282 var extra = total % this.pageSize;
28283 var lastStart = extra ? (total - extra) : total-this.pageSize;
28284 ds.load({params:{start: lastStart, limit: this.pageSize}});
28287 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28293 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28294 * @param {Roo.data.Store} store The data store to unbind
28296 unbind : function(ds){
28297 ds.un("beforeload", this.beforeLoad, this);
28298 ds.un("load", this.onLoad, this);
28299 ds.un("loadexception", this.onLoadError, this);
28300 ds.un("remove", this.updateInfo, this);
28301 ds.un("add", this.updateInfo, this);
28302 this.ds = undefined;
28306 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28307 * @param {Roo.data.Store} store The data store to bind
28309 bind : function(ds){
28310 ds.on("beforeload", this.beforeLoad, this);
28311 ds.on("load", this.onLoad, this);
28312 ds.on("loadexception", this.onLoadError, this);
28313 ds.on("remove", this.updateInfo, this);
28314 ds.on("add", this.updateInfo, this);
28319 * Ext JS Library 1.1.1
28320 * Copyright(c) 2006-2007, Ext JS, LLC.
28322 * Originally Released Under LGPL - original licence link has changed is not relivant.
28325 * <script type="text/javascript">
28329 * @class Roo.Resizable
28330 * @extends Roo.util.Observable
28331 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28332 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28333 * 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
28334 * the element will be wrapped for you automatically.</p>
28335 * <p>Here is the list of valid resize handles:</p>
28338 ------ -------------------
28347 'hd' horizontal drag
28350 * <p>Here's an example showing the creation of a typical Resizable:</p>
28352 var resizer = new Roo.Resizable("element-id", {
28360 resizer.on("resize", myHandler);
28362 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28363 * resizer.east.setDisplayed(false);</p>
28364 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28365 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28366 * resize operation's new size (defaults to [0, 0])
28367 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28368 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28369 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28370 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28371 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28372 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28373 * @cfg {Number} width The width of the element in pixels (defaults to null)
28374 * @cfg {Number} height The height of the element in pixels (defaults to null)
28375 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28376 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28377 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28378 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28379 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28380 * in favor of the handles config option (defaults to false)
28381 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28382 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28383 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28384 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28385 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28386 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28387 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28388 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28389 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28390 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28391 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28393 * Create a new resizable component
28394 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28395 * @param {Object} config configuration options
28397 Roo.Resizable = function(el, config)
28399 this.el = Roo.get(el);
28401 if(config && config.wrap){
28402 config.resizeChild = this.el;
28403 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28404 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28405 this.el.setStyle("overflow", "hidden");
28406 this.el.setPositioning(config.resizeChild.getPositioning());
28407 config.resizeChild.clearPositioning();
28408 if(!config.width || !config.height){
28409 var csize = config.resizeChild.getSize();
28410 this.el.setSize(csize.width, csize.height);
28412 if(config.pinned && !config.adjustments){
28413 config.adjustments = "auto";
28417 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28418 this.proxy.unselectable();
28419 this.proxy.enableDisplayMode('block');
28421 Roo.apply(this, config);
28424 this.disableTrackOver = true;
28425 this.el.addClass("x-resizable-pinned");
28427 // if the element isn't positioned, make it relative
28428 var position = this.el.getStyle("position");
28429 if(position != "absolute" && position != "fixed"){
28430 this.el.setStyle("position", "relative");
28432 if(!this.handles){ // no handles passed, must be legacy style
28433 this.handles = 's,e,se';
28434 if(this.multiDirectional){
28435 this.handles += ',n,w';
28438 if(this.handles == "all"){
28439 this.handles = "n s e w ne nw se sw";
28441 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28442 var ps = Roo.Resizable.positions;
28443 for(var i = 0, len = hs.length; i < len; i++){
28444 if(hs[i] && ps[hs[i]]){
28445 var pos = ps[hs[i]];
28446 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28450 this.corner = this.southeast;
28452 // updateBox = the box can move..
28453 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28454 this.updateBox = true;
28457 this.activeHandle = null;
28459 if(this.resizeChild){
28460 if(typeof this.resizeChild == "boolean"){
28461 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28463 this.resizeChild = Roo.get(this.resizeChild, true);
28467 if(this.adjustments == "auto"){
28468 var rc = this.resizeChild;
28469 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28470 if(rc && (hw || hn)){
28471 rc.position("relative");
28472 rc.setLeft(hw ? hw.el.getWidth() : 0);
28473 rc.setTop(hn ? hn.el.getHeight() : 0);
28475 this.adjustments = [
28476 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28477 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28481 if(this.draggable){
28482 this.dd = this.dynamic ?
28483 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28484 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28490 * @event beforeresize
28491 * Fired before resize is allowed. Set enabled to false to cancel resize.
28492 * @param {Roo.Resizable} this
28493 * @param {Roo.EventObject} e The mousedown event
28495 "beforeresize" : true,
28498 * Fired after a resize.
28499 * @param {Roo.Resizable} this
28500 * @param {Number} width The new width
28501 * @param {Number} height The new height
28502 * @param {Roo.EventObject} e The mouseup event
28507 if(this.width !== null && this.height !== null){
28508 this.resizeTo(this.width, this.height);
28510 this.updateChildSize();
28513 this.el.dom.style.zoom = 1;
28515 Roo.Resizable.superclass.constructor.call(this);
28518 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28519 resizeChild : false,
28520 adjustments : [0, 0],
28530 multiDirectional : false,
28531 disableTrackOver : false,
28532 easing : 'easeOutStrong',
28533 widthIncrement : 0,
28534 heightIncrement : 0,
28538 preserveRatio : false,
28539 transparent: false,
28545 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28547 constrainTo: undefined,
28549 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28551 resizeRegion: undefined,
28555 * Perform a manual resize
28556 * @param {Number} width
28557 * @param {Number} height
28559 resizeTo : function(width, height){
28560 this.el.setSize(width, height);
28561 this.updateChildSize();
28562 this.fireEvent("resize", this, width, height, null);
28566 startSizing : function(e, handle){
28567 this.fireEvent("beforeresize", this, e);
28568 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28571 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28572 this.overlay.unselectable();
28573 this.overlay.enableDisplayMode("block");
28574 this.overlay.on("mousemove", this.onMouseMove, this);
28575 this.overlay.on("mouseup", this.onMouseUp, this);
28577 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28579 this.resizing = true;
28580 this.startBox = this.el.getBox();
28581 this.startPoint = e.getXY();
28582 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28583 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28585 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28586 this.overlay.show();
28588 if(this.constrainTo) {
28589 var ct = Roo.get(this.constrainTo);
28590 this.resizeRegion = ct.getRegion().adjust(
28591 ct.getFrameWidth('t'),
28592 ct.getFrameWidth('l'),
28593 -ct.getFrameWidth('b'),
28594 -ct.getFrameWidth('r')
28598 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28600 this.proxy.setBox(this.startBox);
28602 this.proxy.setStyle('visibility', 'visible');
28608 onMouseDown : function(handle, e){
28611 this.activeHandle = handle;
28612 this.startSizing(e, handle);
28617 onMouseUp : function(e){
28618 var size = this.resizeElement();
28619 this.resizing = false;
28621 this.overlay.hide();
28623 this.fireEvent("resize", this, size.width, size.height, e);
28627 updateChildSize : function(){
28629 if(this.resizeChild){
28631 var child = this.resizeChild;
28632 var adj = this.adjustments;
28633 if(el.dom.offsetWidth){
28634 var b = el.getSize(true);
28635 child.setSize(b.width+adj[0], b.height+adj[1]);
28637 // Second call here for IE
28638 // The first call enables instant resizing and
28639 // the second call corrects scroll bars if they
28642 setTimeout(function(){
28643 if(el.dom.offsetWidth){
28644 var b = el.getSize(true);
28645 child.setSize(b.width+adj[0], b.height+adj[1]);
28653 snap : function(value, inc, min){
28654 if(!inc || !value) return value;
28655 var newValue = value;
28656 var m = value % inc;
28659 newValue = value + (inc-m);
28661 newValue = value - m;
28664 return Math.max(min, newValue);
28668 resizeElement : function(){
28669 var box = this.proxy.getBox();
28670 if(this.updateBox){
28671 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28673 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28675 this.updateChildSize();
28683 constrain : function(v, diff, m, mx){
28686 }else if(v - diff > mx){
28693 onMouseMove : function(e){
28695 try{// try catch so if something goes wrong the user doesn't get hung
28697 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28701 //var curXY = this.startPoint;
28702 var curSize = this.curSize || this.startBox;
28703 var x = this.startBox.x, y = this.startBox.y;
28704 var ox = x, oy = y;
28705 var w = curSize.width, h = curSize.height;
28706 var ow = w, oh = h;
28707 var mw = this.minWidth, mh = this.minHeight;
28708 var mxw = this.maxWidth, mxh = this.maxHeight;
28709 var wi = this.widthIncrement;
28710 var hi = this.heightIncrement;
28712 var eventXY = e.getXY();
28713 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28714 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28716 var pos = this.activeHandle.position;
28721 w = Math.min(Math.max(mw, w), mxw);
28726 h = Math.min(Math.max(mh, h), mxh);
28731 w = Math.min(Math.max(mw, w), mxw);
28732 h = Math.min(Math.max(mh, h), mxh);
28735 diffY = this.constrain(h, diffY, mh, mxh);
28742 var adiffX = Math.abs(diffX);
28743 var sub = (adiffX % wi); // how much
28744 if (sub > (wi/2)) { // far enough to snap
28745 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28747 // remove difference..
28748 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28752 x = Math.max(this.minX, x);
28755 diffX = this.constrain(w, diffX, mw, mxw);
28761 w = Math.min(Math.max(mw, w), mxw);
28762 diffY = this.constrain(h, diffY, mh, mxh);
28767 diffX = this.constrain(w, diffX, mw, mxw);
28768 diffY = this.constrain(h, diffY, mh, mxh);
28775 diffX = this.constrain(w, diffX, mw, mxw);
28777 h = Math.min(Math.max(mh, h), mxh);
28783 var sw = this.snap(w, wi, mw);
28784 var sh = this.snap(h, hi, mh);
28785 if(sw != w || sh != h){
28808 if(this.preserveRatio){
28813 h = Math.min(Math.max(mh, h), mxh);
28818 w = Math.min(Math.max(mw, w), mxw);
28823 w = Math.min(Math.max(mw, w), mxw);
28829 w = Math.min(Math.max(mw, w), mxw);
28835 h = Math.min(Math.max(mh, h), mxh);
28843 h = Math.min(Math.max(mh, h), mxh);
28853 h = Math.min(Math.max(mh, h), mxh);
28861 if (pos == 'hdrag') {
28864 this.proxy.setBounds(x, y, w, h);
28866 this.resizeElement();
28873 handleOver : function(){
28875 this.el.addClass("x-resizable-over");
28880 handleOut : function(){
28881 if(!this.resizing){
28882 this.el.removeClass("x-resizable-over");
28887 * Returns the element this component is bound to.
28888 * @return {Roo.Element}
28890 getEl : function(){
28895 * Returns the resizeChild element (or null).
28896 * @return {Roo.Element}
28898 getResizeChild : function(){
28899 return this.resizeChild;
28901 groupHandler : function()
28906 * Destroys this resizable. If the element was wrapped and
28907 * removeEl is not true then the element remains.
28908 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28910 destroy : function(removeEl){
28911 this.proxy.remove();
28913 this.overlay.removeAllListeners();
28914 this.overlay.remove();
28916 var ps = Roo.Resizable.positions;
28918 if(typeof ps[k] != "function" && this[ps[k]]){
28919 var h = this[ps[k]];
28920 h.el.removeAllListeners();
28925 this.el.update("");
28932 // hash to map config positions to true positions
28933 Roo.Resizable.positions = {
28934 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28939 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28941 // only initialize the template if resizable is used
28942 var tpl = Roo.DomHelper.createTemplate(
28943 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28946 Roo.Resizable.Handle.prototype.tpl = tpl;
28948 this.position = pos;
28950 // show north drag fro topdra
28951 var handlepos = pos == 'hdrag' ? 'north' : pos;
28953 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28954 if (pos == 'hdrag') {
28955 this.el.setStyle('cursor', 'pointer');
28957 this.el.unselectable();
28959 this.el.setOpacity(0);
28961 this.el.on("mousedown", this.onMouseDown, this);
28962 if(!disableTrackOver){
28963 this.el.on("mouseover", this.onMouseOver, this);
28964 this.el.on("mouseout", this.onMouseOut, this);
28969 Roo.Resizable.Handle.prototype = {
28970 afterResize : function(rz){
28974 onMouseDown : function(e){
28975 this.rz.onMouseDown(this, e);
28978 onMouseOver : function(e){
28979 this.rz.handleOver(this, e);
28982 onMouseOut : function(e){
28983 this.rz.handleOut(this, e);
28987 * Ext JS Library 1.1.1
28988 * Copyright(c) 2006-2007, Ext JS, LLC.
28990 * Originally Released Under LGPL - original licence link has changed is not relivant.
28993 * <script type="text/javascript">
28997 * @class Roo.Editor
28998 * @extends Roo.Component
28999 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29001 * Create a new Editor
29002 * @param {Roo.form.Field} field The Field object (or descendant)
29003 * @param {Object} config The config object
29005 Roo.Editor = function(field, config){
29006 Roo.Editor.superclass.constructor.call(this, config);
29007 this.field = field;
29010 * @event beforestartedit
29011 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29012 * false from the handler of this event.
29013 * @param {Editor} this
29014 * @param {Roo.Element} boundEl The underlying element bound to this editor
29015 * @param {Mixed} value The field value being set
29017 "beforestartedit" : true,
29020 * Fires when this editor is displayed
29021 * @param {Roo.Element} boundEl The underlying element bound to this editor
29022 * @param {Mixed} value The starting field value
29024 "startedit" : true,
29026 * @event beforecomplete
29027 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29028 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29029 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29030 * event will not fire since no edit actually occurred.
29031 * @param {Editor} this
29032 * @param {Mixed} value The current field value
29033 * @param {Mixed} startValue The original field value
29035 "beforecomplete" : true,
29038 * Fires after editing is complete and any changed value has been written to the underlying field.
29039 * @param {Editor} this
29040 * @param {Mixed} value The current field value
29041 * @param {Mixed} startValue The original field value
29045 * @event specialkey
29046 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29047 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29048 * @param {Roo.form.Field} this
29049 * @param {Roo.EventObject} e The event object
29051 "specialkey" : true
29055 Roo.extend(Roo.Editor, Roo.Component, {
29057 * @cfg {Boolean/String} autosize
29058 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29059 * or "height" to adopt the height only (defaults to false)
29062 * @cfg {Boolean} revertInvalid
29063 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29064 * validation fails (defaults to true)
29067 * @cfg {Boolean} ignoreNoChange
29068 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29069 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29070 * will never be ignored.
29073 * @cfg {Boolean} hideEl
29074 * False to keep the bound element visible while the editor is displayed (defaults to true)
29077 * @cfg {Mixed} value
29078 * The data value of the underlying field (defaults to "")
29082 * @cfg {String} alignment
29083 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29087 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29088 * for bottom-right shadow (defaults to "frame")
29092 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29096 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29098 completeOnEnter : false,
29100 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29102 cancelOnEsc : false,
29104 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29109 onRender : function(ct, position){
29110 this.el = new Roo.Layer({
29111 shadow: this.shadow,
29117 constrain: this.constrain
29119 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29120 if(this.field.msgTarget != 'title'){
29121 this.field.msgTarget = 'qtip';
29123 this.field.render(this.el);
29125 this.field.el.dom.setAttribute('autocomplete', 'off');
29127 this.field.on("specialkey", this.onSpecialKey, this);
29128 if(this.swallowKeys){
29129 this.field.el.swallowEvent(['keydown','keypress']);
29132 this.field.on("blur", this.onBlur, this);
29133 if(this.field.grow){
29134 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29138 onSpecialKey : function(field, e)
29140 //Roo.log('editor onSpecialKey');
29141 if(this.completeOnEnter && e.getKey() == e.ENTER){
29143 this.completeEdit();
29146 // do not fire special key otherwise it might hide close the editor...
29147 if(e.getKey() == e.ENTER){
29150 if(this.cancelOnEsc && e.getKey() == e.ESC){
29154 this.fireEvent('specialkey', field, e);
29159 * Starts the editing process and shows the editor.
29160 * @param {String/HTMLElement/Element} el The element to edit
29161 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29162 * to the innerHTML of el.
29164 startEdit : function(el, value){
29166 this.completeEdit();
29168 this.boundEl = Roo.get(el);
29169 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29170 if(!this.rendered){
29171 this.render(this.parentEl || document.body);
29173 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29176 this.startValue = v;
29177 this.field.setValue(v);
29179 var sz = this.boundEl.getSize();
29180 switch(this.autoSize){
29182 this.setSize(sz.width, "");
29185 this.setSize("", sz.height);
29188 this.setSize(sz.width, sz.height);
29191 this.el.alignTo(this.boundEl, this.alignment);
29192 this.editing = true;
29194 Roo.QuickTips.disable();
29200 * Sets the height and width of this editor.
29201 * @param {Number} width The new width
29202 * @param {Number} height The new height
29204 setSize : function(w, h){
29205 this.field.setSize(w, h);
29212 * Realigns the editor to the bound field based on the current alignment config value.
29214 realign : function(){
29215 this.el.alignTo(this.boundEl, this.alignment);
29219 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29220 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29222 completeEdit : function(remainVisible){
29226 var v = this.getValue();
29227 if(this.revertInvalid !== false && !this.field.isValid()){
29228 v = this.startValue;
29229 this.cancelEdit(true);
29231 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29232 this.editing = false;
29236 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29237 this.editing = false;
29238 if(this.updateEl && this.boundEl){
29239 this.boundEl.update(v);
29241 if(remainVisible !== true){
29244 this.fireEvent("complete", this, v, this.startValue);
29249 onShow : function(){
29251 if(this.hideEl !== false){
29252 this.boundEl.hide();
29255 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29256 this.fixIEFocus = true;
29257 this.deferredFocus.defer(50, this);
29259 this.field.focus();
29261 this.fireEvent("startedit", this.boundEl, this.startValue);
29264 deferredFocus : function(){
29266 this.field.focus();
29271 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29272 * reverted to the original starting value.
29273 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29274 * cancel (defaults to false)
29276 cancelEdit : function(remainVisible){
29278 this.setValue(this.startValue);
29279 if(remainVisible !== true){
29286 onBlur : function(){
29287 if(this.allowBlur !== true && this.editing){
29288 this.completeEdit();
29293 onHide : function(){
29295 this.completeEdit();
29299 if(this.field.collapse){
29300 this.field.collapse();
29303 if(this.hideEl !== false){
29304 this.boundEl.show();
29307 Roo.QuickTips.enable();
29312 * Sets the data value of the editor
29313 * @param {Mixed} value Any valid value supported by the underlying field
29315 setValue : function(v){
29316 this.field.setValue(v);
29320 * Gets the data value of the editor
29321 * @return {Mixed} The data value
29323 getValue : function(){
29324 return this.field.getValue();
29328 * Ext JS Library 1.1.1
29329 * Copyright(c) 2006-2007, Ext JS, LLC.
29331 * Originally Released Under LGPL - original licence link has changed is not relivant.
29334 * <script type="text/javascript">
29338 * @class Roo.BasicDialog
29339 * @extends Roo.util.Observable
29340 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29342 var dlg = new Roo.BasicDialog("my-dlg", {
29351 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29352 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29353 dlg.addButton('Cancel', dlg.hide, dlg);
29356 <b>A Dialog should always be a direct child of the body element.</b>
29357 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29358 * @cfg {String} title Default text to display in the title bar (defaults to null)
29359 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29360 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29361 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29362 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29363 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29364 * (defaults to null with no animation)
29365 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29366 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29367 * property for valid values (defaults to 'all')
29368 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29369 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29370 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29371 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29372 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29373 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29374 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29375 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29376 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29377 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29378 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29379 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29380 * draggable = true (defaults to false)
29381 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29382 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29383 * shadow (defaults to false)
29384 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29385 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29386 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29387 * @cfg {Array} buttons Array of buttons
29388 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29390 * Create a new BasicDialog.
29391 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29392 * @param {Object} config Configuration options
29394 Roo.BasicDialog = function(el, config){
29395 this.el = Roo.get(el);
29396 var dh = Roo.DomHelper;
29397 if(!this.el && config && config.autoCreate){
29398 if(typeof config.autoCreate == "object"){
29399 if(!config.autoCreate.id){
29400 config.autoCreate.id = el;
29402 this.el = dh.append(document.body,
29403 config.autoCreate, true);
29405 this.el = dh.append(document.body,
29406 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29410 el.setDisplayed(true);
29411 el.hide = this.hideAction;
29413 el.addClass("x-dlg");
29415 Roo.apply(this, config);
29417 this.proxy = el.createProxy("x-dlg-proxy");
29418 this.proxy.hide = this.hideAction;
29419 this.proxy.setOpacity(.5);
29423 el.setWidth(config.width);
29426 el.setHeight(config.height);
29428 this.size = el.getSize();
29429 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29430 this.xy = [config.x,config.y];
29432 this.xy = el.getCenterXY(true);
29434 /** The header element @type Roo.Element */
29435 this.header = el.child("> .x-dlg-hd");
29436 /** The body element @type Roo.Element */
29437 this.body = el.child("> .x-dlg-bd");
29438 /** The footer element @type Roo.Element */
29439 this.footer = el.child("> .x-dlg-ft");
29442 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29445 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29448 this.header.unselectable();
29450 this.header.update(this.title);
29452 // this element allows the dialog to be focused for keyboard event
29453 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29454 this.focusEl.swallowEvent("click", true);
29456 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29458 // wrap the body and footer for special rendering
29459 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29461 this.bwrap.dom.appendChild(this.footer.dom);
29464 this.bg = this.el.createChild({
29465 tag: "div", cls:"x-dlg-bg",
29466 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29468 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29471 if(this.autoScroll !== false && !this.autoTabs){
29472 this.body.setStyle("overflow", "auto");
29475 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29477 if(this.closable !== false){
29478 this.el.addClass("x-dlg-closable");
29479 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29480 this.close.on("click", this.closeClick, this);
29481 this.close.addClassOnOver("x-dlg-close-over");
29483 if(this.collapsible !== false){
29484 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29485 this.collapseBtn.on("click", this.collapseClick, this);
29486 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29487 this.header.on("dblclick", this.collapseClick, this);
29489 if(this.resizable !== false){
29490 this.el.addClass("x-dlg-resizable");
29491 this.resizer = new Roo.Resizable(el, {
29492 minWidth: this.minWidth || 80,
29493 minHeight:this.minHeight || 80,
29494 handles: this.resizeHandles || "all",
29497 this.resizer.on("beforeresize", this.beforeResize, this);
29498 this.resizer.on("resize", this.onResize, this);
29500 if(this.draggable !== false){
29501 el.addClass("x-dlg-draggable");
29502 if (!this.proxyDrag) {
29503 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29506 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29508 dd.setHandleElId(this.header.id);
29509 dd.endDrag = this.endMove.createDelegate(this);
29510 dd.startDrag = this.startMove.createDelegate(this);
29511 dd.onDrag = this.onDrag.createDelegate(this);
29516 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29517 this.mask.enableDisplayMode("block");
29519 this.el.addClass("x-dlg-modal");
29522 this.shadow = new Roo.Shadow({
29523 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29524 offset : this.shadowOffset
29527 this.shadowOffset = 0;
29529 if(Roo.useShims && this.shim !== false){
29530 this.shim = this.el.createShim();
29531 this.shim.hide = this.hideAction;
29539 if (this.buttons) {
29540 var bts= this.buttons;
29542 Roo.each(bts, function(b) {
29551 * Fires when a key is pressed
29552 * @param {Roo.BasicDialog} this
29553 * @param {Roo.EventObject} e
29558 * Fires when this dialog is moved by the user.
29559 * @param {Roo.BasicDialog} this
29560 * @param {Number} x The new page X
29561 * @param {Number} y The new page Y
29566 * Fires when this dialog is resized by the user.
29567 * @param {Roo.BasicDialog} this
29568 * @param {Number} width The new width
29569 * @param {Number} height The new height
29573 * @event beforehide
29574 * Fires before this dialog is hidden.
29575 * @param {Roo.BasicDialog} this
29577 "beforehide" : true,
29580 * Fires when this dialog is hidden.
29581 * @param {Roo.BasicDialog} this
29585 * @event beforeshow
29586 * Fires before this dialog is shown.
29587 * @param {Roo.BasicDialog} this
29589 "beforeshow" : true,
29592 * Fires when this dialog is shown.
29593 * @param {Roo.BasicDialog} this
29597 el.on("keydown", this.onKeyDown, this);
29598 el.on("mousedown", this.toFront, this);
29599 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29601 Roo.DialogManager.register(this);
29602 Roo.BasicDialog.superclass.constructor.call(this);
29605 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29606 shadowOffset: Roo.isIE ? 6 : 5,
29609 minButtonWidth: 75,
29610 defaultButton: null,
29611 buttonAlign: "right",
29616 * Sets the dialog title text
29617 * @param {String} text The title text to display
29618 * @return {Roo.BasicDialog} this
29620 setTitle : function(text){
29621 this.header.update(text);
29626 closeClick : function(){
29631 collapseClick : function(){
29632 this[this.collapsed ? "expand" : "collapse"]();
29636 * Collapses the dialog to its minimized state (only the title bar is visible).
29637 * Equivalent to the user clicking the collapse dialog button.
29639 collapse : function(){
29640 if(!this.collapsed){
29641 this.collapsed = true;
29642 this.el.addClass("x-dlg-collapsed");
29643 this.restoreHeight = this.el.getHeight();
29644 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29649 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29650 * clicking the expand dialog button.
29652 expand : function(){
29653 if(this.collapsed){
29654 this.collapsed = false;
29655 this.el.removeClass("x-dlg-collapsed");
29656 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29661 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29662 * @return {Roo.TabPanel} The tabs component
29664 initTabs : function(){
29665 var tabs = this.getTabs();
29666 while(tabs.getTab(0)){
29669 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29671 tabs.addTab(Roo.id(dom), dom.title);
29679 beforeResize : function(){
29680 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29684 onResize : function(){
29685 this.refreshSize();
29686 this.syncBodyHeight();
29687 this.adjustAssets();
29689 this.fireEvent("resize", this, this.size.width, this.size.height);
29693 onKeyDown : function(e){
29694 if(this.isVisible()){
29695 this.fireEvent("keydown", this, e);
29700 * Resizes the dialog.
29701 * @param {Number} width
29702 * @param {Number} height
29703 * @return {Roo.BasicDialog} this
29705 resizeTo : function(width, height){
29706 this.el.setSize(width, height);
29707 this.size = {width: width, height: height};
29708 this.syncBodyHeight();
29709 if(this.fixedcenter){
29712 if(this.isVisible()){
29713 this.constrainXY();
29714 this.adjustAssets();
29716 this.fireEvent("resize", this, width, height);
29722 * Resizes the dialog to fit the specified content size.
29723 * @param {Number} width
29724 * @param {Number} height
29725 * @return {Roo.BasicDialog} this
29727 setContentSize : function(w, h){
29728 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29729 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29730 //if(!this.el.isBorderBox()){
29731 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29732 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29735 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29736 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29738 this.resizeTo(w, h);
29743 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29744 * executed in response to a particular key being pressed while the dialog is active.
29745 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29746 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29747 * @param {Function} fn The function to call
29748 * @param {Object} scope (optional) The scope of the function
29749 * @return {Roo.BasicDialog} this
29751 addKeyListener : function(key, fn, scope){
29752 var keyCode, shift, ctrl, alt;
29753 if(typeof key == "object" && !(key instanceof Array)){
29754 keyCode = key["key"];
29755 shift = key["shift"];
29756 ctrl = key["ctrl"];
29761 var handler = function(dlg, e){
29762 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29763 var k = e.getKey();
29764 if(keyCode instanceof Array){
29765 for(var i = 0, len = keyCode.length; i < len; i++){
29766 if(keyCode[i] == k){
29767 fn.call(scope || window, dlg, k, e);
29773 fn.call(scope || window, dlg, k, e);
29778 this.on("keydown", handler);
29783 * Returns the TabPanel component (creates it if it doesn't exist).
29784 * Note: If you wish to simply check for the existence of tabs without creating them,
29785 * check for a null 'tabs' property.
29786 * @return {Roo.TabPanel} The tabs component
29788 getTabs : function(){
29790 this.el.addClass("x-dlg-auto-tabs");
29791 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29792 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29798 * Adds a button to the footer section of the dialog.
29799 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29800 * object or a valid Roo.DomHelper element config
29801 * @param {Function} handler The function called when the button is clicked
29802 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29803 * @return {Roo.Button} The new button
29805 addButton : function(config, handler, scope){
29806 var dh = Roo.DomHelper;
29808 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29810 if(!this.btnContainer){
29811 var tb = this.footer.createChild({
29813 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29814 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29816 this.btnContainer = tb.firstChild.firstChild.firstChild;
29821 minWidth: this.minButtonWidth,
29824 if(typeof config == "string"){
29825 bconfig.text = config;
29828 bconfig.dhconfig = config;
29830 Roo.apply(bconfig, config);
29834 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29835 bconfig.position = Math.max(0, bconfig.position);
29836 fc = this.btnContainer.childNodes[bconfig.position];
29839 var btn = new Roo.Button(
29841 this.btnContainer.insertBefore(document.createElement("td"),fc)
29842 : this.btnContainer.appendChild(document.createElement("td")),
29843 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29846 this.syncBodyHeight();
29849 * Array of all the buttons that have been added to this dialog via addButton
29854 this.buttons.push(btn);
29859 * Sets the default button to be focused when the dialog is displayed.
29860 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29861 * @return {Roo.BasicDialog} this
29863 setDefaultButton : function(btn){
29864 this.defaultButton = btn;
29869 getHeaderFooterHeight : function(safe){
29872 height += this.header.getHeight();
29875 var fm = this.footer.getMargins();
29876 height += (this.footer.getHeight()+fm.top+fm.bottom);
29878 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29879 height += this.centerBg.getPadding("tb");
29884 syncBodyHeight : function()
29886 var bd = this.body, // the text
29887 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
29889 var height = this.size.height - this.getHeaderFooterHeight(false);
29890 bd.setHeight(height-bd.getMargins("tb"));
29891 var hh = this.header.getHeight();
29892 var h = this.size.height-hh;
29895 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29896 bw.setHeight(h-cb.getPadding("tb"));
29898 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29899 bd.setWidth(bw.getWidth(true));
29901 this.tabs.syncHeight();
29903 this.tabs.el.repaint();
29909 * Restores the previous state of the dialog if Roo.state is configured.
29910 * @return {Roo.BasicDialog} this
29912 restoreState : function(){
29913 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29914 if(box && box.width){
29915 this.xy = [box.x, box.y];
29916 this.resizeTo(box.width, box.height);
29922 beforeShow : function(){
29924 if(this.fixedcenter){
29925 this.xy = this.el.getCenterXY(true);
29928 Roo.get(document.body).addClass("x-body-masked");
29929 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29932 this.constrainXY();
29936 animShow : function(){
29937 var b = Roo.get(this.animateTarget).getBox();
29938 this.proxy.setSize(b.width, b.height);
29939 this.proxy.setLocation(b.x, b.y);
29941 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29942 true, .35, this.showEl.createDelegate(this));
29946 * Shows the dialog.
29947 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29948 * @return {Roo.BasicDialog} this
29950 show : function(animateTarget){
29951 if (this.fireEvent("beforeshow", this) === false){
29954 if(this.syncHeightBeforeShow){
29955 this.syncBodyHeight();
29956 }else if(this.firstShow){
29957 this.firstShow = false;
29958 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29960 this.animateTarget = animateTarget || this.animateTarget;
29961 if(!this.el.isVisible()){
29963 if(this.animateTarget && Roo.get(this.animateTarget)){
29973 showEl : function(){
29975 this.el.setXY(this.xy);
29977 this.adjustAssets(true);
29980 // IE peekaboo bug - fix found by Dave Fenwick
29984 this.fireEvent("show", this);
29988 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29989 * dialog itself will receive focus.
29991 focus : function(){
29992 if(this.defaultButton){
29993 this.defaultButton.focus();
29995 this.focusEl.focus();
30000 constrainXY : function(){
30001 if(this.constraintoviewport !== false){
30002 if(!this.viewSize){
30003 if(this.container){
30004 var s = this.container.getSize();
30005 this.viewSize = [s.width, s.height];
30007 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30010 var s = Roo.get(this.container||document).getScroll();
30012 var x = this.xy[0], y = this.xy[1];
30013 var w = this.size.width, h = this.size.height;
30014 var vw = this.viewSize[0], vh = this.viewSize[1];
30015 // only move it if it needs it
30017 // first validate right/bottom
30018 if(x + w > vw+s.left){
30022 if(y + h > vh+s.top){
30026 // then make sure top/left isn't negative
30038 if(this.isVisible()){
30039 this.el.setLocation(x, y);
30040 this.adjustAssets();
30047 onDrag : function(){
30048 if(!this.proxyDrag){
30049 this.xy = this.el.getXY();
30050 this.adjustAssets();
30055 adjustAssets : function(doShow){
30056 var x = this.xy[0], y = this.xy[1];
30057 var w = this.size.width, h = this.size.height;
30058 if(doShow === true){
30060 this.shadow.show(this.el);
30066 if(this.shadow && this.shadow.isVisible()){
30067 this.shadow.show(this.el);
30069 if(this.shim && this.shim.isVisible()){
30070 this.shim.setBounds(x, y, w, h);
30075 adjustViewport : function(w, h){
30077 w = Roo.lib.Dom.getViewWidth();
30078 h = Roo.lib.Dom.getViewHeight();
30081 this.viewSize = [w, h];
30082 if(this.modal && this.mask.isVisible()){
30083 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30084 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30086 if(this.isVisible()){
30087 this.constrainXY();
30092 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30093 * shadow, proxy, mask, etc.) Also removes all event listeners.
30094 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30096 destroy : function(removeEl){
30097 if(this.isVisible()){
30098 this.animateTarget = null;
30101 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30103 this.tabs.destroy(removeEl);
30116 for(var i = 0, len = this.buttons.length; i < len; i++){
30117 this.buttons[i].destroy();
30120 this.el.removeAllListeners();
30121 if(removeEl === true){
30122 this.el.update("");
30125 Roo.DialogManager.unregister(this);
30129 startMove : function(){
30130 if(this.proxyDrag){
30133 if(this.constraintoviewport !== false){
30134 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30139 endMove : function(){
30140 if(!this.proxyDrag){
30141 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30143 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30146 this.refreshSize();
30147 this.adjustAssets();
30149 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30153 * Brings this dialog to the front of any other visible dialogs
30154 * @return {Roo.BasicDialog} this
30156 toFront : function(){
30157 Roo.DialogManager.bringToFront(this);
30162 * Sends this dialog to the back (under) of any other visible dialogs
30163 * @return {Roo.BasicDialog} this
30165 toBack : function(){
30166 Roo.DialogManager.sendToBack(this);
30171 * Centers this dialog in the viewport
30172 * @return {Roo.BasicDialog} this
30174 center : function(){
30175 var xy = this.el.getCenterXY(true);
30176 this.moveTo(xy[0], xy[1]);
30181 * Moves the dialog's top-left corner to the specified point
30182 * @param {Number} x
30183 * @param {Number} y
30184 * @return {Roo.BasicDialog} this
30186 moveTo : function(x, y){
30188 if(this.isVisible()){
30189 this.el.setXY(this.xy);
30190 this.adjustAssets();
30196 * Aligns the dialog to the specified element
30197 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30198 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30199 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30200 * @return {Roo.BasicDialog} this
30202 alignTo : function(element, position, offsets){
30203 this.xy = this.el.getAlignToXY(element, position, offsets);
30204 if(this.isVisible()){
30205 this.el.setXY(this.xy);
30206 this.adjustAssets();
30212 * Anchors an element to another element and realigns it when the window is resized.
30213 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30214 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30215 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30216 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30217 * is a number, it is used as the buffer delay (defaults to 50ms).
30218 * @return {Roo.BasicDialog} this
30220 anchorTo : function(el, alignment, offsets, monitorScroll){
30221 var action = function(){
30222 this.alignTo(el, alignment, offsets);
30224 Roo.EventManager.onWindowResize(action, this);
30225 var tm = typeof monitorScroll;
30226 if(tm != 'undefined'){
30227 Roo.EventManager.on(window, 'scroll', action, this,
30228 {buffer: tm == 'number' ? monitorScroll : 50});
30235 * Returns true if the dialog is visible
30236 * @return {Boolean}
30238 isVisible : function(){
30239 return this.el.isVisible();
30243 animHide : function(callback){
30244 var b = Roo.get(this.animateTarget).getBox();
30246 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30248 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30249 this.hideEl.createDelegate(this, [callback]));
30253 * Hides the dialog.
30254 * @param {Function} callback (optional) Function to call when the dialog is hidden
30255 * @return {Roo.BasicDialog} this
30257 hide : function(callback){
30258 if (this.fireEvent("beforehide", this) === false){
30262 this.shadow.hide();
30267 // sometimes animateTarget seems to get set.. causing problems...
30268 // this just double checks..
30269 if(this.animateTarget && Roo.get(this.animateTarget)) {
30270 this.animHide(callback);
30273 this.hideEl(callback);
30279 hideEl : function(callback){
30283 Roo.get(document.body).removeClass("x-body-masked");
30285 this.fireEvent("hide", this);
30286 if(typeof callback == "function"){
30292 hideAction : function(){
30293 this.setLeft("-10000px");
30294 this.setTop("-10000px");
30295 this.setStyle("visibility", "hidden");
30299 refreshSize : function(){
30300 this.size = this.el.getSize();
30301 this.xy = this.el.getXY();
30302 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30306 // z-index is managed by the DialogManager and may be overwritten at any time
30307 setZIndex : function(index){
30309 this.mask.setStyle("z-index", index);
30312 this.shim.setStyle("z-index", ++index);
30315 this.shadow.setZIndex(++index);
30317 this.el.setStyle("z-index", ++index);
30319 this.proxy.setStyle("z-index", ++index);
30322 this.resizer.proxy.setStyle("z-index", ++index);
30325 this.lastZIndex = index;
30329 * Returns the element for this dialog
30330 * @return {Roo.Element} The underlying dialog Element
30332 getEl : function(){
30338 * @class Roo.DialogManager
30339 * Provides global access to BasicDialogs that have been created and
30340 * support for z-indexing (layering) multiple open dialogs.
30342 Roo.DialogManager = function(){
30344 var accessList = [];
30348 var sortDialogs = function(d1, d2){
30349 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30353 var orderDialogs = function(){
30354 accessList.sort(sortDialogs);
30355 var seed = Roo.DialogManager.zseed;
30356 for(var i = 0, len = accessList.length; i < len; i++){
30357 var dlg = accessList[i];
30359 dlg.setZIndex(seed + (i*10));
30366 * The starting z-index for BasicDialogs (defaults to 9000)
30367 * @type Number The z-index value
30372 register : function(dlg){
30373 list[dlg.id] = dlg;
30374 accessList.push(dlg);
30378 unregister : function(dlg){
30379 delete list[dlg.id];
30382 if(!accessList.indexOf){
30383 for( i = 0, len = accessList.length; i < len; i++){
30384 if(accessList[i] == dlg){
30385 accessList.splice(i, 1);
30390 i = accessList.indexOf(dlg);
30392 accessList.splice(i, 1);
30398 * Gets a registered dialog by id
30399 * @param {String/Object} id The id of the dialog or a dialog
30400 * @return {Roo.BasicDialog} this
30402 get : function(id){
30403 return typeof id == "object" ? id : list[id];
30407 * Brings the specified dialog to the front
30408 * @param {String/Object} dlg The id of the dialog or a dialog
30409 * @return {Roo.BasicDialog} this
30411 bringToFront : function(dlg){
30412 dlg = this.get(dlg);
30415 dlg._lastAccess = new Date().getTime();
30422 * Sends the specified dialog to the back
30423 * @param {String/Object} dlg The id of the dialog or a dialog
30424 * @return {Roo.BasicDialog} this
30426 sendToBack : function(dlg){
30427 dlg = this.get(dlg);
30428 dlg._lastAccess = -(new Date().getTime());
30434 * Hides all dialogs
30436 hideAll : function(){
30437 for(var id in list){
30438 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30447 * @class Roo.LayoutDialog
30448 * @extends Roo.BasicDialog
30449 * Dialog which provides adjustments for working with a layout in a Dialog.
30450 * Add your necessary layout config options to the dialog's config.<br>
30451 * Example usage (including a nested layout):
30454 dialog = new Roo.LayoutDialog("download-dlg", {
30463 // layout config merges with the dialog config
30465 tabPosition: "top",
30466 alwaysShowTabs: true
30469 dialog.addKeyListener(27, dialog.hide, dialog);
30470 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30471 dialog.addButton("Build It!", this.getDownload, this);
30473 // we can even add nested layouts
30474 var innerLayout = new Roo.BorderLayout("dl-inner", {
30484 innerLayout.beginUpdate();
30485 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30486 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30487 innerLayout.endUpdate(true);
30489 var layout = dialog.getLayout();
30490 layout.beginUpdate();
30491 layout.add("center", new Roo.ContentPanel("standard-panel",
30492 {title: "Download the Source", fitToFrame:true}));
30493 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30494 {title: "Build your own roo.js"}));
30495 layout.getRegion("center").showPanel(sp);
30496 layout.endUpdate();
30500 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30501 * @param {Object} config configuration options
30503 Roo.LayoutDialog = function(el, cfg){
30506 if (typeof(cfg) == 'undefined') {
30507 config = Roo.apply({}, el);
30508 // not sure why we use documentElement here.. - it should always be body.
30509 // IE7 borks horribly if we use documentElement.
30510 // webkit also does not like documentElement - it creates a body element...
30511 el = Roo.get( document.body || document.documentElement ).createChild();
30512 //config.autoCreate = true;
30516 config.autoTabs = false;
30517 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30518 this.body.setStyle({overflow:"hidden", position:"relative"});
30519 this.layout = new Roo.BorderLayout(this.body.dom, config);
30520 this.layout.monitorWindowResize = false;
30521 this.el.addClass("x-dlg-auto-layout");
30522 // fix case when center region overwrites center function
30523 this.center = Roo.BasicDialog.prototype.center;
30524 this.on("show", this.layout.layout, this.layout, true);
30525 if (config.items) {
30526 var xitems = config.items;
30527 delete config.items;
30528 Roo.each(xitems, this.addxtype, this);
30533 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30535 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30538 endUpdate : function(){
30539 this.layout.endUpdate();
30543 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30546 beginUpdate : function(){
30547 this.layout.beginUpdate();
30551 * Get the BorderLayout for this dialog
30552 * @return {Roo.BorderLayout}
30554 getLayout : function(){
30555 return this.layout;
30558 showEl : function(){
30559 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30561 this.layout.layout();
30566 // Use the syncHeightBeforeShow config option to control this automatically
30567 syncBodyHeight : function(){
30568 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30569 if(this.layout){this.layout.layout();}
30573 * Add an xtype element (actually adds to the layout.)
30574 * @return {Object} xdata xtype object data.
30577 addxtype : function(c) {
30578 return this.layout.addxtype(c);
30582 * Ext JS Library 1.1.1
30583 * Copyright(c) 2006-2007, Ext JS, LLC.
30585 * Originally Released Under LGPL - original licence link has changed is not relivant.
30588 * <script type="text/javascript">
30592 * @class Roo.MessageBox
30593 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30597 Roo.Msg.alert('Status', 'Changes saved successfully.');
30599 // Prompt for user data:
30600 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30602 // process text value...
30606 // Show a dialog using config options:
30608 title:'Save Changes?',
30609 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30610 buttons: Roo.Msg.YESNOCANCEL,
30617 Roo.MessageBox = function(){
30618 var dlg, opt, mask, waitTimer;
30619 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30620 var buttons, activeTextEl, bwidth;
30623 var handleButton = function(button){
30625 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30629 var handleHide = function(){
30630 if(opt && opt.cls){
30631 dlg.el.removeClass(opt.cls);
30634 Roo.TaskMgr.stop(waitTimer);
30640 var updateButtons = function(b){
30643 buttons["ok"].hide();
30644 buttons["cancel"].hide();
30645 buttons["yes"].hide();
30646 buttons["no"].hide();
30647 dlg.footer.dom.style.display = 'none';
30650 dlg.footer.dom.style.display = '';
30651 for(var k in buttons){
30652 if(typeof buttons[k] != "function"){
30655 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30656 width += buttons[k].el.getWidth()+15;
30666 var handleEsc = function(d, k, e){
30667 if(opt && opt.closable !== false){
30677 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30678 * @return {Roo.BasicDialog} The BasicDialog element
30680 getDialog : function(){
30682 dlg = new Roo.BasicDialog("x-msg-box", {
30687 constraintoviewport:false,
30689 collapsible : false,
30692 width:400, height:100,
30693 buttonAlign:"center",
30694 closeClick : function(){
30695 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30696 handleButton("no");
30698 handleButton("cancel");
30702 dlg.on("hide", handleHide);
30704 dlg.addKeyListener(27, handleEsc);
30706 var bt = this.buttonText;
30707 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30708 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30709 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30710 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30711 bodyEl = dlg.body.createChild({
30713 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>'
30715 msgEl = bodyEl.dom.firstChild;
30716 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30717 textboxEl.enableDisplayMode();
30718 textboxEl.addKeyListener([10,13], function(){
30719 if(dlg.isVisible() && opt && opt.buttons){
30720 if(opt.buttons.ok){
30721 handleButton("ok");
30722 }else if(opt.buttons.yes){
30723 handleButton("yes");
30727 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30728 textareaEl.enableDisplayMode();
30729 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30730 progressEl.enableDisplayMode();
30731 var pf = progressEl.dom.firstChild;
30733 pp = Roo.get(pf.firstChild);
30734 pp.setHeight(pf.offsetHeight);
30742 * Updates the message box body text
30743 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30744 * the XHTML-compliant non-breaking space character '&#160;')
30745 * @return {Roo.MessageBox} This message box
30747 updateText : function(text){
30748 if(!dlg.isVisible() && !opt.width){
30749 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30751 msgEl.innerHTML = text || ' ';
30753 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30754 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30756 Math.min(opt.width || cw , this.maxWidth),
30757 Math.max(opt.minWidth || this.minWidth, bwidth)
30760 activeTextEl.setWidth(w);
30762 if(dlg.isVisible()){
30763 dlg.fixedcenter = false;
30765 // to big, make it scroll. = But as usual stupid IE does not support
30768 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30769 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30770 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30772 bodyEl.dom.style.height = '';
30773 bodyEl.dom.style.overflowY = '';
30776 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30778 bodyEl.dom.style.overflowX = '';
30781 dlg.setContentSize(w, bodyEl.getHeight());
30782 if(dlg.isVisible()){
30783 dlg.fixedcenter = true;
30789 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30790 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30791 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30792 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30793 * @return {Roo.MessageBox} This message box
30795 updateProgress : function(value, text){
30797 this.updateText(text);
30799 if (pp) { // weird bug on my firefox - for some reason this is not defined
30800 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30806 * Returns true if the message box is currently displayed
30807 * @return {Boolean} True if the message box is visible, else false
30809 isVisible : function(){
30810 return dlg && dlg.isVisible();
30814 * Hides the message box if it is displayed
30817 if(this.isVisible()){
30823 * Displays a new message box, or reinitializes an existing message box, based on the config options
30824 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30825 * The following config object properties are supported:
30827 Property Type Description
30828 ---------- --------------- ------------------------------------------------------------------------------------
30829 animEl String/Element An id or Element from which the message box should animate as it opens and
30830 closes (defaults to undefined)
30831 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30832 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30833 closable Boolean False to hide the top-right close button (defaults to true). Note that
30834 progress and wait dialogs will ignore this property and always hide the
30835 close button as they can only be closed programmatically.
30836 cls String A custom CSS class to apply to the message box element
30837 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30838 displayed (defaults to 75)
30839 fn Function A callback function to execute after closing the dialog. The arguments to the
30840 function will be btn (the name of the button that was clicked, if applicable,
30841 e.g. "ok"), and text (the value of the active text field, if applicable).
30842 Progress and wait dialogs will ignore this option since they do not respond to
30843 user actions and can only be closed programmatically, so any required function
30844 should be called by the same code after it closes the dialog.
30845 icon String A CSS class that provides a background image to be used as an icon for
30846 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30847 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30848 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30849 modal Boolean False to allow user interaction with the page while the message box is
30850 displayed (defaults to true)
30851 msg String A string that will replace the existing message box body text (defaults
30852 to the XHTML-compliant non-breaking space character ' ')
30853 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30854 progress Boolean True to display a progress bar (defaults to false)
30855 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30856 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30857 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30858 title String The title text
30859 value String The string value to set into the active textbox element if displayed
30860 wait Boolean True to display a progress bar (defaults to false)
30861 width Number The width of the dialog in pixels
30868 msg: 'Please enter your address:',
30870 buttons: Roo.MessageBox.OKCANCEL,
30873 animEl: 'addAddressBtn'
30876 * @param {Object} config Configuration options
30877 * @return {Roo.MessageBox} This message box
30879 show : function(options)
30882 // this causes nightmares if you show one dialog after another
30883 // especially on callbacks..
30885 if(this.isVisible()){
30888 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30889 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30890 Roo.log("New Dialog Message:" + options.msg )
30891 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30892 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30895 var d = this.getDialog();
30897 d.setTitle(opt.title || " ");
30898 d.close.setDisplayed(opt.closable !== false);
30899 activeTextEl = textboxEl;
30900 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30905 textareaEl.setHeight(typeof opt.multiline == "number" ?
30906 opt.multiline : this.defaultTextHeight);
30907 activeTextEl = textareaEl;
30916 progressEl.setDisplayed(opt.progress === true);
30917 this.updateProgress(0);
30918 activeTextEl.dom.value = opt.value || "";
30920 dlg.setDefaultButton(activeTextEl);
30922 var bs = opt.buttons;
30925 db = buttons["ok"];
30926 }else if(bs && bs.yes){
30927 db = buttons["yes"];
30929 dlg.setDefaultButton(db);
30931 bwidth = updateButtons(opt.buttons);
30932 this.updateText(opt.msg);
30934 d.el.addClass(opt.cls);
30936 d.proxyDrag = opt.proxyDrag === true;
30937 d.modal = opt.modal !== false;
30938 d.mask = opt.modal !== false ? mask : false;
30939 if(!d.isVisible()){
30940 // force it to the end of the z-index stack so it gets a cursor in FF
30941 document.body.appendChild(dlg.el.dom);
30942 d.animateTarget = null;
30943 d.show(options.animEl);
30949 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30950 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30951 * and closing the message box when the process is complete.
30952 * @param {String} title The title bar text
30953 * @param {String} msg The message box body text
30954 * @return {Roo.MessageBox} This message box
30956 progress : function(title, msg){
30963 minWidth: this.minProgressWidth,
30970 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30971 * If a callback function is passed it will be called after the user clicks the button, and the
30972 * id of the button that was clicked will be passed as the only parameter to the callback
30973 * (could also be the top-right close button).
30974 * @param {String} title The title bar text
30975 * @param {String} msg The message box body text
30976 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30977 * @param {Object} scope (optional) The scope of the callback function
30978 * @return {Roo.MessageBox} This message box
30980 alert : function(title, msg, fn, scope){
30993 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30994 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30995 * You are responsible for closing the message box when the process is complete.
30996 * @param {String} msg The message box body text
30997 * @param {String} title (optional) The title bar text
30998 * @return {Roo.MessageBox} This message box
31000 wait : function(msg, title){
31011 waitTimer = Roo.TaskMgr.start({
31013 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31021 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31022 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31023 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31024 * @param {String} title The title bar text
31025 * @param {String} msg The message box body text
31026 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31027 * @param {Object} scope (optional) The scope of the callback function
31028 * @return {Roo.MessageBox} This message box
31030 confirm : function(title, msg, fn, scope){
31034 buttons: this.YESNO,
31043 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31044 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31045 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31046 * (could also be the top-right close button) and the text that was entered will be passed as the two
31047 * parameters to the callback.
31048 * @param {String} title The title bar text
31049 * @param {String} msg The message box body text
31050 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31051 * @param {Object} scope (optional) The scope of the callback function
31052 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31053 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31054 * @return {Roo.MessageBox} This message box
31056 prompt : function(title, msg, fn, scope, multiline){
31060 buttons: this.OKCANCEL,
31065 multiline: multiline,
31072 * Button config that displays a single OK button
31077 * Button config that displays Yes and No buttons
31080 YESNO : {yes:true, no:true},
31082 * Button config that displays OK and Cancel buttons
31085 OKCANCEL : {ok:true, cancel:true},
31087 * Button config that displays Yes, No and Cancel buttons
31090 YESNOCANCEL : {yes:true, no:true, cancel:true},
31093 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31096 defaultTextHeight : 75,
31098 * The maximum width in pixels of the message box (defaults to 600)
31103 * The minimum width in pixels of the message box (defaults to 100)
31108 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31109 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31112 minProgressWidth : 250,
31114 * An object containing the default button text strings that can be overriden for localized language support.
31115 * Supported properties are: ok, cancel, yes and no.
31116 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31129 * Shorthand for {@link Roo.MessageBox}
31131 Roo.Msg = Roo.MessageBox;/*
31133 * Ext JS Library 1.1.1
31134 * Copyright(c) 2006-2007, Ext JS, LLC.
31136 * Originally Released Under LGPL - original licence link has changed is not relivant.
31139 * <script type="text/javascript">
31142 * @class Roo.QuickTips
31143 * Provides attractive and customizable tooltips for any element.
31146 Roo.QuickTips = function(){
31147 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31148 var ce, bd, xy, dd;
31149 var visible = false, disabled = true, inited = false;
31150 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31152 var onOver = function(e){
31156 var t = e.getTarget();
31157 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31160 if(ce && t == ce.el){
31161 clearTimeout(hideProc);
31164 if(t && tagEls[t.id]){
31165 tagEls[t.id].el = t;
31166 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31169 var ttp, et = Roo.fly(t);
31170 var ns = cfg.namespace;
31171 if(tm.interceptTitles && t.title){
31174 t.removeAttribute("title");
31175 e.preventDefault();
31177 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31180 showProc = show.defer(tm.showDelay, tm, [{
31183 width: et.getAttributeNS(ns, cfg.width),
31184 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31185 title: et.getAttributeNS(ns, cfg.title),
31186 cls: et.getAttributeNS(ns, cfg.cls)
31191 var onOut = function(e){
31192 clearTimeout(showProc);
31193 var t = e.getTarget();
31194 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31195 hideProc = setTimeout(hide, tm.hideDelay);
31199 var onMove = function(e){
31205 if(tm.trackMouse && ce){
31210 var onDown = function(e){
31211 clearTimeout(showProc);
31212 clearTimeout(hideProc);
31214 if(tm.hideOnClick){
31217 tm.enable.defer(100, tm);
31222 var getPad = function(){
31223 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31226 var show = function(o){
31230 clearTimeout(dismissProc);
31232 if(removeCls){ // in case manually hidden
31233 el.removeClass(removeCls);
31237 el.addClass(ce.cls);
31238 removeCls = ce.cls;
31241 tipTitle.update(ce.title);
31244 tipTitle.update('');
31247 el.dom.style.width = tm.maxWidth+'px';
31248 //tipBody.dom.style.width = '';
31249 tipBodyText.update(o.text);
31250 var p = getPad(), w = ce.width;
31252 var td = tipBodyText.dom;
31253 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31254 if(aw > tm.maxWidth){
31256 }else if(aw < tm.minWidth){
31262 //tipBody.setWidth(w);
31263 el.setWidth(parseInt(w, 10) + p);
31264 if(ce.autoHide === false){
31265 close.setDisplayed(true);
31270 close.setDisplayed(false);
31276 el.avoidY = xy[1]-18;
31281 el.setStyle("visibility", "visible");
31282 el.fadeIn({callback: afterShow});
31288 var afterShow = function(){
31292 if(tm.autoDismiss && ce.autoHide !== false){
31293 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31298 var hide = function(noanim){
31299 clearTimeout(dismissProc);
31300 clearTimeout(hideProc);
31302 if(el.isVisible()){
31304 if(noanim !== true && tm.animate){
31305 el.fadeOut({callback: afterHide});
31312 var afterHide = function(){
31315 el.removeClass(removeCls);
31322 * @cfg {Number} minWidth
31323 * The minimum width of the quick tip (defaults to 40)
31327 * @cfg {Number} maxWidth
31328 * The maximum width of the quick tip (defaults to 300)
31332 * @cfg {Boolean} interceptTitles
31333 * True to automatically use the element's DOM title value if available (defaults to false)
31335 interceptTitles : false,
31337 * @cfg {Boolean} trackMouse
31338 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31340 trackMouse : false,
31342 * @cfg {Boolean} hideOnClick
31343 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31345 hideOnClick : true,
31347 * @cfg {Number} showDelay
31348 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31352 * @cfg {Number} hideDelay
31353 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31357 * @cfg {Boolean} autoHide
31358 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31359 * Used in conjunction with hideDelay.
31364 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31365 * (defaults to true). Used in conjunction with autoDismissDelay.
31367 autoDismiss : true,
31370 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31372 autoDismissDelay : 5000,
31374 * @cfg {Boolean} animate
31375 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31380 * @cfg {String} title
31381 * Title text to display (defaults to ''). This can be any valid HTML markup.
31385 * @cfg {String} text
31386 * Body text to display (defaults to ''). This can be any valid HTML markup.
31390 * @cfg {String} cls
31391 * A CSS class to apply to the base quick tip element (defaults to '').
31395 * @cfg {Number} width
31396 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31397 * minWidth or maxWidth.
31402 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31403 * or display QuickTips in a page.
31406 tm = Roo.QuickTips;
31407 cfg = tm.tagConfig;
31409 if(!Roo.isReady){ // allow calling of init() before onReady
31410 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31413 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31414 el.fxDefaults = {stopFx: true};
31415 // maximum custom styling
31416 //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>');
31417 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>');
31418 tipTitle = el.child('h3');
31419 tipTitle.enableDisplayMode("block");
31420 tipBody = el.child('div.x-tip-bd');
31421 tipBodyText = el.child('div.x-tip-bd-inner');
31422 //bdLeft = el.child('div.x-tip-bd-left');
31423 //bdRight = el.child('div.x-tip-bd-right');
31424 close = el.child('div.x-tip-close');
31425 close.enableDisplayMode("block");
31426 close.on("click", hide);
31427 var d = Roo.get(document);
31428 d.on("mousedown", onDown);
31429 d.on("mouseover", onOver);
31430 d.on("mouseout", onOut);
31431 d.on("mousemove", onMove);
31432 esc = d.addKeyListener(27, hide);
31435 dd = el.initDD("default", null, {
31436 onDrag : function(){
31440 dd.setHandleElId(tipTitle.id);
31449 * Configures a new quick tip instance and assigns it to a target element. The following config options
31452 Property Type Description
31453 ---------- --------------------- ------------------------------------------------------------------------
31454 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31456 * @param {Object} config The config object
31458 register : function(config){
31459 var cs = config instanceof Array ? config : arguments;
31460 for(var i = 0, len = cs.length; i < len; i++) {
31462 var target = c.target;
31464 if(target instanceof Array){
31465 for(var j = 0, jlen = target.length; j < jlen; j++){
31466 tagEls[target[j]] = c;
31469 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31476 * Removes this quick tip from its element and destroys it.
31477 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31479 unregister : function(el){
31480 delete tagEls[Roo.id(el)];
31484 * Enable this quick tip.
31486 enable : function(){
31487 if(inited && disabled){
31489 if(locks.length < 1){
31496 * Disable this quick tip.
31498 disable : function(){
31500 clearTimeout(showProc);
31501 clearTimeout(hideProc);
31502 clearTimeout(dismissProc);
31510 * Returns true if the quick tip is enabled, else false.
31512 isEnabled : function(){
31519 attribute : "qtip",
31529 // backwards compat
31530 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31532 * Ext JS Library 1.1.1
31533 * Copyright(c) 2006-2007, Ext JS, LLC.
31535 * Originally Released Under LGPL - original licence link has changed is not relivant.
31538 * <script type="text/javascript">
31543 * @class Roo.tree.TreePanel
31544 * @extends Roo.data.Tree
31546 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31547 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31548 * @cfg {Boolean} enableDD true to enable drag and drop
31549 * @cfg {Boolean} enableDrag true to enable just drag
31550 * @cfg {Boolean} enableDrop true to enable just drop
31551 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31552 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31553 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31554 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31555 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31556 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31557 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31558 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31559 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31560 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31561 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31562 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31563 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31564 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31565 * @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>
31566 * @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>
31569 * @param {String/HTMLElement/Element} el The container element
31570 * @param {Object} config
31572 Roo.tree.TreePanel = function(el, config){
31574 var loader = false;
31576 root = config.root;
31577 delete config.root;
31579 if (config.loader) {
31580 loader = config.loader;
31581 delete config.loader;
31584 Roo.apply(this, config);
31585 Roo.tree.TreePanel.superclass.constructor.call(this);
31586 this.el = Roo.get(el);
31587 this.el.addClass('x-tree');
31588 //console.log(root);
31590 this.setRootNode( Roo.factory(root, Roo.tree));
31593 this.loader = Roo.factory(loader, Roo.tree);
31596 * Read-only. The id of the container element becomes this TreePanel's id.
31598 this.id = this.el.id;
31601 * @event beforeload
31602 * Fires before a node is loaded, return false to cancel
31603 * @param {Node} node The node being loaded
31605 "beforeload" : true,
31608 * Fires when a node is loaded
31609 * @param {Node} node The node that was loaded
31613 * @event textchange
31614 * Fires when the text for a node is changed
31615 * @param {Node} node The node
31616 * @param {String} text The new text
31617 * @param {String} oldText The old text
31619 "textchange" : true,
31621 * @event beforeexpand
31622 * Fires before a node is expanded, return false to cancel.
31623 * @param {Node} node The node
31624 * @param {Boolean} deep
31625 * @param {Boolean} anim
31627 "beforeexpand" : true,
31629 * @event beforecollapse
31630 * Fires before a node is collapsed, return false to cancel.
31631 * @param {Node} node The node
31632 * @param {Boolean} deep
31633 * @param {Boolean} anim
31635 "beforecollapse" : true,
31638 * Fires when a node is expanded
31639 * @param {Node} node The node
31643 * @event disabledchange
31644 * Fires when the disabled status of a node changes
31645 * @param {Node} node The node
31646 * @param {Boolean} disabled
31648 "disabledchange" : true,
31651 * Fires when a node is collapsed
31652 * @param {Node} node The node
31656 * @event beforeclick
31657 * Fires before click processing on a node. Return false to cancel the default action.
31658 * @param {Node} node The node
31659 * @param {Roo.EventObject} e The event object
31661 "beforeclick":true,
31663 * @event checkchange
31664 * Fires when a node with a checkbox's checked property changes
31665 * @param {Node} this This node
31666 * @param {Boolean} checked
31668 "checkchange":true,
31671 * Fires when a node is clicked
31672 * @param {Node} node The node
31673 * @param {Roo.EventObject} e The event object
31678 * Fires when a node is double clicked
31679 * @param {Node} node The node
31680 * @param {Roo.EventObject} e The event object
31684 * @event contextmenu
31685 * Fires when a node is right clicked
31686 * @param {Node} node The node
31687 * @param {Roo.EventObject} e The event object
31689 "contextmenu":true,
31691 * @event beforechildrenrendered
31692 * Fires right before the child nodes for a node are rendered
31693 * @param {Node} node The node
31695 "beforechildrenrendered":true,
31698 * Fires when a node starts being dragged
31699 * @param {Roo.tree.TreePanel} this
31700 * @param {Roo.tree.TreeNode} node
31701 * @param {event} e The raw browser event
31703 "startdrag" : true,
31706 * Fires when a drag operation is complete
31707 * @param {Roo.tree.TreePanel} this
31708 * @param {Roo.tree.TreeNode} node
31709 * @param {event} e The raw browser event
31714 * Fires when a dragged node is dropped on a valid DD target
31715 * @param {Roo.tree.TreePanel} this
31716 * @param {Roo.tree.TreeNode} node
31717 * @param {DD} dd The dd it was dropped on
31718 * @param {event} e The raw browser event
31722 * @event beforenodedrop
31723 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31724 * passed to handlers has the following properties:<br />
31725 * <ul style="padding:5px;padding-left:16px;">
31726 * <li>tree - The TreePanel</li>
31727 * <li>target - The node being targeted for the drop</li>
31728 * <li>data - The drag data from the drag source</li>
31729 * <li>point - The point of the drop - append, above or below</li>
31730 * <li>source - The drag source</li>
31731 * <li>rawEvent - Raw mouse event</li>
31732 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31733 * to be inserted by setting them on this object.</li>
31734 * <li>cancel - Set this to true to cancel the drop.</li>
31736 * @param {Object} dropEvent
31738 "beforenodedrop" : true,
31741 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31742 * passed to handlers has the following properties:<br />
31743 * <ul style="padding:5px;padding-left:16px;">
31744 * <li>tree - The TreePanel</li>
31745 * <li>target - The node being targeted for the drop</li>
31746 * <li>data - The drag data from the drag source</li>
31747 * <li>point - The point of the drop - append, above or below</li>
31748 * <li>source - The drag source</li>
31749 * <li>rawEvent - Raw mouse event</li>
31750 * <li>dropNode - Dropped node(s).</li>
31752 * @param {Object} dropEvent
31756 * @event nodedragover
31757 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31758 * passed to handlers has the following properties:<br />
31759 * <ul style="padding:5px;padding-left:16px;">
31760 * <li>tree - The TreePanel</li>
31761 * <li>target - The node being targeted for the drop</li>
31762 * <li>data - The drag data from the drag source</li>
31763 * <li>point - The point of the drop - append, above or below</li>
31764 * <li>source - The drag source</li>
31765 * <li>rawEvent - Raw mouse event</li>
31766 * <li>dropNode - Drop node(s) provided by the source.</li>
31767 * <li>cancel - Set this to true to signal drop not allowed.</li>
31769 * @param {Object} dragOverEvent
31771 "nodedragover" : true
31774 if(this.singleExpand){
31775 this.on("beforeexpand", this.restrictExpand, this);
31778 this.editor.tree = this;
31779 this.editor = Roo.factory(this.editor, Roo.tree);
31782 if (this.selModel) {
31783 this.selModel = Roo.factory(this.selModel, Roo.tree);
31787 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31788 rootVisible : true,
31789 animate: Roo.enableFx,
31792 hlDrop : Roo.enableFx,
31796 rendererTip: false,
31798 restrictExpand : function(node){
31799 var p = node.parentNode;
31801 if(p.expandedChild && p.expandedChild.parentNode == p){
31802 p.expandedChild.collapse();
31804 p.expandedChild = node;
31808 // private override
31809 setRootNode : function(node){
31810 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31811 if(!this.rootVisible){
31812 node.ui = new Roo.tree.RootTreeNodeUI(node);
31818 * Returns the container element for this TreePanel
31820 getEl : function(){
31825 * Returns the default TreeLoader for this TreePanel
31827 getLoader : function(){
31828 return this.loader;
31834 expandAll : function(){
31835 this.root.expand(true);
31839 * Collapse all nodes
31841 collapseAll : function(){
31842 this.root.collapse(true);
31846 * Returns the selection model used by this TreePanel
31848 getSelectionModel : function(){
31849 if(!this.selModel){
31850 this.selModel = new Roo.tree.DefaultSelectionModel();
31852 return this.selModel;
31856 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31857 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31858 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31861 getChecked : function(a, startNode){
31862 startNode = startNode || this.root;
31864 var f = function(){
31865 if(this.attributes.checked){
31866 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31869 startNode.cascade(f);
31874 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31875 * @param {String} path
31876 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31877 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31878 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31880 expandPath : function(path, attr, callback){
31881 attr = attr || "id";
31882 var keys = path.split(this.pathSeparator);
31883 var curNode = this.root;
31884 if(curNode.attributes[attr] != keys[1]){ // invalid root
31886 callback(false, null);
31891 var f = function(){
31892 if(++index == keys.length){
31894 callback(true, curNode);
31898 var c = curNode.findChild(attr, keys[index]);
31901 callback(false, curNode);
31906 c.expand(false, false, f);
31908 curNode.expand(false, false, f);
31912 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31913 * @param {String} path
31914 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31915 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31916 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31918 selectPath : function(path, attr, callback){
31919 attr = attr || "id";
31920 var keys = path.split(this.pathSeparator);
31921 var v = keys.pop();
31922 if(keys.length > 0){
31923 var f = function(success, node){
31924 if(success && node){
31925 var n = node.findChild(attr, v);
31931 }else if(callback){
31932 callback(false, n);
31936 callback(false, n);
31940 this.expandPath(keys.join(this.pathSeparator), attr, f);
31942 this.root.select();
31944 callback(true, this.root);
31949 getTreeEl : function(){
31954 * Trigger rendering of this TreePanel
31956 render : function(){
31957 if (this.innerCt) {
31958 return this; // stop it rendering more than once!!
31961 this.innerCt = this.el.createChild({tag:"ul",
31962 cls:"x-tree-root-ct " +
31963 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31965 if(this.containerScroll){
31966 Roo.dd.ScrollManager.register(this.el);
31968 if((this.enableDD || this.enableDrop) && !this.dropZone){
31970 * The dropZone used by this tree if drop is enabled
31971 * @type Roo.tree.TreeDropZone
31973 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31974 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31977 if((this.enableDD || this.enableDrag) && !this.dragZone){
31979 * The dragZone used by this tree if drag is enabled
31980 * @type Roo.tree.TreeDragZone
31982 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31983 ddGroup: this.ddGroup || "TreeDD",
31984 scroll: this.ddScroll
31987 this.getSelectionModel().init(this);
31989 Roo.log("ROOT not set in tree");
31992 this.root.render();
31993 if(!this.rootVisible){
31994 this.root.renderChildren();
32000 * Ext JS Library 1.1.1
32001 * Copyright(c) 2006-2007, Ext JS, LLC.
32003 * Originally Released Under LGPL - original licence link has changed is not relivant.
32006 * <script type="text/javascript">
32011 * @class Roo.tree.DefaultSelectionModel
32012 * @extends Roo.util.Observable
32013 * The default single selection for a TreePanel.
32014 * @param {Object} cfg Configuration
32016 Roo.tree.DefaultSelectionModel = function(cfg){
32017 this.selNode = null;
32023 * @event selectionchange
32024 * Fires when the selected node changes
32025 * @param {DefaultSelectionModel} this
32026 * @param {TreeNode} node the new selection
32028 "selectionchange" : true,
32031 * @event beforeselect
32032 * Fires before the selected node changes, return false to cancel the change
32033 * @param {DefaultSelectionModel} this
32034 * @param {TreeNode} node the new selection
32035 * @param {TreeNode} node the old selection
32037 "beforeselect" : true
32040 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32043 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32044 init : function(tree){
32046 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32047 tree.on("click", this.onNodeClick, this);
32050 onNodeClick : function(node, e){
32051 if (e.ctrlKey && this.selNode == node) {
32052 this.unselect(node);
32060 * @param {TreeNode} node The node to select
32061 * @return {TreeNode} The selected node
32063 select : function(node){
32064 var last = this.selNode;
32065 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32067 last.ui.onSelectedChange(false);
32069 this.selNode = node;
32070 node.ui.onSelectedChange(true);
32071 this.fireEvent("selectionchange", this, node, last);
32078 * @param {TreeNode} node The node to unselect
32080 unselect : function(node){
32081 if(this.selNode == node){
32082 this.clearSelections();
32087 * Clear all selections
32089 clearSelections : function(){
32090 var n = this.selNode;
32092 n.ui.onSelectedChange(false);
32093 this.selNode = null;
32094 this.fireEvent("selectionchange", this, null);
32100 * Get the selected node
32101 * @return {TreeNode} The selected node
32103 getSelectedNode : function(){
32104 return this.selNode;
32108 * Returns true if the node is selected
32109 * @param {TreeNode} node The node to check
32110 * @return {Boolean}
32112 isSelected : function(node){
32113 return this.selNode == node;
32117 * Selects the node above the selected node in the tree, intelligently walking the nodes
32118 * @return TreeNode The new selection
32120 selectPrevious : function(){
32121 var s = this.selNode || this.lastSelNode;
32125 var ps = s.previousSibling;
32127 if(!ps.isExpanded() || ps.childNodes.length < 1){
32128 return this.select(ps);
32130 var lc = ps.lastChild;
32131 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32134 return this.select(lc);
32136 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32137 return this.select(s.parentNode);
32143 * Selects the node above the selected node in the tree, intelligently walking the nodes
32144 * @return TreeNode The new selection
32146 selectNext : function(){
32147 var s = this.selNode || this.lastSelNode;
32151 if(s.firstChild && s.isExpanded()){
32152 return this.select(s.firstChild);
32153 }else if(s.nextSibling){
32154 return this.select(s.nextSibling);
32155 }else if(s.parentNode){
32157 s.parentNode.bubble(function(){
32158 if(this.nextSibling){
32159 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32168 onKeyDown : function(e){
32169 var s = this.selNode || this.lastSelNode;
32170 // undesirable, but required
32175 var k = e.getKey();
32183 this.selectPrevious();
32186 e.preventDefault();
32187 if(s.hasChildNodes()){
32188 if(!s.isExpanded()){
32190 }else if(s.firstChild){
32191 this.select(s.firstChild, e);
32196 e.preventDefault();
32197 if(s.hasChildNodes() && s.isExpanded()){
32199 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32200 this.select(s.parentNode, e);
32208 * @class Roo.tree.MultiSelectionModel
32209 * @extends Roo.util.Observable
32210 * Multi selection for a TreePanel.
32211 * @param {Object} cfg Configuration
32213 Roo.tree.MultiSelectionModel = function(){
32214 this.selNodes = [];
32218 * @event selectionchange
32219 * Fires when the selected nodes change
32220 * @param {MultiSelectionModel} this
32221 * @param {Array} nodes Array of the selected nodes
32223 "selectionchange" : true
32225 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32229 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32230 init : function(tree){
32232 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32233 tree.on("click", this.onNodeClick, this);
32236 onNodeClick : function(node, e){
32237 this.select(node, e, e.ctrlKey);
32242 * @param {TreeNode} node The node to select
32243 * @param {EventObject} e (optional) An event associated with the selection
32244 * @param {Boolean} keepExisting True to retain existing selections
32245 * @return {TreeNode} The selected node
32247 select : function(node, e, keepExisting){
32248 if(keepExisting !== true){
32249 this.clearSelections(true);
32251 if(this.isSelected(node)){
32252 this.lastSelNode = node;
32255 this.selNodes.push(node);
32256 this.selMap[node.id] = node;
32257 this.lastSelNode = node;
32258 node.ui.onSelectedChange(true);
32259 this.fireEvent("selectionchange", this, this.selNodes);
32265 * @param {TreeNode} node The node to unselect
32267 unselect : function(node){
32268 if(this.selMap[node.id]){
32269 node.ui.onSelectedChange(false);
32270 var sn = this.selNodes;
32273 index = sn.indexOf(node);
32275 for(var i = 0, len = sn.length; i < len; i++){
32283 this.selNodes.splice(index, 1);
32285 delete this.selMap[node.id];
32286 this.fireEvent("selectionchange", this, this.selNodes);
32291 * Clear all selections
32293 clearSelections : function(suppressEvent){
32294 var sn = this.selNodes;
32296 for(var i = 0, len = sn.length; i < len; i++){
32297 sn[i].ui.onSelectedChange(false);
32299 this.selNodes = [];
32301 if(suppressEvent !== true){
32302 this.fireEvent("selectionchange", this, this.selNodes);
32308 * Returns true if the node is selected
32309 * @param {TreeNode} node The node to check
32310 * @return {Boolean}
32312 isSelected : function(node){
32313 return this.selMap[node.id] ? true : false;
32317 * Returns an array of the selected nodes
32320 getSelectedNodes : function(){
32321 return this.selNodes;
32324 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32326 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32328 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32331 * Ext JS Library 1.1.1
32332 * Copyright(c) 2006-2007, Ext JS, LLC.
32334 * Originally Released Under LGPL - original licence link has changed is not relivant.
32337 * <script type="text/javascript">
32341 * @class Roo.tree.TreeNode
32342 * @extends Roo.data.Node
32343 * @cfg {String} text The text for this node
32344 * @cfg {Boolean} expanded true to start the node expanded
32345 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32346 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32347 * @cfg {Boolean} disabled true to start the node disabled
32348 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32349 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32350 * @cfg {String} cls A css class to be added to the node
32351 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32352 * @cfg {String} href URL of the link used for the node (defaults to #)
32353 * @cfg {String} hrefTarget target frame for the link
32354 * @cfg {String} qtip An Ext QuickTip for the node
32355 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32356 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32357 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32358 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32359 * (defaults to undefined with no checkbox rendered)
32361 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32363 Roo.tree.TreeNode = function(attributes){
32364 attributes = attributes || {};
32365 if(typeof attributes == "string"){
32366 attributes = {text: attributes};
32368 this.childrenRendered = false;
32369 this.rendered = false;
32370 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32371 this.expanded = attributes.expanded === true;
32372 this.isTarget = attributes.isTarget !== false;
32373 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32374 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32377 * Read-only. The text for this node. To change it use setText().
32380 this.text = attributes.text;
32382 * True if this node is disabled.
32385 this.disabled = attributes.disabled === true;
32389 * @event textchange
32390 * Fires when the text for this node is changed
32391 * @param {Node} this This node
32392 * @param {String} text The new text
32393 * @param {String} oldText The old text
32395 "textchange" : true,
32397 * @event beforeexpand
32398 * Fires before this node is expanded, return false to cancel.
32399 * @param {Node} this This node
32400 * @param {Boolean} deep
32401 * @param {Boolean} anim
32403 "beforeexpand" : true,
32405 * @event beforecollapse
32406 * Fires before this node is collapsed, return false to cancel.
32407 * @param {Node} this This node
32408 * @param {Boolean} deep
32409 * @param {Boolean} anim
32411 "beforecollapse" : true,
32414 * Fires when this node is expanded
32415 * @param {Node} this This node
32419 * @event disabledchange
32420 * Fires when the disabled status of this node changes
32421 * @param {Node} this This node
32422 * @param {Boolean} disabled
32424 "disabledchange" : true,
32427 * Fires when this node is collapsed
32428 * @param {Node} this This node
32432 * @event beforeclick
32433 * Fires before click processing. Return false to cancel the default action.
32434 * @param {Node} this This node
32435 * @param {Roo.EventObject} e The event object
32437 "beforeclick":true,
32439 * @event checkchange
32440 * Fires when a node with a checkbox's checked property changes
32441 * @param {Node} this This node
32442 * @param {Boolean} checked
32444 "checkchange":true,
32447 * Fires when this node is clicked
32448 * @param {Node} this This node
32449 * @param {Roo.EventObject} e The event object
32454 * Fires when this node is double clicked
32455 * @param {Node} this This node
32456 * @param {Roo.EventObject} e The event object
32460 * @event contextmenu
32461 * Fires when this node is right clicked
32462 * @param {Node} this This node
32463 * @param {Roo.EventObject} e The event object
32465 "contextmenu":true,
32467 * @event beforechildrenrendered
32468 * Fires right before the child nodes for this node are rendered
32469 * @param {Node} this This node
32471 "beforechildrenrendered":true
32474 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32477 * Read-only. The UI for this node
32480 this.ui = new uiClass(this);
32482 // finally support items[]
32483 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32488 Roo.each(this.attributes.items, function(c) {
32489 this.appendChild(Roo.factory(c,Roo.Tree));
32491 delete this.attributes.items;
32496 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32497 preventHScroll: true,
32499 * Returns true if this node is expanded
32500 * @return {Boolean}
32502 isExpanded : function(){
32503 return this.expanded;
32507 * Returns the UI object for this node
32508 * @return {TreeNodeUI}
32510 getUI : function(){
32514 // private override
32515 setFirstChild : function(node){
32516 var of = this.firstChild;
32517 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32518 if(this.childrenRendered && of && node != of){
32519 of.renderIndent(true, true);
32522 this.renderIndent(true, true);
32526 // private override
32527 setLastChild : function(node){
32528 var ol = this.lastChild;
32529 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32530 if(this.childrenRendered && ol && node != ol){
32531 ol.renderIndent(true, true);
32534 this.renderIndent(true, true);
32538 // these methods are overridden to provide lazy rendering support
32539 // private override
32540 appendChild : function()
32542 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32543 if(node && this.childrenRendered){
32546 this.ui.updateExpandIcon();
32550 // private override
32551 removeChild : function(node){
32552 this.ownerTree.getSelectionModel().unselect(node);
32553 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32554 // if it's been rendered remove dom node
32555 if(this.childrenRendered){
32558 if(this.childNodes.length < 1){
32559 this.collapse(false, false);
32561 this.ui.updateExpandIcon();
32563 if(!this.firstChild) {
32564 this.childrenRendered = false;
32569 // private override
32570 insertBefore : function(node, refNode){
32571 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32572 if(newNode && refNode && this.childrenRendered){
32575 this.ui.updateExpandIcon();
32580 * Sets the text for this node
32581 * @param {String} text
32583 setText : function(text){
32584 var oldText = this.text;
32586 this.attributes.text = text;
32587 if(this.rendered){ // event without subscribing
32588 this.ui.onTextChange(this, text, oldText);
32590 this.fireEvent("textchange", this, text, oldText);
32594 * Triggers selection of this node
32596 select : function(){
32597 this.getOwnerTree().getSelectionModel().select(this);
32601 * Triggers deselection of this node
32603 unselect : function(){
32604 this.getOwnerTree().getSelectionModel().unselect(this);
32608 * Returns true if this node is selected
32609 * @return {Boolean}
32611 isSelected : function(){
32612 return this.getOwnerTree().getSelectionModel().isSelected(this);
32616 * Expand this node.
32617 * @param {Boolean} deep (optional) True to expand all children as well
32618 * @param {Boolean} anim (optional) false to cancel the default animation
32619 * @param {Function} callback (optional) A callback to be called when
32620 * expanding this node completes (does not wait for deep expand to complete).
32621 * Called with 1 parameter, this node.
32623 expand : function(deep, anim, callback){
32624 if(!this.expanded){
32625 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32628 if(!this.childrenRendered){
32629 this.renderChildren();
32631 this.expanded = true;
32632 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32633 this.ui.animExpand(function(){
32634 this.fireEvent("expand", this);
32635 if(typeof callback == "function"){
32639 this.expandChildNodes(true);
32641 }.createDelegate(this));
32645 this.fireEvent("expand", this);
32646 if(typeof callback == "function"){
32651 if(typeof callback == "function"){
32656 this.expandChildNodes(true);
32660 isHiddenRoot : function(){
32661 return this.isRoot && !this.getOwnerTree().rootVisible;
32665 * Collapse this node.
32666 * @param {Boolean} deep (optional) True to collapse all children as well
32667 * @param {Boolean} anim (optional) false to cancel the default animation
32669 collapse : function(deep, anim){
32670 if(this.expanded && !this.isHiddenRoot()){
32671 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32674 this.expanded = false;
32675 if((this.getOwnerTree().animate && anim !== false) || anim){
32676 this.ui.animCollapse(function(){
32677 this.fireEvent("collapse", this);
32679 this.collapseChildNodes(true);
32681 }.createDelegate(this));
32684 this.ui.collapse();
32685 this.fireEvent("collapse", this);
32689 var cs = this.childNodes;
32690 for(var i = 0, len = cs.length; i < len; i++) {
32691 cs[i].collapse(true, false);
32697 delayedExpand : function(delay){
32698 if(!this.expandProcId){
32699 this.expandProcId = this.expand.defer(delay, this);
32704 cancelExpand : function(){
32705 if(this.expandProcId){
32706 clearTimeout(this.expandProcId);
32708 this.expandProcId = false;
32712 * Toggles expanded/collapsed state of the node
32714 toggle : function(){
32723 * Ensures all parent nodes are expanded
32725 ensureVisible : function(callback){
32726 var tree = this.getOwnerTree();
32727 tree.expandPath(this.parentNode.getPath(), false, function(){
32728 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32729 Roo.callback(callback);
32730 }.createDelegate(this));
32734 * Expand all child nodes
32735 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32737 expandChildNodes : function(deep){
32738 var cs = this.childNodes;
32739 for(var i = 0, len = cs.length; i < len; i++) {
32740 cs[i].expand(deep);
32745 * Collapse all child nodes
32746 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32748 collapseChildNodes : function(deep){
32749 var cs = this.childNodes;
32750 for(var i = 0, len = cs.length; i < len; i++) {
32751 cs[i].collapse(deep);
32756 * Disables this node
32758 disable : function(){
32759 this.disabled = true;
32761 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32762 this.ui.onDisableChange(this, true);
32764 this.fireEvent("disabledchange", this, true);
32768 * Enables this node
32770 enable : function(){
32771 this.disabled = false;
32772 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32773 this.ui.onDisableChange(this, false);
32775 this.fireEvent("disabledchange", this, false);
32779 renderChildren : function(suppressEvent){
32780 if(suppressEvent !== false){
32781 this.fireEvent("beforechildrenrendered", this);
32783 var cs = this.childNodes;
32784 for(var i = 0, len = cs.length; i < len; i++){
32785 cs[i].render(true);
32787 this.childrenRendered = true;
32791 sort : function(fn, scope){
32792 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32793 if(this.childrenRendered){
32794 var cs = this.childNodes;
32795 for(var i = 0, len = cs.length; i < len; i++){
32796 cs[i].render(true);
32802 render : function(bulkRender){
32803 this.ui.render(bulkRender);
32804 if(!this.rendered){
32805 this.rendered = true;
32807 this.expanded = false;
32808 this.expand(false, false);
32814 renderIndent : function(deep, refresh){
32816 this.ui.childIndent = null;
32818 this.ui.renderIndent();
32819 if(deep === true && this.childrenRendered){
32820 var cs = this.childNodes;
32821 for(var i = 0, len = cs.length; i < len; i++){
32822 cs[i].renderIndent(true, refresh);
32828 * Ext JS Library 1.1.1
32829 * Copyright(c) 2006-2007, Ext JS, LLC.
32831 * Originally Released Under LGPL - original licence link has changed is not relivant.
32834 * <script type="text/javascript">
32838 * @class Roo.tree.AsyncTreeNode
32839 * @extends Roo.tree.TreeNode
32840 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32842 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32844 Roo.tree.AsyncTreeNode = function(config){
32845 this.loaded = false;
32846 this.loading = false;
32847 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32849 * @event beforeload
32850 * Fires before this node is loaded, return false to cancel
32851 * @param {Node} this This node
32853 this.addEvents({'beforeload':true, 'load': true});
32856 * Fires when this node is loaded
32857 * @param {Node} this This node
32860 * The loader used by this node (defaults to using the tree's defined loader)
32865 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32866 expand : function(deep, anim, callback){
32867 if(this.loading){ // if an async load is already running, waiting til it's done
32869 var f = function(){
32870 if(!this.loading){ // done loading
32871 clearInterval(timer);
32872 this.expand(deep, anim, callback);
32874 }.createDelegate(this);
32875 timer = setInterval(f, 200);
32879 if(this.fireEvent("beforeload", this) === false){
32882 this.loading = true;
32883 this.ui.beforeLoad(this);
32884 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32886 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32890 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32894 * Returns true if this node is currently loading
32895 * @return {Boolean}
32897 isLoading : function(){
32898 return this.loading;
32901 loadComplete : function(deep, anim, callback){
32902 this.loading = false;
32903 this.loaded = true;
32904 this.ui.afterLoad(this);
32905 this.fireEvent("load", this);
32906 this.expand(deep, anim, callback);
32910 * Returns true if this node has been loaded
32911 * @return {Boolean}
32913 isLoaded : function(){
32914 return this.loaded;
32917 hasChildNodes : function(){
32918 if(!this.isLeaf() && !this.loaded){
32921 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32926 * Trigger a reload for this node
32927 * @param {Function} callback
32929 reload : function(callback){
32930 this.collapse(false, false);
32931 while(this.firstChild){
32932 this.removeChild(this.firstChild);
32934 this.childrenRendered = false;
32935 this.loaded = false;
32936 if(this.isHiddenRoot()){
32937 this.expanded = false;
32939 this.expand(false, false, callback);
32943 * Ext JS Library 1.1.1
32944 * Copyright(c) 2006-2007, Ext JS, LLC.
32946 * Originally Released Under LGPL - original licence link has changed is not relivant.
32949 * <script type="text/javascript">
32953 * @class Roo.tree.TreeNodeUI
32955 * @param {Object} node The node to render
32956 * The TreeNode UI implementation is separate from the
32957 * tree implementation. Unless you are customizing the tree UI,
32958 * you should never have to use this directly.
32960 Roo.tree.TreeNodeUI = function(node){
32962 this.rendered = false;
32963 this.animating = false;
32964 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32967 Roo.tree.TreeNodeUI.prototype = {
32968 removeChild : function(node){
32970 this.ctNode.removeChild(node.ui.getEl());
32974 beforeLoad : function(){
32975 this.addClass("x-tree-node-loading");
32978 afterLoad : function(){
32979 this.removeClass("x-tree-node-loading");
32982 onTextChange : function(node, text, oldText){
32984 this.textNode.innerHTML = text;
32988 onDisableChange : function(node, state){
32989 this.disabled = state;
32991 this.addClass("x-tree-node-disabled");
32993 this.removeClass("x-tree-node-disabled");
32997 onSelectedChange : function(state){
33000 this.addClass("x-tree-selected");
33003 this.removeClass("x-tree-selected");
33007 onMove : function(tree, node, oldParent, newParent, index, refNode){
33008 this.childIndent = null;
33010 var targetNode = newParent.ui.getContainer();
33011 if(!targetNode){//target not rendered
33012 this.holder = document.createElement("div");
33013 this.holder.appendChild(this.wrap);
33016 var insertBefore = refNode ? refNode.ui.getEl() : null;
33018 targetNode.insertBefore(this.wrap, insertBefore);
33020 targetNode.appendChild(this.wrap);
33022 this.node.renderIndent(true);
33026 addClass : function(cls){
33028 Roo.fly(this.elNode).addClass(cls);
33032 removeClass : function(cls){
33034 Roo.fly(this.elNode).removeClass(cls);
33038 remove : function(){
33040 this.holder = document.createElement("div");
33041 this.holder.appendChild(this.wrap);
33045 fireEvent : function(){
33046 return this.node.fireEvent.apply(this.node, arguments);
33049 initEvents : function(){
33050 this.node.on("move", this.onMove, this);
33051 var E = Roo.EventManager;
33052 var a = this.anchor;
33054 var el = Roo.fly(a, '_treeui');
33056 if(Roo.isOpera){ // opera render bug ignores the CSS
33057 el.setStyle("text-decoration", "none");
33060 el.on("click", this.onClick, this);
33061 el.on("dblclick", this.onDblClick, this);
33064 Roo.EventManager.on(this.checkbox,
33065 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33068 el.on("contextmenu", this.onContextMenu, this);
33070 var icon = Roo.fly(this.iconNode);
33071 icon.on("click", this.onClick, this);
33072 icon.on("dblclick", this.onDblClick, this);
33073 icon.on("contextmenu", this.onContextMenu, this);
33074 E.on(this.ecNode, "click", this.ecClick, this, true);
33076 if(this.node.disabled){
33077 this.addClass("x-tree-node-disabled");
33079 if(this.node.hidden){
33080 this.addClass("x-tree-node-disabled");
33082 var ot = this.node.getOwnerTree();
33083 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33084 if(dd && (!this.node.isRoot || ot.rootVisible)){
33085 Roo.dd.Registry.register(this.elNode, {
33087 handles: this.getDDHandles(),
33093 getDDHandles : function(){
33094 return [this.iconNode, this.textNode];
33099 this.wrap.style.display = "none";
33105 this.wrap.style.display = "";
33109 onContextMenu : function(e){
33110 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33111 e.preventDefault();
33113 this.fireEvent("contextmenu", this.node, e);
33117 onClick : function(e){
33122 if(this.fireEvent("beforeclick", this.node, e) !== false){
33123 if(!this.disabled && this.node.attributes.href){
33124 this.fireEvent("click", this.node, e);
33127 e.preventDefault();
33132 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33133 this.node.toggle();
33136 this.fireEvent("click", this.node, e);
33142 onDblClick : function(e){
33143 e.preventDefault();
33148 this.toggleCheck();
33150 if(!this.animating && this.node.hasChildNodes()){
33151 this.node.toggle();
33153 this.fireEvent("dblclick", this.node, e);
33156 onCheckChange : function(){
33157 var checked = this.checkbox.checked;
33158 this.node.attributes.checked = checked;
33159 this.fireEvent('checkchange', this.node, checked);
33162 ecClick : function(e){
33163 if(!this.animating && this.node.hasChildNodes()){
33164 this.node.toggle();
33168 startDrop : function(){
33169 this.dropping = true;
33172 // delayed drop so the click event doesn't get fired on a drop
33173 endDrop : function(){
33174 setTimeout(function(){
33175 this.dropping = false;
33176 }.createDelegate(this), 50);
33179 expand : function(){
33180 this.updateExpandIcon();
33181 this.ctNode.style.display = "";
33184 focus : function(){
33185 if(!this.node.preventHScroll){
33186 try{this.anchor.focus();
33188 }else if(!Roo.isIE){
33190 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33191 var l = noscroll.scrollLeft;
33192 this.anchor.focus();
33193 noscroll.scrollLeft = l;
33198 toggleCheck : function(value){
33199 var cb = this.checkbox;
33201 cb.checked = (value === undefined ? !cb.checked : value);
33207 this.anchor.blur();
33211 animExpand : function(callback){
33212 var ct = Roo.get(this.ctNode);
33214 if(!this.node.hasChildNodes()){
33215 this.updateExpandIcon();
33216 this.ctNode.style.display = "";
33217 Roo.callback(callback);
33220 this.animating = true;
33221 this.updateExpandIcon();
33224 callback : function(){
33225 this.animating = false;
33226 Roo.callback(callback);
33229 duration: this.node.ownerTree.duration || .25
33233 highlight : function(){
33234 var tree = this.node.getOwnerTree();
33235 Roo.fly(this.wrap).highlight(
33236 tree.hlColor || "C3DAF9",
33237 {endColor: tree.hlBaseColor}
33241 collapse : function(){
33242 this.updateExpandIcon();
33243 this.ctNode.style.display = "none";
33246 animCollapse : function(callback){
33247 var ct = Roo.get(this.ctNode);
33248 ct.enableDisplayMode('block');
33251 this.animating = true;
33252 this.updateExpandIcon();
33255 callback : function(){
33256 this.animating = false;
33257 Roo.callback(callback);
33260 duration: this.node.ownerTree.duration || .25
33264 getContainer : function(){
33265 return this.ctNode;
33268 getEl : function(){
33272 appendDDGhost : function(ghostNode){
33273 ghostNode.appendChild(this.elNode.cloneNode(true));
33276 getDDRepairXY : function(){
33277 return Roo.lib.Dom.getXY(this.iconNode);
33280 onRender : function(){
33284 render : function(bulkRender){
33285 var n = this.node, a = n.attributes;
33286 var targetNode = n.parentNode ?
33287 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33289 if(!this.rendered){
33290 this.rendered = true;
33292 this.renderElements(n, a, targetNode, bulkRender);
33295 if(this.textNode.setAttributeNS){
33296 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33298 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33301 this.textNode.setAttribute("ext:qtip", a.qtip);
33303 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33306 }else if(a.qtipCfg){
33307 a.qtipCfg.target = Roo.id(this.textNode);
33308 Roo.QuickTips.register(a.qtipCfg);
33311 if(!this.node.expanded){
33312 this.updateExpandIcon();
33315 if(bulkRender === true) {
33316 targetNode.appendChild(this.wrap);
33321 renderElements : function(n, a, targetNode, bulkRender)
33323 // add some indent caching, this helps performance when rendering a large tree
33324 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33325 var t = n.getOwnerTree();
33326 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33327 if (typeof(n.attributes.html) != 'undefined') {
33328 txt = n.attributes.html;
33330 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33331 var cb = typeof a.checked == 'boolean';
33332 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33333 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33334 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33335 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33336 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33337 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33338 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33339 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33340 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33341 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33344 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33345 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33346 n.nextSibling.ui.getEl(), buf.join(""));
33348 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33351 this.elNode = this.wrap.childNodes[0];
33352 this.ctNode = this.wrap.childNodes[1];
33353 var cs = this.elNode.childNodes;
33354 this.indentNode = cs[0];
33355 this.ecNode = cs[1];
33356 this.iconNode = cs[2];
33359 this.checkbox = cs[3];
33362 this.anchor = cs[index];
33363 this.textNode = cs[index].firstChild;
33366 getAnchor : function(){
33367 return this.anchor;
33370 getTextEl : function(){
33371 return this.textNode;
33374 getIconEl : function(){
33375 return this.iconNode;
33378 isChecked : function(){
33379 return this.checkbox ? this.checkbox.checked : false;
33382 updateExpandIcon : function(){
33384 var n = this.node, c1, c2;
33385 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33386 var hasChild = n.hasChildNodes();
33390 c1 = "x-tree-node-collapsed";
33391 c2 = "x-tree-node-expanded";
33394 c1 = "x-tree-node-expanded";
33395 c2 = "x-tree-node-collapsed";
33398 this.removeClass("x-tree-node-leaf");
33399 this.wasLeaf = false;
33401 if(this.c1 != c1 || this.c2 != c2){
33402 Roo.fly(this.elNode).replaceClass(c1, c2);
33403 this.c1 = c1; this.c2 = c2;
33406 // this changes non-leafs into leafs if they have no children.
33407 // it's not very rational behaviour..
33409 if(!this.wasLeaf && this.node.leaf){
33410 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33413 this.wasLeaf = true;
33416 var ecc = "x-tree-ec-icon "+cls;
33417 if(this.ecc != ecc){
33418 this.ecNode.className = ecc;
33424 getChildIndent : function(){
33425 if(!this.childIndent){
33429 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33431 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33433 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33438 this.childIndent = buf.join("");
33440 return this.childIndent;
33443 renderIndent : function(){
33446 var p = this.node.parentNode;
33448 indent = p.ui.getChildIndent();
33450 if(this.indentMarkup != indent){ // don't rerender if not required
33451 this.indentNode.innerHTML = indent;
33452 this.indentMarkup = indent;
33454 this.updateExpandIcon();
33459 Roo.tree.RootTreeNodeUI = function(){
33460 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33462 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33463 render : function(){
33464 if(!this.rendered){
33465 var targetNode = this.node.ownerTree.innerCt.dom;
33466 this.node.expanded = true;
33467 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33468 this.wrap = this.ctNode = targetNode.firstChild;
33471 collapse : function(){
33473 expand : function(){
33477 * Ext JS Library 1.1.1
33478 * Copyright(c) 2006-2007, Ext JS, LLC.
33480 * Originally Released Under LGPL - original licence link has changed is not relivant.
33483 * <script type="text/javascript">
33486 * @class Roo.tree.TreeLoader
33487 * @extends Roo.util.Observable
33488 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33489 * nodes from a specified URL. The response must be a javascript Array definition
33490 * who's elements are node definition objects. eg:
33495 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33496 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33503 * The old style respose with just an array is still supported, but not recommended.
33506 * A server request is sent, and child nodes are loaded only when a node is expanded.
33507 * The loading node's id is passed to the server under the parameter name "node" to
33508 * enable the server to produce the correct child nodes.
33510 * To pass extra parameters, an event handler may be attached to the "beforeload"
33511 * event, and the parameters specified in the TreeLoader's baseParams property:
33513 myTreeLoader.on("beforeload", function(treeLoader, node) {
33514 this.baseParams.category = node.attributes.category;
33517 * This would pass an HTTP parameter called "category" to the server containing
33518 * the value of the Node's "category" attribute.
33520 * Creates a new Treeloader.
33521 * @param {Object} config A config object containing config properties.
33523 Roo.tree.TreeLoader = function(config){
33524 this.baseParams = {};
33525 this.requestMethod = "POST";
33526 Roo.apply(this, config);
33531 * @event beforeload
33532 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33533 * @param {Object} This TreeLoader object.
33534 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33535 * @param {Object} callback The callback function specified in the {@link #load} call.
33540 * Fires when the node has been successfuly loaded.
33541 * @param {Object} This TreeLoader object.
33542 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33543 * @param {Object} response The response object containing the data from the server.
33547 * @event loadexception
33548 * Fires if the network request failed.
33549 * @param {Object} This TreeLoader object.
33550 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33551 * @param {Object} response The response object containing the data from the server.
33553 loadexception : true,
33556 * Fires before a node is created, enabling you to return custom Node types
33557 * @param {Object} This TreeLoader object.
33558 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33563 Roo.tree.TreeLoader.superclass.constructor.call(this);
33566 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33568 * @cfg {String} dataUrl The URL from which to request a Json string which
33569 * specifies an array of node definition object representing the child nodes
33573 * @cfg {String} requestMethod either GET or POST
33574 * defaults to POST (due to BC)
33578 * @cfg {Object} baseParams (optional) An object containing properties which
33579 * specify HTTP parameters to be passed to each request for child nodes.
33582 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33583 * created by this loader. If the attributes sent by the server have an attribute in this object,
33584 * they take priority.
33587 * @cfg {Object} uiProviders (optional) An object containing properties which
33589 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33590 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33591 * <i>uiProvider</i> attribute of a returned child node is a string rather
33592 * than a reference to a TreeNodeUI implementation, this that string value
33593 * is used as a property name in the uiProviders object. You can define the provider named
33594 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33599 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33600 * child nodes before loading.
33602 clearOnLoad : true,
33605 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33606 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33607 * Grid query { data : [ .....] }
33612 * @cfg {String} queryParam (optional)
33613 * Name of the query as it will be passed on the querystring (defaults to 'node')
33614 * eg. the request will be ?node=[id]
33621 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33622 * This is called automatically when a node is expanded, but may be used to reload
33623 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33624 * @param {Roo.tree.TreeNode} node
33625 * @param {Function} callback
33627 load : function(node, callback){
33628 if(this.clearOnLoad){
33629 while(node.firstChild){
33630 node.removeChild(node.firstChild);
33633 if(node.attributes.children){ // preloaded json children
33634 var cs = node.attributes.children;
33635 for(var i = 0, len = cs.length; i < len; i++){
33636 node.appendChild(this.createNode(cs[i]));
33638 if(typeof callback == "function"){
33641 }else if(this.dataUrl){
33642 this.requestData(node, callback);
33646 getParams: function(node){
33647 var buf = [], bp = this.baseParams;
33648 for(var key in bp){
33649 if(typeof bp[key] != "function"){
33650 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33653 var n = this.queryParam === false ? 'node' : this.queryParam;
33654 buf.push(n + "=", encodeURIComponent(node.id));
33655 return buf.join("");
33658 requestData : function(node, callback){
33659 if(this.fireEvent("beforeload", this, node, callback) !== false){
33660 this.transId = Roo.Ajax.request({
33661 method:this.requestMethod,
33662 url: this.dataUrl||this.url,
33663 success: this.handleResponse,
33664 failure: this.handleFailure,
33666 argument: {callback: callback, node: node},
33667 params: this.getParams(node)
33670 // if the load is cancelled, make sure we notify
33671 // the node that we are done
33672 if(typeof callback == "function"){
33678 isLoading : function(){
33679 return this.transId ? true : false;
33682 abort : function(){
33683 if(this.isLoading()){
33684 Roo.Ajax.abort(this.transId);
33689 createNode : function(attr)
33691 // apply baseAttrs, nice idea Corey!
33692 if(this.baseAttrs){
33693 Roo.applyIf(attr, this.baseAttrs);
33695 if(this.applyLoader !== false){
33696 attr.loader = this;
33698 // uiProvider = depreciated..
33700 if(typeof(attr.uiProvider) == 'string'){
33701 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33702 /** eval:var:attr */ eval(attr.uiProvider);
33704 if(typeof(this.uiProviders['default']) != 'undefined') {
33705 attr.uiProvider = this.uiProviders['default'];
33708 this.fireEvent('create', this, attr);
33710 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33712 new Roo.tree.TreeNode(attr) :
33713 new Roo.tree.AsyncTreeNode(attr));
33716 processResponse : function(response, node, callback)
33718 var json = response.responseText;
33721 var o = Roo.decode(json);
33723 if (this.root === false && typeof(o.success) != undefined) {
33724 this.root = 'data'; // the default behaviour for list like data..
33727 if (this.root !== false && !o.success) {
33728 // it's a failure condition.
33729 var a = response.argument;
33730 this.fireEvent("loadexception", this, a.node, response);
33731 Roo.log("Load failed - should have a handler really");
33737 if (this.root !== false) {
33741 for(var i = 0, len = o.length; i < len; i++){
33742 var n = this.createNode(o[i]);
33744 node.appendChild(n);
33747 if(typeof callback == "function"){
33748 callback(this, node);
33751 this.handleFailure(response);
33755 handleResponse : function(response){
33756 this.transId = false;
33757 var a = response.argument;
33758 this.processResponse(response, a.node, a.callback);
33759 this.fireEvent("load", this, a.node, response);
33762 handleFailure : function(response)
33764 // should handle failure better..
33765 this.transId = false;
33766 var a = response.argument;
33767 this.fireEvent("loadexception", this, a.node, response);
33768 if(typeof a.callback == "function"){
33769 a.callback(this, a.node);
33774 * Ext JS Library 1.1.1
33775 * Copyright(c) 2006-2007, Ext JS, LLC.
33777 * Originally Released Under LGPL - original licence link has changed is not relivant.
33780 * <script type="text/javascript">
33784 * @class Roo.tree.TreeFilter
33785 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33786 * @param {TreePanel} tree
33787 * @param {Object} config (optional)
33789 Roo.tree.TreeFilter = function(tree, config){
33791 this.filtered = {};
33792 Roo.apply(this, config);
33795 Roo.tree.TreeFilter.prototype = {
33802 * Filter the data by a specific attribute.
33803 * @param {String/RegExp} value Either string that the attribute value
33804 * should start with or a RegExp to test against the attribute
33805 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33806 * @param {TreeNode} startNode (optional) The node to start the filter at.
33808 filter : function(value, attr, startNode){
33809 attr = attr || "text";
33811 if(typeof value == "string"){
33812 var vlen = value.length;
33813 // auto clear empty filter
33814 if(vlen == 0 && this.clearBlank){
33818 value = value.toLowerCase();
33820 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33822 }else if(value.exec){ // regex?
33824 return value.test(n.attributes[attr]);
33827 throw 'Illegal filter type, must be string or regex';
33829 this.filterBy(f, null, startNode);
33833 * Filter by a function. The passed function will be called with each
33834 * node in the tree (or from the startNode). If the function returns true, the node is kept
33835 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33836 * @param {Function} fn The filter function
33837 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33839 filterBy : function(fn, scope, startNode){
33840 startNode = startNode || this.tree.root;
33841 if(this.autoClear){
33844 var af = this.filtered, rv = this.reverse;
33845 var f = function(n){
33846 if(n == startNode){
33852 var m = fn.call(scope || n, n);
33860 startNode.cascade(f);
33863 if(typeof id != "function"){
33865 if(n && n.parentNode){
33866 n.parentNode.removeChild(n);
33874 * Clears the current filter. Note: with the "remove" option
33875 * set a filter cannot be cleared.
33877 clear : function(){
33879 var af = this.filtered;
33881 if(typeof id != "function"){
33888 this.filtered = {};
33893 * Ext JS Library 1.1.1
33894 * Copyright(c) 2006-2007, Ext JS, LLC.
33896 * Originally Released Under LGPL - original licence link has changed is not relivant.
33899 * <script type="text/javascript">
33904 * @class Roo.tree.TreeSorter
33905 * Provides sorting of nodes in a TreePanel
33907 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33908 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33909 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33910 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33911 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33912 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33914 * @param {TreePanel} tree
33915 * @param {Object} config
33917 Roo.tree.TreeSorter = function(tree, config){
33918 Roo.apply(this, config);
33919 tree.on("beforechildrenrendered", this.doSort, this);
33920 tree.on("append", this.updateSort, this);
33921 tree.on("insert", this.updateSort, this);
33923 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33924 var p = this.property || "text";
33925 var sortType = this.sortType;
33926 var fs = this.folderSort;
33927 var cs = this.caseSensitive === true;
33928 var leafAttr = this.leafAttr || 'leaf';
33930 this.sortFn = function(n1, n2){
33932 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33935 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33939 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33940 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33942 return dsc ? +1 : -1;
33944 return dsc ? -1 : +1;
33951 Roo.tree.TreeSorter.prototype = {
33952 doSort : function(node){
33953 node.sort(this.sortFn);
33956 compareNodes : function(n1, n2){
33957 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33960 updateSort : function(tree, node){
33961 if(node.childrenRendered){
33962 this.doSort.defer(1, this, [node]);
33967 * Ext JS Library 1.1.1
33968 * Copyright(c) 2006-2007, Ext JS, LLC.
33970 * Originally Released Under LGPL - original licence link has changed is not relivant.
33973 * <script type="text/javascript">
33976 if(Roo.dd.DropZone){
33978 Roo.tree.TreeDropZone = function(tree, config){
33979 this.allowParentInsert = false;
33980 this.allowContainerDrop = false;
33981 this.appendOnly = false;
33982 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33984 this.lastInsertClass = "x-tree-no-status";
33985 this.dragOverData = {};
33988 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33989 ddGroup : "TreeDD",
33992 expandDelay : 1000,
33994 expandNode : function(node){
33995 if(node.hasChildNodes() && !node.isExpanded()){
33996 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34000 queueExpand : function(node){
34001 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34004 cancelExpand : function(){
34005 if(this.expandProcId){
34006 clearTimeout(this.expandProcId);
34007 this.expandProcId = false;
34011 isValidDropPoint : function(n, pt, dd, e, data){
34012 if(!n || !data){ return false; }
34013 var targetNode = n.node;
34014 var dropNode = data.node;
34015 // default drop rules
34016 if(!(targetNode && targetNode.isTarget && pt)){
34019 if(pt == "append" && targetNode.allowChildren === false){
34022 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34025 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34028 // reuse the object
34029 var overEvent = this.dragOverData;
34030 overEvent.tree = this.tree;
34031 overEvent.target = targetNode;
34032 overEvent.data = data;
34033 overEvent.point = pt;
34034 overEvent.source = dd;
34035 overEvent.rawEvent = e;
34036 overEvent.dropNode = dropNode;
34037 overEvent.cancel = false;
34038 var result = this.tree.fireEvent("nodedragover", overEvent);
34039 return overEvent.cancel === false && result !== false;
34042 getDropPoint : function(e, n, dd)
34046 return tn.allowChildren !== false ? "append" : false; // always append for root
34048 var dragEl = n.ddel;
34049 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34050 var y = Roo.lib.Event.getPageY(e);
34051 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34053 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34054 var noAppend = tn.allowChildren === false;
34055 if(this.appendOnly || tn.parentNode.allowChildren === false){
34056 return noAppend ? false : "append";
34058 var noBelow = false;
34059 if(!this.allowParentInsert){
34060 noBelow = tn.hasChildNodes() && tn.isExpanded();
34062 var q = (b - t) / (noAppend ? 2 : 3);
34063 if(y >= t && y < (t + q)){
34065 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34072 onNodeEnter : function(n, dd, e, data)
34074 this.cancelExpand();
34077 onNodeOver : function(n, dd, e, data)
34080 var pt = this.getDropPoint(e, n, dd);
34083 // auto node expand check
34084 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34085 this.queueExpand(node);
34086 }else if(pt != "append"){
34087 this.cancelExpand();
34090 // set the insert point style on the target node
34091 var returnCls = this.dropNotAllowed;
34092 if(this.isValidDropPoint(n, pt, dd, e, data)){
34097 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34098 cls = "x-tree-drag-insert-above";
34099 }else if(pt == "below"){
34100 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34101 cls = "x-tree-drag-insert-below";
34103 returnCls = "x-tree-drop-ok-append";
34104 cls = "x-tree-drag-append";
34106 if(this.lastInsertClass != cls){
34107 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34108 this.lastInsertClass = cls;
34115 onNodeOut : function(n, dd, e, data){
34117 this.cancelExpand();
34118 this.removeDropIndicators(n);
34121 onNodeDrop : function(n, dd, e, data){
34122 var point = this.getDropPoint(e, n, dd);
34123 var targetNode = n.node;
34124 targetNode.ui.startDrop();
34125 if(!this.isValidDropPoint(n, point, dd, e, data)){
34126 targetNode.ui.endDrop();
34129 // first try to find the drop node
34130 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34133 target: targetNode,
34138 dropNode: dropNode,
34141 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34142 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34143 targetNode.ui.endDrop();
34146 // allow target changing
34147 targetNode = dropEvent.target;
34148 if(point == "append" && !targetNode.isExpanded()){
34149 targetNode.expand(false, null, function(){
34150 this.completeDrop(dropEvent);
34151 }.createDelegate(this));
34153 this.completeDrop(dropEvent);
34158 completeDrop : function(de){
34159 var ns = de.dropNode, p = de.point, t = de.target;
34160 if(!(ns instanceof Array)){
34164 for(var i = 0, len = ns.length; i < len; i++){
34167 t.parentNode.insertBefore(n, t);
34168 }else if(p == "below"){
34169 t.parentNode.insertBefore(n, t.nextSibling);
34175 if(this.tree.hlDrop){
34179 this.tree.fireEvent("nodedrop", de);
34182 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34183 if(this.tree.hlDrop){
34184 dropNode.ui.focus();
34185 dropNode.ui.highlight();
34187 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34190 getTree : function(){
34194 removeDropIndicators : function(n){
34197 Roo.fly(el).removeClass([
34198 "x-tree-drag-insert-above",
34199 "x-tree-drag-insert-below",
34200 "x-tree-drag-append"]);
34201 this.lastInsertClass = "_noclass";
34205 beforeDragDrop : function(target, e, id){
34206 this.cancelExpand();
34210 afterRepair : function(data){
34211 if(data && Roo.enableFx){
34212 data.node.ui.highlight();
34222 * Ext JS Library 1.1.1
34223 * Copyright(c) 2006-2007, Ext JS, LLC.
34225 * Originally Released Under LGPL - original licence link has changed is not relivant.
34228 * <script type="text/javascript">
34232 if(Roo.dd.DragZone){
34233 Roo.tree.TreeDragZone = function(tree, config){
34234 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34238 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34239 ddGroup : "TreeDD",
34241 onBeforeDrag : function(data, e){
34243 return n && n.draggable && !n.disabled;
34247 onInitDrag : function(e){
34248 var data = this.dragData;
34249 this.tree.getSelectionModel().select(data.node);
34250 this.proxy.update("");
34251 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34252 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34255 getRepairXY : function(e, data){
34256 return data.node.ui.getDDRepairXY();
34259 onEndDrag : function(data, e){
34260 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34265 onValidDrop : function(dd, e, id){
34266 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34270 beforeInvalidDrop : function(e, id){
34271 // this scrolls the original position back into view
34272 var sm = this.tree.getSelectionModel();
34273 sm.clearSelections();
34274 sm.select(this.dragData.node);
34279 * Ext JS Library 1.1.1
34280 * Copyright(c) 2006-2007, Ext JS, LLC.
34282 * Originally Released Under LGPL - original licence link has changed is not relivant.
34285 * <script type="text/javascript">
34288 * @class Roo.tree.TreeEditor
34289 * @extends Roo.Editor
34290 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34291 * as the editor field.
34293 * @param {Object} config (used to be the tree panel.)
34294 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34296 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34297 * @cfg {Roo.form.TextField|Object} field The field configuration
34301 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34304 if (oldconfig) { // old style..
34305 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34308 tree = config.tree;
34309 config.field = config.field || {};
34310 config.field.xtype = 'TextField';
34311 field = Roo.factory(config.field, Roo.form);
34313 config = config || {};
34318 * @event beforenodeedit
34319 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34320 * false from the handler of this event.
34321 * @param {Editor} this
34322 * @param {Roo.tree.Node} node
34324 "beforenodeedit" : true
34328 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34332 tree.on('beforeclick', this.beforeNodeClick, this);
34333 tree.getTreeEl().on('mousedown', this.hide, this);
34334 this.on('complete', this.updateNode, this);
34335 this.on('beforestartedit', this.fitToTree, this);
34336 this.on('startedit', this.bindScroll, this, {delay:10});
34337 this.on('specialkey', this.onSpecialKey, this);
34340 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34342 * @cfg {String} alignment
34343 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34349 * @cfg {Boolean} hideEl
34350 * True to hide the bound element while the editor is displayed (defaults to false)
34354 * @cfg {String} cls
34355 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34357 cls: "x-small-editor x-tree-editor",
34359 * @cfg {Boolean} shim
34360 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34366 * @cfg {Number} maxWidth
34367 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34368 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34369 * scroll and client offsets into account prior to each edit.
34376 fitToTree : function(ed, el){
34377 var td = this.tree.getTreeEl().dom, nd = el.dom;
34378 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34379 td.scrollLeft = nd.offsetLeft;
34383 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34384 this.setSize(w, '');
34386 return this.fireEvent('beforenodeedit', this, this.editNode);
34391 triggerEdit : function(node){
34392 this.completeEdit();
34393 this.editNode = node;
34394 this.startEdit(node.ui.textNode, node.text);
34398 bindScroll : function(){
34399 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34403 beforeNodeClick : function(node, e){
34404 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34405 this.lastClick = new Date();
34406 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34408 this.triggerEdit(node);
34415 updateNode : function(ed, value){
34416 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34417 this.editNode.setText(value);
34421 onHide : function(){
34422 Roo.tree.TreeEditor.superclass.onHide.call(this);
34424 this.editNode.ui.focus();
34429 onSpecialKey : function(field, e){
34430 var k = e.getKey();
34434 }else if(k == e.ENTER && !e.hasModifier()){
34436 this.completeEdit();
34439 });//<Script type="text/javascript">
34442 * Ext JS Library 1.1.1
34443 * Copyright(c) 2006-2007, Ext JS, LLC.
34445 * Originally Released Under LGPL - original licence link has changed is not relivant.
34448 * <script type="text/javascript">
34452 * Not documented??? - probably should be...
34455 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34456 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34458 renderElements : function(n, a, targetNode, bulkRender){
34459 //consel.log("renderElements?");
34460 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34462 var t = n.getOwnerTree();
34463 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34465 var cols = t.columns;
34466 var bw = t.borderWidth;
34468 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34469 var cb = typeof a.checked == "boolean";
34470 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34471 var colcls = 'x-t-' + tid + '-c0';
34473 '<li class="x-tree-node">',
34476 '<div class="x-tree-node-el ', a.cls,'">',
34478 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34481 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34482 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34483 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34484 (a.icon ? ' x-tree-node-inline-icon' : ''),
34485 (a.iconCls ? ' '+a.iconCls : ''),
34486 '" unselectable="on" />',
34487 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34488 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34490 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34491 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34492 '<span unselectable="on" qtip="' + tx + '">',
34496 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34497 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34499 for(var i = 1, len = cols.length; i < len; i++){
34501 colcls = 'x-t-' + tid + '-c' +i;
34502 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34503 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34504 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34510 '<div class="x-clear"></div></div>',
34511 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34514 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34515 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34516 n.nextSibling.ui.getEl(), buf.join(""));
34518 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34520 var el = this.wrap.firstChild;
34522 this.elNode = el.firstChild;
34523 this.ranchor = el.childNodes[1];
34524 this.ctNode = this.wrap.childNodes[1];
34525 var cs = el.firstChild.childNodes;
34526 this.indentNode = cs[0];
34527 this.ecNode = cs[1];
34528 this.iconNode = cs[2];
34531 this.checkbox = cs[3];
34534 this.anchor = cs[index];
34536 this.textNode = cs[index].firstChild;
34538 //el.on("click", this.onClick, this);
34539 //el.on("dblclick", this.onDblClick, this);
34542 // console.log(this);
34544 initEvents : function(){
34545 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34548 var a = this.ranchor;
34550 var el = Roo.get(a);
34552 if(Roo.isOpera){ // opera render bug ignores the CSS
34553 el.setStyle("text-decoration", "none");
34556 el.on("click", this.onClick, this);
34557 el.on("dblclick", this.onDblClick, this);
34558 el.on("contextmenu", this.onContextMenu, this);
34562 /*onSelectedChange : function(state){
34565 this.addClass("x-tree-selected");
34568 this.removeClass("x-tree-selected");
34571 addClass : function(cls){
34573 Roo.fly(this.elRow).addClass(cls);
34579 removeClass : function(cls){
34581 Roo.fly(this.elRow).removeClass(cls);
34587 });//<Script type="text/javascript">
34591 * Ext JS Library 1.1.1
34592 * Copyright(c) 2006-2007, Ext JS, LLC.
34594 * Originally Released Under LGPL - original licence link has changed is not relivant.
34597 * <script type="text/javascript">
34602 * @class Roo.tree.ColumnTree
34603 * @extends Roo.data.TreePanel
34604 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34605 * @cfg {int} borderWidth compined right/left border allowance
34607 * @param {String/HTMLElement/Element} el The container element
34608 * @param {Object} config
34610 Roo.tree.ColumnTree = function(el, config)
34612 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34616 * Fire this event on a container when it resizes
34617 * @param {int} w Width
34618 * @param {int} h Height
34622 this.on('resize', this.onResize, this);
34625 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34629 borderWidth: Roo.isBorderBox ? 0 : 2,
34632 render : function(){
34633 // add the header.....
34635 Roo.tree.ColumnTree.superclass.render.apply(this);
34637 this.el.addClass('x-column-tree');
34639 this.headers = this.el.createChild(
34640 {cls:'x-tree-headers'},this.innerCt.dom);
34642 var cols = this.columns, c;
34643 var totalWidth = 0;
34645 var len = cols.length;
34646 for(var i = 0; i < len; i++){
34648 totalWidth += c.width;
34649 this.headEls.push(this.headers.createChild({
34650 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34652 cls:'x-tree-hd-text',
34655 style:'width:'+(c.width-this.borderWidth)+'px;'
34658 this.headers.createChild({cls:'x-clear'});
34659 // prevent floats from wrapping when clipped
34660 this.headers.setWidth(totalWidth);
34661 //this.innerCt.setWidth(totalWidth);
34662 this.innerCt.setStyle({ overflow: 'auto' });
34663 this.onResize(this.width, this.height);
34667 onResize : function(w,h)
34672 this.innerCt.setWidth(this.width);
34673 this.innerCt.setHeight(this.height-20);
34676 var cols = this.columns, c;
34677 var totalWidth = 0;
34679 var len = cols.length;
34680 for(var i = 0; i < len; i++){
34682 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34683 // it's the expander..
34684 expEl = this.headEls[i];
34687 totalWidth += c.width;
34691 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34693 this.headers.setWidth(w-20);
34702 * Ext JS Library 1.1.1
34703 * Copyright(c) 2006-2007, Ext JS, LLC.
34705 * Originally Released Under LGPL - original licence link has changed is not relivant.
34708 * <script type="text/javascript">
34712 * @class Roo.menu.Menu
34713 * @extends Roo.util.Observable
34714 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34715 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34717 * Creates a new Menu
34718 * @param {Object} config Configuration options
34720 Roo.menu.Menu = function(config){
34721 Roo.apply(this, config);
34722 this.id = this.id || Roo.id();
34725 * @event beforeshow
34726 * Fires before this menu is displayed
34727 * @param {Roo.menu.Menu} this
34731 * @event beforehide
34732 * Fires before this menu is hidden
34733 * @param {Roo.menu.Menu} this
34738 * Fires after this menu is displayed
34739 * @param {Roo.menu.Menu} this
34744 * Fires after this menu is hidden
34745 * @param {Roo.menu.Menu} this
34750 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34751 * @param {Roo.menu.Menu} this
34752 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34753 * @param {Roo.EventObject} e
34758 * Fires when the mouse is hovering over this menu
34759 * @param {Roo.menu.Menu} this
34760 * @param {Roo.EventObject} e
34761 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34766 * Fires when the mouse exits this menu
34767 * @param {Roo.menu.Menu} this
34768 * @param {Roo.EventObject} e
34769 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34774 * Fires when a menu item contained in this menu is clicked
34775 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34776 * @param {Roo.EventObject} e
34780 if (this.registerMenu) {
34781 Roo.menu.MenuMgr.register(this);
34784 var mis = this.items;
34785 this.items = new Roo.util.MixedCollection();
34787 this.add.apply(this, mis);
34791 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34793 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34797 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34798 * for bottom-right shadow (defaults to "sides")
34802 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34803 * this menu (defaults to "tl-tr?")
34805 subMenuAlign : "tl-tr?",
34807 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34808 * relative to its element of origin (defaults to "tl-bl?")
34810 defaultAlign : "tl-bl?",
34812 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34814 allowOtherMenus : false,
34816 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34818 registerMenu : true,
34823 render : function(){
34827 var el = this.el = new Roo.Layer({
34829 shadow:this.shadow,
34831 parentEl: this.parentEl || document.body,
34835 this.keyNav = new Roo.menu.MenuNav(this);
34838 el.addClass("x-menu-plain");
34841 el.addClass(this.cls);
34843 // generic focus element
34844 this.focusEl = el.createChild({
34845 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34847 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34848 ul.on("click", this.onClick, this);
34849 ul.on("mouseover", this.onMouseOver, this);
34850 ul.on("mouseout", this.onMouseOut, this);
34851 this.items.each(function(item){
34856 var li = document.createElement("li");
34857 li.className = "x-menu-list-item";
34858 ul.dom.appendChild(li);
34859 item.render(li, this);
34866 autoWidth : function(){
34867 var el = this.el, ul = this.ul;
34871 var w = this.width;
34874 }else if(Roo.isIE){
34875 el.setWidth(this.minWidth);
34876 var t = el.dom.offsetWidth; // force recalc
34877 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34882 delayAutoWidth : function(){
34885 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34887 this.awTask.delay(20);
34892 findTargetItem : function(e){
34893 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34894 if(t && t.menuItemId){
34895 return this.items.get(t.menuItemId);
34900 onClick : function(e){
34902 if(t = this.findTargetItem(e)){
34904 this.fireEvent("click", this, t, e);
34909 setActiveItem : function(item, autoExpand){
34910 if(item != this.activeItem){
34911 if(this.activeItem){
34912 this.activeItem.deactivate();
34914 this.activeItem = item;
34915 item.activate(autoExpand);
34916 }else if(autoExpand){
34922 tryActivate : function(start, step){
34923 var items = this.items;
34924 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34925 var item = items.get(i);
34926 if(!item.disabled && item.canActivate){
34927 this.setActiveItem(item, false);
34935 onMouseOver : function(e){
34937 if(t = this.findTargetItem(e)){
34938 if(t.canActivate && !t.disabled){
34939 this.setActiveItem(t, true);
34942 this.fireEvent("mouseover", this, e, t);
34946 onMouseOut : function(e){
34948 if(t = this.findTargetItem(e)){
34949 if(t == this.activeItem && t.shouldDeactivate(e)){
34950 this.activeItem.deactivate();
34951 delete this.activeItem;
34954 this.fireEvent("mouseout", this, e, t);
34958 * Read-only. Returns true if the menu is currently displayed, else false.
34961 isVisible : function(){
34962 return this.el && !this.hidden;
34966 * Displays this menu relative to another element
34967 * @param {String/HTMLElement/Roo.Element} element The element to align to
34968 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34969 * the element (defaults to this.defaultAlign)
34970 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34972 show : function(el, pos, parentMenu){
34973 this.parentMenu = parentMenu;
34977 this.fireEvent("beforeshow", this);
34978 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34982 * Displays this menu at a specific xy position
34983 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34984 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34986 showAt : function(xy, parentMenu, /* private: */_e){
34987 this.parentMenu = parentMenu;
34992 this.fireEvent("beforeshow", this);
34993 xy = this.el.adjustForConstraints(xy);
34997 this.hidden = false;
34999 this.fireEvent("show", this);
35002 focus : function(){
35004 this.doFocus.defer(50, this);
35008 doFocus : function(){
35010 this.focusEl.focus();
35015 * Hides this menu and optionally all parent menus
35016 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35018 hide : function(deep){
35019 if(this.el && this.isVisible()){
35020 this.fireEvent("beforehide", this);
35021 if(this.activeItem){
35022 this.activeItem.deactivate();
35023 this.activeItem = null;
35026 this.hidden = true;
35027 this.fireEvent("hide", this);
35029 if(deep === true && this.parentMenu){
35030 this.parentMenu.hide(true);
35035 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35036 * Any of the following are valid:
35038 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35039 * <li>An HTMLElement object which will be converted to a menu item</li>
35040 * <li>A menu item config object that will be created as a new menu item</li>
35041 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35042 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35047 var menu = new Roo.menu.Menu();
35049 // Create a menu item to add by reference
35050 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35052 // Add a bunch of items at once using different methods.
35053 // Only the last item added will be returned.
35054 var item = menu.add(
35055 menuItem, // add existing item by ref
35056 'Dynamic Item', // new TextItem
35057 '-', // new separator
35058 { text: 'Config Item' } // new item by config
35061 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35062 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35065 var a = arguments, l = a.length, item;
35066 for(var i = 0; i < l; i++){
35068 if ((typeof(el) == "object") && el.xtype && el.xns) {
35069 el = Roo.factory(el, Roo.menu);
35072 if(el.render){ // some kind of Item
35073 item = this.addItem(el);
35074 }else if(typeof el == "string"){ // string
35075 if(el == "separator" || el == "-"){
35076 item = this.addSeparator();
35078 item = this.addText(el);
35080 }else if(el.tagName || el.el){ // element
35081 item = this.addElement(el);
35082 }else if(typeof el == "object"){ // must be menu item config?
35083 item = this.addMenuItem(el);
35090 * Returns this menu's underlying {@link Roo.Element} object
35091 * @return {Roo.Element} The element
35093 getEl : function(){
35101 * Adds a separator bar to the menu
35102 * @return {Roo.menu.Item} The menu item that was added
35104 addSeparator : function(){
35105 return this.addItem(new Roo.menu.Separator());
35109 * Adds an {@link Roo.Element} object to the menu
35110 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35111 * @return {Roo.menu.Item} The menu item that was added
35113 addElement : function(el){
35114 return this.addItem(new Roo.menu.BaseItem(el));
35118 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35119 * @param {Roo.menu.Item} item The menu item to add
35120 * @return {Roo.menu.Item} The menu item that was added
35122 addItem : function(item){
35123 this.items.add(item);
35125 var li = document.createElement("li");
35126 li.className = "x-menu-list-item";
35127 this.ul.dom.appendChild(li);
35128 item.render(li, this);
35129 this.delayAutoWidth();
35135 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35136 * @param {Object} config A MenuItem config object
35137 * @return {Roo.menu.Item} The menu item that was added
35139 addMenuItem : function(config){
35140 if(!(config instanceof Roo.menu.Item)){
35141 if(typeof config.checked == "boolean"){ // must be check menu item config?
35142 config = new Roo.menu.CheckItem(config);
35144 config = new Roo.menu.Item(config);
35147 return this.addItem(config);
35151 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35152 * @param {String} text The text to display in the menu item
35153 * @return {Roo.menu.Item} The menu item that was added
35155 addText : function(text){
35156 return this.addItem(new Roo.menu.TextItem({ text : text }));
35160 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35161 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35162 * @param {Roo.menu.Item} item The menu item to add
35163 * @return {Roo.menu.Item} The menu item that was added
35165 insert : function(index, item){
35166 this.items.insert(index, item);
35168 var li = document.createElement("li");
35169 li.className = "x-menu-list-item";
35170 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35171 item.render(li, this);
35172 this.delayAutoWidth();
35178 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35179 * @param {Roo.menu.Item} item The menu item to remove
35181 remove : function(item){
35182 this.items.removeKey(item.id);
35187 * Removes and destroys all items in the menu
35189 removeAll : function(){
35191 while(f = this.items.first()){
35197 // MenuNav is a private utility class used internally by the Menu
35198 Roo.menu.MenuNav = function(menu){
35199 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35200 this.scope = this.menu = menu;
35203 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35204 doRelay : function(e, h){
35205 var k = e.getKey();
35206 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35207 this.menu.tryActivate(0, 1);
35210 return h.call(this.scope || this, e, this.menu);
35213 up : function(e, m){
35214 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35215 m.tryActivate(m.items.length-1, -1);
35219 down : function(e, m){
35220 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35221 m.tryActivate(0, 1);
35225 right : function(e, m){
35227 m.activeItem.expandMenu(true);
35231 left : function(e, m){
35233 if(m.parentMenu && m.parentMenu.activeItem){
35234 m.parentMenu.activeItem.activate();
35238 enter : function(e, m){
35240 e.stopPropagation();
35241 m.activeItem.onClick(e);
35242 m.fireEvent("click", this, m.activeItem);
35248 * Ext JS Library 1.1.1
35249 * Copyright(c) 2006-2007, Ext JS, LLC.
35251 * Originally Released Under LGPL - original licence link has changed is not relivant.
35254 * <script type="text/javascript">
35258 * @class Roo.menu.MenuMgr
35259 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35262 Roo.menu.MenuMgr = function(){
35263 var menus, active, groups = {}, attached = false, lastShow = new Date();
35265 // private - called when first menu is created
35268 active = new Roo.util.MixedCollection();
35269 Roo.get(document).addKeyListener(27, function(){
35270 if(active.length > 0){
35277 function hideAll(){
35278 if(active && active.length > 0){
35279 var c = active.clone();
35280 c.each(function(m){
35287 function onHide(m){
35289 if(active.length < 1){
35290 Roo.get(document).un("mousedown", onMouseDown);
35296 function onShow(m){
35297 var last = active.last();
35298 lastShow = new Date();
35301 Roo.get(document).on("mousedown", onMouseDown);
35305 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35306 m.parentMenu.activeChild = m;
35307 }else if(last && last.isVisible()){
35308 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35313 function onBeforeHide(m){
35315 m.activeChild.hide();
35317 if(m.autoHideTimer){
35318 clearTimeout(m.autoHideTimer);
35319 delete m.autoHideTimer;
35324 function onBeforeShow(m){
35325 var pm = m.parentMenu;
35326 if(!pm && !m.allowOtherMenus){
35328 }else if(pm && pm.activeChild && active != m){
35329 pm.activeChild.hide();
35334 function onMouseDown(e){
35335 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35341 function onBeforeCheck(mi, state){
35343 var g = groups[mi.group];
35344 for(var i = 0, l = g.length; i < l; i++){
35346 g[i].setChecked(false);
35355 * Hides all menus that are currently visible
35357 hideAll : function(){
35362 register : function(menu){
35366 menus[menu.id] = menu;
35367 menu.on("beforehide", onBeforeHide);
35368 menu.on("hide", onHide);
35369 menu.on("beforeshow", onBeforeShow);
35370 menu.on("show", onShow);
35371 var g = menu.group;
35372 if(g && menu.events["checkchange"]){
35376 groups[g].push(menu);
35377 menu.on("checkchange", onCheck);
35382 * Returns a {@link Roo.menu.Menu} object
35383 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35384 * be used to generate and return a new Menu instance.
35386 get : function(menu){
35387 if(typeof menu == "string"){ // menu id
35388 return menus[menu];
35389 }else if(menu.events){ // menu instance
35391 }else if(typeof menu.length == 'number'){ // array of menu items?
35392 return new Roo.menu.Menu({items:menu});
35393 }else{ // otherwise, must be a config
35394 return new Roo.menu.Menu(menu);
35399 unregister : function(menu){
35400 delete menus[menu.id];
35401 menu.un("beforehide", onBeforeHide);
35402 menu.un("hide", onHide);
35403 menu.un("beforeshow", onBeforeShow);
35404 menu.un("show", onShow);
35405 var g = menu.group;
35406 if(g && menu.events["checkchange"]){
35407 groups[g].remove(menu);
35408 menu.un("checkchange", onCheck);
35413 registerCheckable : function(menuItem){
35414 var g = menuItem.group;
35419 groups[g].push(menuItem);
35420 menuItem.on("beforecheckchange", onBeforeCheck);
35425 unregisterCheckable : function(menuItem){
35426 var g = menuItem.group;
35428 groups[g].remove(menuItem);
35429 menuItem.un("beforecheckchange", onBeforeCheck);
35435 * Ext JS Library 1.1.1
35436 * Copyright(c) 2006-2007, Ext JS, LLC.
35438 * Originally Released Under LGPL - original licence link has changed is not relivant.
35441 * <script type="text/javascript">
35446 * @class Roo.menu.BaseItem
35447 * @extends Roo.Component
35448 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35449 * management and base configuration options shared by all menu components.
35451 * Creates a new BaseItem
35452 * @param {Object} config Configuration options
35454 Roo.menu.BaseItem = function(config){
35455 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35460 * Fires when this item is clicked
35461 * @param {Roo.menu.BaseItem} this
35462 * @param {Roo.EventObject} e
35467 * Fires when this item is activated
35468 * @param {Roo.menu.BaseItem} this
35472 * @event deactivate
35473 * Fires when this item is deactivated
35474 * @param {Roo.menu.BaseItem} this
35480 this.on("click", this.handler, this.scope, true);
35484 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35486 * @cfg {Function} handler
35487 * A function that will handle the click event of this menu item (defaults to undefined)
35490 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35492 canActivate : false,
35495 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
35500 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35502 activeClass : "x-menu-item-active",
35504 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35506 hideOnClick : true,
35508 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35513 ctype: "Roo.menu.BaseItem",
35516 actionMode : "container",
35519 render : function(container, parentMenu){
35520 this.parentMenu = parentMenu;
35521 Roo.menu.BaseItem.superclass.render.call(this, container);
35522 this.container.menuItemId = this.id;
35526 onRender : function(container, position){
35527 this.el = Roo.get(this.el);
35528 container.dom.appendChild(this.el.dom);
35532 onClick : function(e){
35533 if(!this.disabled && this.fireEvent("click", this, e) !== false
35534 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35535 this.handleClick(e);
35542 activate : function(){
35546 var li = this.container;
35547 li.addClass(this.activeClass);
35548 this.region = li.getRegion().adjust(2, 2, -2, -2);
35549 this.fireEvent("activate", this);
35554 deactivate : function(){
35555 this.container.removeClass(this.activeClass);
35556 this.fireEvent("deactivate", this);
35560 shouldDeactivate : function(e){
35561 return !this.region || !this.region.contains(e.getPoint());
35565 handleClick : function(e){
35566 if(this.hideOnClick){
35567 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35572 expandMenu : function(autoActivate){
35577 hideMenu : function(){
35582 * Ext JS Library 1.1.1
35583 * Copyright(c) 2006-2007, Ext JS, LLC.
35585 * Originally Released Under LGPL - original licence link has changed is not relivant.
35588 * <script type="text/javascript">
35592 * @class Roo.menu.Adapter
35593 * @extends Roo.menu.BaseItem
35594 * 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.
35595 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35597 * Creates a new Adapter
35598 * @param {Object} config Configuration options
35600 Roo.menu.Adapter = function(component, config){
35601 Roo.menu.Adapter.superclass.constructor.call(this, config);
35602 this.component = component;
35604 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35606 canActivate : true,
35609 onRender : function(container, position){
35610 this.component.render(container);
35611 this.el = this.component.getEl();
35615 activate : function(){
35619 this.component.focus();
35620 this.fireEvent("activate", this);
35625 deactivate : function(){
35626 this.fireEvent("deactivate", this);
35630 disable : function(){
35631 this.component.disable();
35632 Roo.menu.Adapter.superclass.disable.call(this);
35636 enable : function(){
35637 this.component.enable();
35638 Roo.menu.Adapter.superclass.enable.call(this);
35642 * Ext JS Library 1.1.1
35643 * Copyright(c) 2006-2007, Ext JS, LLC.
35645 * Originally Released Under LGPL - original licence link has changed is not relivant.
35648 * <script type="text/javascript">
35652 * @class Roo.menu.TextItem
35653 * @extends Roo.menu.BaseItem
35654 * Adds a static text string to a menu, usually used as either a heading or group separator.
35655 * Note: old style constructor with text is still supported.
35658 * Creates a new TextItem
35659 * @param {Object} cfg Configuration
35661 Roo.menu.TextItem = function(cfg){
35662 if (typeof(cfg) == 'string') {
35665 Roo.apply(this,cfg);
35668 Roo.menu.TextItem.superclass.constructor.call(this);
35671 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35673 * @cfg {Boolean} text Text to show on item.
35678 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35680 hideOnClick : false,
35682 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35684 itemCls : "x-menu-text",
35687 onRender : function(){
35688 var s = document.createElement("span");
35689 s.className = this.itemCls;
35690 s.innerHTML = this.text;
35692 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35696 * Ext JS Library 1.1.1
35697 * Copyright(c) 2006-2007, Ext JS, LLC.
35699 * Originally Released Under LGPL - original licence link has changed is not relivant.
35702 * <script type="text/javascript">
35706 * @class Roo.menu.Separator
35707 * @extends Roo.menu.BaseItem
35708 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35709 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35711 * @param {Object} config Configuration options
35713 Roo.menu.Separator = function(config){
35714 Roo.menu.Separator.superclass.constructor.call(this, config);
35717 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35719 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35721 itemCls : "x-menu-sep",
35723 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35725 hideOnClick : false,
35728 onRender : function(li){
35729 var s = document.createElement("span");
35730 s.className = this.itemCls;
35731 s.innerHTML = " ";
35733 li.addClass("x-menu-sep-li");
35734 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35738 * Ext JS Library 1.1.1
35739 * Copyright(c) 2006-2007, Ext JS, LLC.
35741 * Originally Released Under LGPL - original licence link has changed is not relivant.
35744 * <script type="text/javascript">
35747 * @class Roo.menu.Item
35748 * @extends Roo.menu.BaseItem
35749 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35750 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35751 * activation and click handling.
35753 * Creates a new Item
35754 * @param {Object} config Configuration options
35756 Roo.menu.Item = function(config){
35757 Roo.menu.Item.superclass.constructor.call(this, config);
35759 this.menu = Roo.menu.MenuMgr.get(this.menu);
35762 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35765 * @cfg {String} text
35766 * The text to show on the menu item.
35770 * @cfg {String} HTML to render in menu
35771 * The text to show on the menu item (HTML version).
35775 * @cfg {String} icon
35776 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35780 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35782 itemCls : "x-menu-item",
35784 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35786 canActivate : true,
35788 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35791 // doc'd in BaseItem
35795 ctype: "Roo.menu.Item",
35798 onRender : function(container, position){
35799 var el = document.createElement("a");
35800 el.hideFocus = true;
35801 el.unselectable = "on";
35802 el.href = this.href || "#";
35803 if(this.hrefTarget){
35804 el.target = this.hrefTarget;
35806 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35808 var html = this.html.length ? this.html : String.format('{0}',this.text);
35810 el.innerHTML = String.format(
35811 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35812 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35814 Roo.menu.Item.superclass.onRender.call(this, container, position);
35818 * Sets the text to display in this menu item
35819 * @param {String} text The text to display
35820 * @param {Boolean} isHTML true to indicate text is pure html.
35822 setText : function(text, isHTML){
35830 var html = this.html.length ? this.html : String.format('{0}',this.text);
35832 this.el.update(String.format(
35833 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35834 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35835 this.parentMenu.autoWidth();
35840 handleClick : function(e){
35841 if(!this.href){ // if no link defined, stop the event automatically
35844 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35848 activate : function(autoExpand){
35849 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35859 shouldDeactivate : function(e){
35860 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35861 if(this.menu && this.menu.isVisible()){
35862 return !this.menu.getEl().getRegion().contains(e.getPoint());
35870 deactivate : function(){
35871 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35876 expandMenu : function(autoActivate){
35877 if(!this.disabled && this.menu){
35878 clearTimeout(this.hideTimer);
35879 delete this.hideTimer;
35880 if(!this.menu.isVisible() && !this.showTimer){
35881 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35882 }else if (this.menu.isVisible() && autoActivate){
35883 this.menu.tryActivate(0, 1);
35889 deferExpand : function(autoActivate){
35890 delete this.showTimer;
35891 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35893 this.menu.tryActivate(0, 1);
35898 hideMenu : function(){
35899 clearTimeout(this.showTimer);
35900 delete this.showTimer;
35901 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35902 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35907 deferHide : function(){
35908 delete this.hideTimer;
35913 * Ext JS Library 1.1.1
35914 * Copyright(c) 2006-2007, Ext JS, LLC.
35916 * Originally Released Under LGPL - original licence link has changed is not relivant.
35919 * <script type="text/javascript">
35923 * @class Roo.menu.CheckItem
35924 * @extends Roo.menu.Item
35925 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35927 * Creates a new CheckItem
35928 * @param {Object} config Configuration options
35930 Roo.menu.CheckItem = function(config){
35931 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35934 * @event beforecheckchange
35935 * Fires before the checked value is set, providing an opportunity to cancel if needed
35936 * @param {Roo.menu.CheckItem} this
35937 * @param {Boolean} checked The new checked value that will be set
35939 "beforecheckchange" : true,
35941 * @event checkchange
35942 * Fires after the checked value has been set
35943 * @param {Roo.menu.CheckItem} this
35944 * @param {Boolean} checked The checked value that was set
35946 "checkchange" : true
35948 if(this.checkHandler){
35949 this.on('checkchange', this.checkHandler, this.scope);
35952 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35954 * @cfg {String} group
35955 * All check items with the same group name will automatically be grouped into a single-select
35956 * radio button group (defaults to '')
35959 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35961 itemCls : "x-menu-item x-menu-check-item",
35963 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35965 groupClass : "x-menu-group-item",
35968 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35969 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35970 * initialized with checked = true will be rendered as checked.
35975 ctype: "Roo.menu.CheckItem",
35978 onRender : function(c){
35979 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35981 this.el.addClass(this.groupClass);
35983 Roo.menu.MenuMgr.registerCheckable(this);
35985 this.checked = false;
35986 this.setChecked(true, true);
35991 destroy : function(){
35993 Roo.menu.MenuMgr.unregisterCheckable(this);
35995 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35999 * Set the checked state of this item
36000 * @param {Boolean} checked The new checked value
36001 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36003 setChecked : function(state, suppressEvent){
36004 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36005 if(this.container){
36006 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36008 this.checked = state;
36009 if(suppressEvent !== true){
36010 this.fireEvent("checkchange", this, state);
36016 handleClick : function(e){
36017 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36018 this.setChecked(!this.checked);
36020 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36024 * Ext JS Library 1.1.1
36025 * Copyright(c) 2006-2007, Ext JS, LLC.
36027 * Originally Released Under LGPL - original licence link has changed is not relivant.
36030 * <script type="text/javascript">
36034 * @class Roo.menu.DateItem
36035 * @extends Roo.menu.Adapter
36036 * A menu item that wraps the {@link Roo.DatPicker} component.
36038 * Creates a new DateItem
36039 * @param {Object} config Configuration options
36041 Roo.menu.DateItem = function(config){
36042 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36043 /** The Roo.DatePicker object @type Roo.DatePicker */
36044 this.picker = this.component;
36045 this.addEvents({select: true});
36047 this.picker.on("render", function(picker){
36048 picker.getEl().swallowEvent("click");
36049 picker.container.addClass("x-menu-date-item");
36052 this.picker.on("select", this.onSelect, this);
36055 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36057 onSelect : function(picker, date){
36058 this.fireEvent("select", this, date, picker);
36059 Roo.menu.DateItem.superclass.handleClick.call(this);
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">
36073 * @class Roo.menu.ColorItem
36074 * @extends Roo.menu.Adapter
36075 * A menu item that wraps the {@link Roo.ColorPalette} component.
36077 * Creates a new ColorItem
36078 * @param {Object} config Configuration options
36080 Roo.menu.ColorItem = function(config){
36081 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36082 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36083 this.palette = this.component;
36084 this.relayEvents(this.palette, ["select"]);
36085 if(this.selectHandler){
36086 this.on('select', this.selectHandler, this.scope);
36089 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36091 * Ext JS Library 1.1.1
36092 * Copyright(c) 2006-2007, Ext JS, LLC.
36094 * Originally Released Under LGPL - original licence link has changed is not relivant.
36097 * <script type="text/javascript">
36102 * @class Roo.menu.DateMenu
36103 * @extends Roo.menu.Menu
36104 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36106 * Creates a new DateMenu
36107 * @param {Object} config Configuration options
36109 Roo.menu.DateMenu = function(config){
36110 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36112 var di = new Roo.menu.DateItem(config);
36115 * The {@link Roo.DatePicker} instance for this DateMenu
36118 this.picker = di.picker;
36121 * @param {DatePicker} picker
36122 * @param {Date} date
36124 this.relayEvents(di, ["select"]);
36125 this.on('beforeshow', function(){
36127 this.picker.hideMonthPicker(false);
36131 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36135 * Ext JS Library 1.1.1
36136 * Copyright(c) 2006-2007, Ext JS, LLC.
36138 * Originally Released Under LGPL - original licence link has changed is not relivant.
36141 * <script type="text/javascript">
36146 * @class Roo.menu.ColorMenu
36147 * @extends Roo.menu.Menu
36148 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36150 * Creates a new ColorMenu
36151 * @param {Object} config Configuration options
36153 Roo.menu.ColorMenu = function(config){
36154 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36156 var ci = new Roo.menu.ColorItem(config);
36159 * The {@link Roo.ColorPalette} instance for this ColorMenu
36160 * @type ColorPalette
36162 this.palette = ci.palette;
36165 * @param {ColorPalette} palette
36166 * @param {String} color
36168 this.relayEvents(ci, ["select"]);
36170 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36172 * Ext JS Library 1.1.1
36173 * Copyright(c) 2006-2007, Ext JS, LLC.
36175 * Originally Released Under LGPL - original licence link has changed is not relivant.
36178 * <script type="text/javascript">
36182 * @class Roo.form.Field
36183 * @extends Roo.BoxComponent
36184 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36186 * Creates a new Field
36187 * @param {Object} config Configuration options
36189 Roo.form.Field = function(config){
36190 Roo.form.Field.superclass.constructor.call(this, config);
36193 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36195 * @cfg {String} fieldLabel Label to use when rendering a form.
36198 * @cfg {String} qtip Mouse over tip
36202 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36204 invalidClass : "x-form-invalid",
36206 * @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")
36208 invalidText : "The value in this field is invalid",
36210 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36212 focusClass : "x-form-focus",
36214 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36215 automatic validation (defaults to "keyup").
36217 validationEvent : "keyup",
36219 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36221 validateOnBlur : true,
36223 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36225 validationDelay : 250,
36227 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36228 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36230 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36232 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36234 fieldClass : "x-form-field",
36236 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36239 ----------- ----------------------------------------------------------------------
36240 qtip Display a quick tip when the user hovers over the field
36241 title Display a default browser title attribute popup
36242 under Add a block div beneath the field containing the error text
36243 side Add an error icon to the right of the field with a popup on hover
36244 [element id] Add the error text directly to the innerHTML of the specified element
36247 msgTarget : 'qtip',
36249 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36254 * @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.
36259 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36264 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36266 inputType : undefined,
36269 * @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).
36271 tabIndex : undefined,
36274 isFormField : true,
36279 * @property {Roo.Element} fieldEl
36280 * Element Containing the rendered Field (with label etc.)
36283 * @cfg {Mixed} value A value to initialize this field with.
36288 * @cfg {String} name The field's HTML name attribute.
36291 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36295 initComponent : function(){
36296 Roo.form.Field.superclass.initComponent.call(this);
36300 * Fires when this field receives input focus.
36301 * @param {Roo.form.Field} this
36306 * Fires when this field loses input focus.
36307 * @param {Roo.form.Field} this
36311 * @event specialkey
36312 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36313 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36314 * @param {Roo.form.Field} this
36315 * @param {Roo.EventObject} e The event object
36320 * Fires just before the field blurs if the field value has changed.
36321 * @param {Roo.form.Field} this
36322 * @param {Mixed} newValue The new value
36323 * @param {Mixed} oldValue The original value
36328 * Fires after the field has been marked as invalid.
36329 * @param {Roo.form.Field} this
36330 * @param {String} msg The validation message
36335 * Fires after the field has been validated with no errors.
36336 * @param {Roo.form.Field} this
36341 * Fires after the key up
36342 * @param {Roo.form.Field} this
36343 * @param {Roo.EventObject} e The event Object
36350 * Returns the name attribute of the field if available
36351 * @return {String} name The field name
36353 getName: function(){
36354 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36358 onRender : function(ct, position){
36359 Roo.form.Field.superclass.onRender.call(this, ct, position);
36361 var cfg = this.getAutoCreate();
36363 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36365 if (!cfg.name.length) {
36368 if(this.inputType){
36369 cfg.type = this.inputType;
36371 this.el = ct.createChild(cfg, position);
36373 var type = this.el.dom.type;
36375 if(type == 'password'){
36378 this.el.addClass('x-form-'+type);
36381 this.el.dom.readOnly = true;
36383 if(this.tabIndex !== undefined){
36384 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36387 this.el.addClass([this.fieldClass, this.cls]);
36392 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36393 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36394 * @return {Roo.form.Field} this
36396 applyTo : function(target){
36397 this.allowDomMove = false;
36398 this.el = Roo.get(target);
36399 this.render(this.el.dom.parentNode);
36404 initValue : function(){
36405 if(this.value !== undefined){
36406 this.setValue(this.value);
36407 }else if(this.el.dom.value.length > 0){
36408 this.setValue(this.el.dom.value);
36413 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36415 isDirty : function() {
36416 if(this.disabled) {
36419 return String(this.getValue()) !== String(this.originalValue);
36423 afterRender : function(){
36424 Roo.form.Field.superclass.afterRender.call(this);
36429 fireKey : function(e){
36430 //Roo.log('field ' + e.getKey());
36431 if(e.isNavKeyPress()){
36432 this.fireEvent("specialkey", this, e);
36437 * Resets the current field value to the originally loaded value and clears any validation messages
36439 reset : function(){
36440 this.setValue(this.originalValue);
36441 this.clearInvalid();
36445 initEvents : function(){
36446 // safari killled keypress - so keydown is now used..
36447 this.el.on("keydown" , this.fireKey, this);
36448 this.el.on("focus", this.onFocus, this);
36449 this.el.on("blur", this.onBlur, this);
36450 this.el.relayEvent('keyup', this);
36452 // reference to original value for reset
36453 this.originalValue = this.getValue();
36457 onFocus : function(){
36458 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36459 this.el.addClass(this.focusClass);
36461 if(!this.hasFocus){
36462 this.hasFocus = true;
36463 this.startValue = this.getValue();
36464 this.fireEvent("focus", this);
36468 beforeBlur : Roo.emptyFn,
36471 onBlur : function(){
36473 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36474 this.el.removeClass(this.focusClass);
36476 this.hasFocus = false;
36477 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36480 var v = this.getValue();
36481 if(String(v) !== String(this.startValue)){
36482 this.fireEvent('change', this, v, this.startValue);
36484 this.fireEvent("blur", this);
36488 * Returns whether or not the field value is currently valid
36489 * @param {Boolean} preventMark True to disable marking the field invalid
36490 * @return {Boolean} True if the value is valid, else false
36492 isValid : function(preventMark){
36496 var restore = this.preventMark;
36497 this.preventMark = preventMark === true;
36498 var v = this.validateValue(this.processValue(this.getRawValue()));
36499 this.preventMark = restore;
36504 * Validates the field value
36505 * @return {Boolean} True if the value is valid, else false
36507 validate : function(){
36508 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36509 this.clearInvalid();
36515 processValue : function(value){
36520 // Subclasses should provide the validation implementation by overriding this
36521 validateValue : function(value){
36526 * Mark this field as invalid
36527 * @param {String} msg The validation message
36529 markInvalid : function(msg){
36530 if(!this.rendered || this.preventMark){ // not rendered
36533 this.el.addClass(this.invalidClass);
36534 msg = msg || this.invalidText;
36535 switch(this.msgTarget){
36537 this.el.dom.qtip = msg;
36538 this.el.dom.qclass = 'x-form-invalid-tip';
36539 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36540 Roo.QuickTips.enable();
36544 this.el.dom.title = msg;
36548 var elp = this.el.findParent('.x-form-element', 5, true);
36549 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36550 this.errorEl.setWidth(elp.getWidth(true)-20);
36552 this.errorEl.update(msg);
36553 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36556 if(!this.errorIcon){
36557 var elp = this.el.findParent('.x-form-element', 5, true);
36558 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36560 this.alignErrorIcon();
36561 this.errorIcon.dom.qtip = msg;
36562 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36563 this.errorIcon.show();
36564 this.on('resize', this.alignErrorIcon, this);
36567 var t = Roo.getDom(this.msgTarget);
36569 t.style.display = this.msgDisplay;
36572 this.fireEvent('invalid', this, msg);
36576 alignErrorIcon : function(){
36577 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36581 * Clear any invalid styles/messages for this field
36583 clearInvalid : function(){
36584 if(!this.rendered || this.preventMark){ // not rendered
36587 this.el.removeClass(this.invalidClass);
36588 switch(this.msgTarget){
36590 this.el.dom.qtip = '';
36593 this.el.dom.title = '';
36597 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36601 if(this.errorIcon){
36602 this.errorIcon.dom.qtip = '';
36603 this.errorIcon.hide();
36604 this.un('resize', this.alignErrorIcon, this);
36608 var t = Roo.getDom(this.msgTarget);
36610 t.style.display = 'none';
36613 this.fireEvent('valid', this);
36617 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36618 * @return {Mixed} value The field value
36620 getRawValue : function(){
36621 var v = this.el.getValue();
36627 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36628 * @return {Mixed} value The field value
36630 getValue : function(){
36631 var v = this.el.getValue();
36637 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36638 * @param {Mixed} value The value to set
36640 setRawValue : function(v){
36641 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36645 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36646 * @param {Mixed} value The value to set
36648 setValue : function(v){
36651 this.el.dom.value = (v === null || v === undefined ? '' : v);
36656 adjustSize : function(w, h){
36657 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36658 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36662 adjustWidth : function(tag, w){
36663 tag = tag.toLowerCase();
36664 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36665 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36666 if(tag == 'input'){
36669 if(tag == 'textarea'){
36672 }else if(Roo.isOpera){
36673 if(tag == 'input'){
36676 if(tag == 'textarea'){
36686 // anything other than normal should be considered experimental
36687 Roo.form.Field.msgFx = {
36689 show: function(msgEl, f){
36690 msgEl.setDisplayed('block');
36693 hide : function(msgEl, f){
36694 msgEl.setDisplayed(false).update('');
36699 show: function(msgEl, f){
36700 msgEl.slideIn('t', {stopFx:true});
36703 hide : function(msgEl, f){
36704 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36709 show: function(msgEl, f){
36710 msgEl.fixDisplay();
36711 msgEl.alignTo(f.el, 'tl-tr');
36712 msgEl.slideIn('l', {stopFx:true});
36715 hide : function(msgEl, f){
36716 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36721 * Ext JS Library 1.1.1
36722 * Copyright(c) 2006-2007, Ext JS, LLC.
36724 * Originally Released Under LGPL - original licence link has changed is not relivant.
36727 * <script type="text/javascript">
36732 * @class Roo.form.TextField
36733 * @extends Roo.form.Field
36734 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36735 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36737 * Creates a new TextField
36738 * @param {Object} config Configuration options
36740 Roo.form.TextField = function(config){
36741 Roo.form.TextField.superclass.constructor.call(this, config);
36745 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36746 * according to the default logic, but this event provides a hook for the developer to apply additional
36747 * logic at runtime to resize the field if needed.
36748 * @param {Roo.form.Field} this This text field
36749 * @param {Number} width The new field width
36755 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36757 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36761 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36765 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36769 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36773 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36777 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36779 disableKeyFilter : false,
36781 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36785 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36789 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36791 maxLength : Number.MAX_VALUE,
36793 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36795 minLengthText : "The minimum length for this field is {0}",
36797 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36799 maxLengthText : "The maximum length for this field is {0}",
36801 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36803 selectOnFocus : false,
36805 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36807 blankText : "This field is required",
36809 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36810 * If available, this function will be called only after the basic validators all return true, and will be passed the
36811 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36815 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36816 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36817 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36821 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36825 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
36831 initEvents : function()
36833 if (this.emptyText) {
36834 this.el.attr('placeholder', this.emptyText);
36837 Roo.form.TextField.superclass.initEvents.call(this);
36838 if(this.validationEvent == 'keyup'){
36839 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36840 this.el.on('keyup', this.filterValidation, this);
36842 else if(this.validationEvent !== false){
36843 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36846 if(this.selectOnFocus){
36847 this.on("focus", this.preFocus, this);
36850 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36851 this.el.on("keypress", this.filterKeys, this);
36854 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36855 this.el.on("click", this.autoSize, this);
36857 if(this.el.is('input[type=password]') && Roo.isSafari){
36858 this.el.on('keydown', this.SafariOnKeyDown, this);
36862 processValue : function(value){
36863 if(this.stripCharsRe){
36864 var newValue = value.replace(this.stripCharsRe, '');
36865 if(newValue !== value){
36866 this.setRawValue(newValue);
36873 filterValidation : function(e){
36874 if(!e.isNavKeyPress()){
36875 this.validationTask.delay(this.validationDelay);
36880 onKeyUp : function(e){
36881 if(!e.isNavKeyPress()){
36887 * Resets the current field value to the originally-loaded value and clears any validation messages.
36890 reset : function(){
36891 Roo.form.TextField.superclass.reset.call(this);
36897 preFocus : function(){
36899 if(this.selectOnFocus){
36900 this.el.dom.select();
36906 filterKeys : function(e){
36907 var k = e.getKey();
36908 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36911 var c = e.getCharCode(), cc = String.fromCharCode(c);
36912 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36915 if(!this.maskRe.test(cc)){
36920 setValue : function(v){
36922 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36928 * Validates a value according to the field's validation rules and marks the field as invalid
36929 * if the validation fails
36930 * @param {Mixed} value The value to validate
36931 * @return {Boolean} True if the value is valid, else false
36933 validateValue : function(value){
36934 if(value.length < 1) { // if it's blank
36935 if(this.allowBlank){
36936 this.clearInvalid();
36939 this.markInvalid(this.blankText);
36943 if(value.length < this.minLength){
36944 this.markInvalid(String.format(this.minLengthText, this.minLength));
36947 if(value.length > this.maxLength){
36948 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36952 var vt = Roo.form.VTypes;
36953 if(!vt[this.vtype](value, this)){
36954 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36958 if(typeof this.validator == "function"){
36959 var msg = this.validator(value);
36961 this.markInvalid(msg);
36965 if(this.regex && !this.regex.test(value)){
36966 this.markInvalid(this.regexText);
36973 * Selects text in this field
36974 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36975 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36977 selectText : function(start, end){
36978 var v = this.getRawValue();
36980 start = start === undefined ? 0 : start;
36981 end = end === undefined ? v.length : end;
36982 var d = this.el.dom;
36983 if(d.setSelectionRange){
36984 d.setSelectionRange(start, end);
36985 }else if(d.createTextRange){
36986 var range = d.createTextRange();
36987 range.moveStart("character", start);
36988 range.moveEnd("character", v.length-end);
36995 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36996 * This only takes effect if grow = true, and fires the autosize event.
36998 autoSize : function(){
36999 if(!this.grow || !this.rendered){
37003 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37006 var v = el.dom.value;
37007 var d = document.createElement('div');
37008 d.appendChild(document.createTextNode(v));
37012 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37013 this.el.setWidth(w);
37014 this.fireEvent("autosize", this, w);
37018 SafariOnKeyDown : function(event)
37020 // this is a workaround for a password hang bug on chrome/ webkit.
37022 var isSelectAll = false;
37024 if(this.el.dom.selectionEnd > 0){
37025 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37027 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37028 event.preventDefault();
37033 if(isSelectAll){ // backspace and delete key
37035 event.preventDefault();
37036 // this is very hacky as keydown always get's upper case.
37038 var cc = String.fromCharCode(event.getCharCode());
37039 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37047 * Ext JS Library 1.1.1
37048 * Copyright(c) 2006-2007, Ext JS, LLC.
37050 * Originally Released Under LGPL - original licence link has changed is not relivant.
37053 * <script type="text/javascript">
37057 * @class Roo.form.Hidden
37058 * @extends Roo.form.TextField
37059 * Simple Hidden element used on forms
37061 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37064 * Creates a new Hidden form element.
37065 * @param {Object} config Configuration options
37070 // easy hidden field...
37071 Roo.form.Hidden = function(config){
37072 Roo.form.Hidden.superclass.constructor.call(this, config);
37075 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37077 inputType: 'hidden',
37080 labelSeparator: '',
37082 itemCls : 'x-form-item-display-none'
37090 * Ext JS Library 1.1.1
37091 * Copyright(c) 2006-2007, Ext JS, LLC.
37093 * Originally Released Under LGPL - original licence link has changed is not relivant.
37096 * <script type="text/javascript">
37100 * @class Roo.form.TriggerField
37101 * @extends Roo.form.TextField
37102 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37103 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37104 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37105 * for which you can provide a custom implementation. For example:
37107 var trigger = new Roo.form.TriggerField();
37108 trigger.onTriggerClick = myTriggerFn;
37109 trigger.applyTo('my-field');
37112 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37113 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37114 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37115 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37117 * Create a new TriggerField.
37118 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37119 * to the base TextField)
37121 Roo.form.TriggerField = function(config){
37122 this.mimicing = false;
37123 Roo.form.TriggerField.superclass.constructor.call(this, config);
37126 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37128 * @cfg {String} triggerClass A CSS class to apply to the trigger
37131 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37132 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37134 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37136 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37140 /** @cfg {Boolean} grow @hide */
37141 /** @cfg {Number} growMin @hide */
37142 /** @cfg {Number} growMax @hide */
37148 autoSize: Roo.emptyFn,
37152 deferHeight : true,
37155 actionMode : 'wrap',
37157 onResize : function(w, h){
37158 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37159 if(typeof w == 'number'){
37160 var x = w - this.trigger.getWidth();
37161 this.el.setWidth(this.adjustWidth('input', x));
37162 this.trigger.setStyle('left', x+'px');
37167 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37170 getResizeEl : function(){
37175 getPositionEl : function(){
37180 alignErrorIcon : function(){
37181 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37185 onRender : function(ct, position){
37186 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37187 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37188 this.trigger = this.wrap.createChild(this.triggerConfig ||
37189 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37190 if(this.hideTrigger){
37191 this.trigger.setDisplayed(false);
37193 this.initTrigger();
37195 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37200 initTrigger : function(){
37201 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37202 this.trigger.addClassOnOver('x-form-trigger-over');
37203 this.trigger.addClassOnClick('x-form-trigger-click');
37207 onDestroy : function(){
37209 this.trigger.removeAllListeners();
37210 this.trigger.remove();
37213 this.wrap.remove();
37215 Roo.form.TriggerField.superclass.onDestroy.call(this);
37219 onFocus : function(){
37220 Roo.form.TriggerField.superclass.onFocus.call(this);
37221 if(!this.mimicing){
37222 this.wrap.addClass('x-trigger-wrap-focus');
37223 this.mimicing = true;
37224 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37225 if(this.monitorTab){
37226 this.el.on("keydown", this.checkTab, this);
37232 checkTab : function(e){
37233 if(e.getKey() == e.TAB){
37234 this.triggerBlur();
37239 onBlur : function(){
37244 mimicBlur : function(e, t){
37245 if(!this.wrap.contains(t) && this.validateBlur()){
37246 this.triggerBlur();
37251 triggerBlur : function(){
37252 this.mimicing = false;
37253 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37254 if(this.monitorTab){
37255 this.el.un("keydown", this.checkTab, this);
37257 this.wrap.removeClass('x-trigger-wrap-focus');
37258 Roo.form.TriggerField.superclass.onBlur.call(this);
37262 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37263 validateBlur : function(e, t){
37268 onDisable : function(){
37269 Roo.form.TriggerField.superclass.onDisable.call(this);
37271 this.wrap.addClass('x-item-disabled');
37276 onEnable : function(){
37277 Roo.form.TriggerField.superclass.onEnable.call(this);
37279 this.wrap.removeClass('x-item-disabled');
37284 onShow : function(){
37285 var ae = this.getActionEl();
37288 ae.dom.style.display = '';
37289 ae.dom.style.visibility = 'visible';
37295 onHide : function(){
37296 var ae = this.getActionEl();
37297 ae.dom.style.display = 'none';
37301 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37302 * by an implementing function.
37304 * @param {EventObject} e
37306 onTriggerClick : Roo.emptyFn
37309 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37310 // to be extended by an implementing class. For an example of implementing this class, see the custom
37311 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37312 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37313 initComponent : function(){
37314 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37316 this.triggerConfig = {
37317 tag:'span', cls:'x-form-twin-triggers', cn:[
37318 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37319 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37323 getTrigger : function(index){
37324 return this.triggers[index];
37327 initTrigger : function(){
37328 var ts = this.trigger.select('.x-form-trigger', true);
37329 this.wrap.setStyle('overflow', 'hidden');
37330 var triggerField = this;
37331 ts.each(function(t, all, index){
37332 t.hide = function(){
37333 var w = triggerField.wrap.getWidth();
37334 this.dom.style.display = 'none';
37335 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37337 t.show = function(){
37338 var w = triggerField.wrap.getWidth();
37339 this.dom.style.display = '';
37340 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37342 var triggerIndex = 'Trigger'+(index+1);
37344 if(this['hide'+triggerIndex]){
37345 t.dom.style.display = 'none';
37347 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37348 t.addClassOnOver('x-form-trigger-over');
37349 t.addClassOnClick('x-form-trigger-click');
37351 this.triggers = ts.elements;
37354 onTrigger1Click : Roo.emptyFn,
37355 onTrigger2Click : Roo.emptyFn
37358 * Ext JS Library 1.1.1
37359 * Copyright(c) 2006-2007, Ext JS, LLC.
37361 * Originally Released Under LGPL - original licence link has changed is not relivant.
37364 * <script type="text/javascript">
37368 * @class Roo.form.TextArea
37369 * @extends Roo.form.TextField
37370 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37371 * support for auto-sizing.
37373 * Creates a new TextArea
37374 * @param {Object} config Configuration options
37376 Roo.form.TextArea = function(config){
37377 Roo.form.TextArea.superclass.constructor.call(this, config);
37378 // these are provided exchanges for backwards compat
37379 // minHeight/maxHeight were replaced by growMin/growMax to be
37380 // compatible with TextField growing config values
37381 if(this.minHeight !== undefined){
37382 this.growMin = this.minHeight;
37384 if(this.maxHeight !== undefined){
37385 this.growMax = this.maxHeight;
37389 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37391 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37395 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37399 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37400 * in the field (equivalent to setting overflow: hidden, defaults to false)
37402 preventScrollbars: false,
37404 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37405 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37409 onRender : function(ct, position){
37411 this.defaultAutoCreate = {
37413 style:"width:300px;height:60px;",
37414 autocomplete: "off"
37417 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37419 this.textSizeEl = Roo.DomHelper.append(document.body, {
37420 tag: "pre", cls: "x-form-grow-sizer"
37422 if(this.preventScrollbars){
37423 this.el.setStyle("overflow", "hidden");
37425 this.el.setHeight(this.growMin);
37429 onDestroy : function(){
37430 if(this.textSizeEl){
37431 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37433 Roo.form.TextArea.superclass.onDestroy.call(this);
37437 onKeyUp : function(e){
37438 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37444 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37445 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37447 autoSize : function(){
37448 if(!this.grow || !this.textSizeEl){
37452 var v = el.dom.value;
37453 var ts = this.textSizeEl;
37456 ts.appendChild(document.createTextNode(v));
37459 Roo.fly(ts).setWidth(this.el.getWidth());
37461 v = "  ";
37464 v = v.replace(/\n/g, '<p> </p>');
37466 v += " \n ";
37469 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37470 if(h != this.lastHeight){
37471 this.lastHeight = h;
37472 this.el.setHeight(h);
37473 this.fireEvent("autosize", this, h);
37478 * Ext JS Library 1.1.1
37479 * Copyright(c) 2006-2007, Ext JS, LLC.
37481 * Originally Released Under LGPL - original licence link has changed is not relivant.
37484 * <script type="text/javascript">
37489 * @class Roo.form.NumberField
37490 * @extends Roo.form.TextField
37491 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37493 * Creates a new NumberField
37494 * @param {Object} config Configuration options
37496 Roo.form.NumberField = function(config){
37497 Roo.form.NumberField.superclass.constructor.call(this, config);
37500 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37502 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37504 fieldClass: "x-form-field x-form-num-field",
37506 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37508 allowDecimals : true,
37510 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37512 decimalSeparator : ".",
37514 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37516 decimalPrecision : 2,
37518 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37520 allowNegative : true,
37522 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37524 minValue : Number.NEGATIVE_INFINITY,
37526 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37528 maxValue : Number.MAX_VALUE,
37530 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37532 minText : "The minimum value for this field is {0}",
37534 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37536 maxText : "The maximum value for this field is {0}",
37538 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37539 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37541 nanText : "{0} is not a valid number",
37544 initEvents : function(){
37545 Roo.form.NumberField.superclass.initEvents.call(this);
37546 var allowed = "0123456789";
37547 if(this.allowDecimals){
37548 allowed += this.decimalSeparator;
37550 if(this.allowNegative){
37553 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37554 var keyPress = function(e){
37555 var k = e.getKey();
37556 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37559 var c = e.getCharCode();
37560 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37564 this.el.on("keypress", keyPress, this);
37568 validateValue : function(value){
37569 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37572 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37575 var num = this.parseValue(value);
37577 this.markInvalid(String.format(this.nanText, value));
37580 if(num < this.minValue){
37581 this.markInvalid(String.format(this.minText, this.minValue));
37584 if(num > this.maxValue){
37585 this.markInvalid(String.format(this.maxText, this.maxValue));
37591 getValue : function(){
37592 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37596 parseValue : function(value){
37597 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37598 return isNaN(value) ? '' : value;
37602 fixPrecision : function(value){
37603 var nan = isNaN(value);
37604 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37605 return nan ? '' : value;
37607 return parseFloat(value).toFixed(this.decimalPrecision);
37610 setValue : function(v){
37611 v = this.fixPrecision(v);
37612 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37616 decimalPrecisionFcn : function(v){
37617 return Math.floor(v);
37620 beforeBlur : function(){
37621 var v = this.parseValue(this.getRawValue());
37628 * Ext JS Library 1.1.1
37629 * Copyright(c) 2006-2007, Ext JS, LLC.
37631 * Originally Released Under LGPL - original licence link has changed is not relivant.
37634 * <script type="text/javascript">
37638 * @class Roo.form.DateField
37639 * @extends Roo.form.TriggerField
37640 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37642 * Create a new DateField
37643 * @param {Object} config
37645 Roo.form.DateField = function(config){
37646 Roo.form.DateField.superclass.constructor.call(this, config);
37652 * Fires when a date is selected
37653 * @param {Roo.form.DateField} combo This combo box
37654 * @param {Date} date The date selected
37661 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37662 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37663 this.ddMatch = null;
37664 if(this.disabledDates){
37665 var dd = this.disabledDates;
37667 for(var i = 0; i < dd.length; i++){
37669 if(i != dd.length-1) re += "|";
37671 this.ddMatch = new RegExp(re + ")");
37675 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37677 * @cfg {String} format
37678 * The default date format string which can be overriden for localization support. The format must be
37679 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37683 * @cfg {String} altFormats
37684 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37685 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37687 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37689 * @cfg {Array} disabledDays
37690 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37692 disabledDays : null,
37694 * @cfg {String} disabledDaysText
37695 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37697 disabledDaysText : "Disabled",
37699 * @cfg {Array} disabledDates
37700 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37701 * expression so they are very powerful. Some examples:
37703 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37704 * <li>["03/08", "09/16"] would disable those days for every year</li>
37705 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37706 * <li>["03/../2006"] would disable every day in March 2006</li>
37707 * <li>["^03"] would disable every day in every March</li>
37709 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37710 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37712 disabledDates : null,
37714 * @cfg {String} disabledDatesText
37715 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37717 disabledDatesText : "Disabled",
37719 * @cfg {Date/String} minValue
37720 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37721 * valid format (defaults to null).
37725 * @cfg {Date/String} maxValue
37726 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37727 * valid format (defaults to null).
37731 * @cfg {String} minText
37732 * The error text to display when the date in the cell is before minValue (defaults to
37733 * 'The date in this field must be after {minValue}').
37735 minText : "The date in this field must be equal to or after {0}",
37737 * @cfg {String} maxText
37738 * The error text to display when the date in the cell is after maxValue (defaults to
37739 * 'The date in this field must be before {maxValue}').
37741 maxText : "The date in this field must be equal to or before {0}",
37743 * @cfg {String} invalidText
37744 * The error text to display when the date in the field is invalid (defaults to
37745 * '{value} is not a valid date - it must be in the format {format}').
37747 invalidText : "{0} is not a valid date - it must be in the format {1}",
37749 * @cfg {String} triggerClass
37750 * An additional CSS class used to style the trigger button. The trigger will always get the
37751 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37752 * which displays a calendar icon).
37754 triggerClass : 'x-form-date-trigger',
37758 * @cfg {Boolean} useIso
37759 * if enabled, then the date field will use a hidden field to store the
37760 * real value as iso formated date. default (false)
37764 * @cfg {String/Object} autoCreate
37765 * A DomHelper element spec, or true for a default element spec (defaults to
37766 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37769 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37772 hiddenField: false,
37774 onRender : function(ct, position)
37776 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37778 //this.el.dom.removeAttribute('name');
37779 Roo.log("Changing name?");
37780 this.el.dom.setAttribute('name', this.name + '____hidden___' );
37781 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37783 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37784 // prevent input submission
37785 this.hiddenName = this.name;
37792 validateValue : function(value)
37794 value = this.formatDate(value);
37795 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37796 Roo.log('super failed');
37799 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37802 var svalue = value;
37803 value = this.parseDate(value);
37805 Roo.log('parse date failed' + svalue);
37806 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37809 var time = value.getTime();
37810 if(this.minValue && time < this.minValue.getTime()){
37811 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37814 if(this.maxValue && time > this.maxValue.getTime()){
37815 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37818 if(this.disabledDays){
37819 var day = value.getDay();
37820 for(var i = 0; i < this.disabledDays.length; i++) {
37821 if(day === this.disabledDays[i]){
37822 this.markInvalid(this.disabledDaysText);
37827 var fvalue = this.formatDate(value);
37828 if(this.ddMatch && this.ddMatch.test(fvalue)){
37829 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37836 // Provides logic to override the default TriggerField.validateBlur which just returns true
37837 validateBlur : function(){
37838 return !this.menu || !this.menu.isVisible();
37841 getName: function()
37843 // returns hidden if it's set..
37844 if (!this.rendered) {return ''};
37845 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37850 * Returns the current date value of the date field.
37851 * @return {Date} The date value
37853 getValue : function(){
37855 return this.hiddenField ?
37856 this.hiddenField.value :
37857 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37861 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37862 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37863 * (the default format used is "m/d/y").
37866 //All of these calls set the same date value (May 4, 2006)
37868 //Pass a date object:
37869 var dt = new Date('5/4/06');
37870 dateField.setValue(dt);
37872 //Pass a date string (default format):
37873 dateField.setValue('5/4/06');
37875 //Pass a date string (custom format):
37876 dateField.format = 'Y-m-d';
37877 dateField.setValue('2006-5-4');
37879 * @param {String/Date} date The date or valid date string
37881 setValue : function(date){
37882 if (this.hiddenField) {
37883 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37885 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37886 // make sure the value field is always stored as a date..
37887 this.value = this.parseDate(date);
37893 parseDate : function(value){
37894 if(!value || value instanceof Date){
37897 var v = Date.parseDate(value, this.format);
37898 if (!v && this.useIso) {
37899 v = Date.parseDate(value, 'Y-m-d');
37901 if(!v && this.altFormats){
37902 if(!this.altFormatsArray){
37903 this.altFormatsArray = this.altFormats.split("|");
37905 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37906 v = Date.parseDate(value, this.altFormatsArray[i]);
37913 formatDate : function(date, fmt){
37914 return (!date || !(date instanceof Date)) ?
37915 date : date.dateFormat(fmt || this.format);
37920 select: function(m, d){
37923 this.fireEvent('select', this, d);
37925 show : function(){ // retain focus styling
37929 this.focus.defer(10, this);
37930 var ml = this.menuListeners;
37931 this.menu.un("select", ml.select, this);
37932 this.menu.un("show", ml.show, this);
37933 this.menu.un("hide", ml.hide, this);
37938 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37939 onTriggerClick : function(){
37943 if(this.menu == null){
37944 this.menu = new Roo.menu.DateMenu();
37946 Roo.apply(this.menu.picker, {
37947 showClear: this.allowBlank,
37948 minDate : this.minValue,
37949 maxDate : this.maxValue,
37950 disabledDatesRE : this.ddMatch,
37951 disabledDatesText : this.disabledDatesText,
37952 disabledDays : this.disabledDays,
37953 disabledDaysText : this.disabledDaysText,
37954 format : this.useIso ? 'Y-m-d' : this.format,
37955 minText : String.format(this.minText, this.formatDate(this.minValue)),
37956 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37958 this.menu.on(Roo.apply({}, this.menuListeners, {
37961 this.menu.picker.setValue(this.getValue() || new Date());
37962 this.menu.show(this.el, "tl-bl?");
37965 beforeBlur : function(){
37966 var v = this.parseDate(this.getRawValue());
37972 /** @cfg {Boolean} grow @hide */
37973 /** @cfg {Number} growMin @hide */
37974 /** @cfg {Number} growMax @hide */
37981 * Ext JS Library 1.1.1
37982 * Copyright(c) 2006-2007, Ext JS, LLC.
37984 * Originally Released Under LGPL - original licence link has changed is not relivant.
37987 * <script type="text/javascript">
37991 * @class Roo.form.MonthField
37992 * @extends Roo.form.TriggerField
37993 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37995 * Create a new MonthField
37996 * @param {Object} config
37998 Roo.form.MonthField = function(config){
38000 Roo.form.MonthField.superclass.constructor.call(this, config);
38006 * Fires when a date is selected
38007 * @param {Roo.form.MonthFieeld} combo This combo box
38008 * @param {Date} date The date selected
38015 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38016 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38017 this.ddMatch = null;
38018 if(this.disabledDates){
38019 var dd = this.disabledDates;
38021 for(var i = 0; i < dd.length; i++){
38023 if(i != dd.length-1) re += "|";
38025 this.ddMatch = new RegExp(re + ")");
38029 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38031 * @cfg {String} format
38032 * The default date format string which can be overriden for localization support. The format must be
38033 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38037 * @cfg {String} altFormats
38038 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38039 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38041 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38043 * @cfg {Array} disabledDays
38044 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38046 disabledDays : [0,1,2,3,4,5,6],
38048 * @cfg {String} disabledDaysText
38049 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38051 disabledDaysText : "Disabled",
38053 * @cfg {Array} disabledDates
38054 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38055 * expression so they are very powerful. Some examples:
38057 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38058 * <li>["03/08", "09/16"] would disable those days for every year</li>
38059 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38060 * <li>["03/../2006"] would disable every day in March 2006</li>
38061 * <li>["^03"] would disable every day in every March</li>
38063 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38064 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38066 disabledDates : null,
38068 * @cfg {String} disabledDatesText
38069 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38071 disabledDatesText : "Disabled",
38073 * @cfg {Date/String} minValue
38074 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38075 * valid format (defaults to null).
38079 * @cfg {Date/String} maxValue
38080 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38081 * valid format (defaults to null).
38085 * @cfg {String} minText
38086 * The error text to display when the date in the cell is before minValue (defaults to
38087 * 'The date in this field must be after {minValue}').
38089 minText : "The date in this field must be equal to or after {0}",
38091 * @cfg {String} maxTextf
38092 * The error text to display when the date in the cell is after maxValue (defaults to
38093 * 'The date in this field must be before {maxValue}').
38095 maxText : "The date in this field must be equal to or before {0}",
38097 * @cfg {String} invalidText
38098 * The error text to display when the date in the field is invalid (defaults to
38099 * '{value} is not a valid date - it must be in the format {format}').
38101 invalidText : "{0} is not a valid date - it must be in the format {1}",
38103 * @cfg {String} triggerClass
38104 * An additional CSS class used to style the trigger button. The trigger will always get the
38105 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38106 * which displays a calendar icon).
38108 triggerClass : 'x-form-date-trigger',
38112 * @cfg {Boolean} useIso
38113 * if enabled, then the date field will use a hidden field to store the
38114 * real value as iso formated date. default (true)
38118 * @cfg {String/Object} autoCreate
38119 * A DomHelper element spec, or true for a default element spec (defaults to
38120 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38123 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38126 hiddenField: false,
38128 hideMonthPicker : false,
38130 onRender : function(ct, position)
38132 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38134 this.el.dom.removeAttribute('name');
38135 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38137 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38138 // prevent input submission
38139 this.hiddenName = this.name;
38146 validateValue : function(value)
38148 value = this.formatDate(value);
38149 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38152 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38155 var svalue = value;
38156 value = this.parseDate(value);
38158 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38161 var time = value.getTime();
38162 if(this.minValue && time < this.minValue.getTime()){
38163 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38166 if(this.maxValue && time > this.maxValue.getTime()){
38167 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38170 /*if(this.disabledDays){
38171 var day = value.getDay();
38172 for(var i = 0; i < this.disabledDays.length; i++) {
38173 if(day === this.disabledDays[i]){
38174 this.markInvalid(this.disabledDaysText);
38180 var fvalue = this.formatDate(value);
38181 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38182 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38190 // Provides logic to override the default TriggerField.validateBlur which just returns true
38191 validateBlur : function(){
38192 return !this.menu || !this.menu.isVisible();
38196 * Returns the current date value of the date field.
38197 * @return {Date} The date value
38199 getValue : function(){
38203 return this.hiddenField ?
38204 this.hiddenField.value :
38205 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38209 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38210 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38211 * (the default format used is "m/d/y").
38214 //All of these calls set the same date value (May 4, 2006)
38216 //Pass a date object:
38217 var dt = new Date('5/4/06');
38218 monthField.setValue(dt);
38220 //Pass a date string (default format):
38221 monthField.setValue('5/4/06');
38223 //Pass a date string (custom format):
38224 monthField.format = 'Y-m-d';
38225 monthField.setValue('2006-5-4');
38227 * @param {String/Date} date The date or valid date string
38229 setValue : function(date){
38230 Roo.log('month setValue' + date);
38231 // can only be first of month..
38233 var val = this.parseDate(date);
38235 if (this.hiddenField) {
38236 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38238 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38239 this.value = this.parseDate(date);
38243 parseDate : function(value){
38244 if(!value || value instanceof Date){
38245 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38248 var v = Date.parseDate(value, this.format);
38249 if (!v && this.useIso) {
38250 v = Date.parseDate(value, 'Y-m-d');
38254 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38258 if(!v && this.altFormats){
38259 if(!this.altFormatsArray){
38260 this.altFormatsArray = this.altFormats.split("|");
38262 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38263 v = Date.parseDate(value, this.altFormatsArray[i]);
38270 formatDate : function(date, fmt){
38271 return (!date || !(date instanceof Date)) ?
38272 date : date.dateFormat(fmt || this.format);
38277 select: function(m, d){
38279 this.fireEvent('select', this, d);
38281 show : function(){ // retain focus styling
38285 this.focus.defer(10, this);
38286 var ml = this.menuListeners;
38287 this.menu.un("select", ml.select, this);
38288 this.menu.un("show", ml.show, this);
38289 this.menu.un("hide", ml.hide, this);
38293 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38294 onTriggerClick : function(){
38298 if(this.menu == null){
38299 this.menu = new Roo.menu.DateMenu();
38303 Roo.apply(this.menu.picker, {
38305 showClear: this.allowBlank,
38306 minDate : this.minValue,
38307 maxDate : this.maxValue,
38308 disabledDatesRE : this.ddMatch,
38309 disabledDatesText : this.disabledDatesText,
38311 format : this.useIso ? 'Y-m-d' : this.format,
38312 minText : String.format(this.minText, this.formatDate(this.minValue)),
38313 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38316 this.menu.on(Roo.apply({}, this.menuListeners, {
38324 // hide month picker get's called when we called by 'before hide';
38326 var ignorehide = true;
38327 p.hideMonthPicker = function(disableAnim){
38331 if(this.monthPicker){
38332 Roo.log("hideMonthPicker called");
38333 if(disableAnim === true){
38334 this.monthPicker.hide();
38336 this.monthPicker.slideOut('t', {duration:.2});
38337 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38338 p.fireEvent("select", this, this.value);
38344 Roo.log('picker set value');
38345 Roo.log(this.getValue());
38346 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38347 m.show(this.el, 'tl-bl?');
38348 ignorehide = false;
38349 // this will trigger hideMonthPicker..
38352 // hidden the day picker
38353 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38359 p.showMonthPicker.defer(100, p);
38365 beforeBlur : function(){
38366 var v = this.parseDate(this.getRawValue());
38372 /** @cfg {Boolean} grow @hide */
38373 /** @cfg {Number} growMin @hide */
38374 /** @cfg {Number} growMax @hide */
38381 * Ext JS Library 1.1.1
38382 * Copyright(c) 2006-2007, Ext JS, LLC.
38384 * Originally Released Under LGPL - original licence link has changed is not relivant.
38387 * <script type="text/javascript">
38392 * @class Roo.form.ComboBox
38393 * @extends Roo.form.TriggerField
38394 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38396 * Create a new ComboBox.
38397 * @param {Object} config Configuration options
38399 Roo.form.ComboBox = function(config){
38400 Roo.form.ComboBox.superclass.constructor.call(this, config);
38404 * Fires when the dropdown list is expanded
38405 * @param {Roo.form.ComboBox} combo This combo box
38410 * Fires when the dropdown list is collapsed
38411 * @param {Roo.form.ComboBox} combo This combo box
38415 * @event beforeselect
38416 * Fires before a list item is selected. Return false to cancel the selection.
38417 * @param {Roo.form.ComboBox} combo This combo box
38418 * @param {Roo.data.Record} record The data record returned from the underlying store
38419 * @param {Number} index The index of the selected item in the dropdown list
38421 'beforeselect' : true,
38424 * Fires when a list item is selected
38425 * @param {Roo.form.ComboBox} combo This combo box
38426 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
38427 * @param {Number} index The index of the selected item in the dropdown list
38431 * @event beforequery
38432 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
38433 * The event object passed has these properties:
38434 * @param {Roo.form.ComboBox} combo This combo box
38435 * @param {String} query The query
38436 * @param {Boolean} forceAll true to force "all" query
38437 * @param {Boolean} cancel true to cancel the query
38438 * @param {Object} e The query event object
38440 'beforequery': true,
38443 * Fires when the 'add' icon is pressed (add a listener to enable add button)
38444 * @param {Roo.form.ComboBox} combo This combo box
38449 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
38450 * @param {Roo.form.ComboBox} combo This combo box
38451 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
38457 if(this.transform){
38458 this.allowDomMove = false;
38459 var s = Roo.getDom(this.transform);
38460 if(!this.hiddenName){
38461 this.hiddenName = s.name;
38464 this.mode = 'local';
38465 var d = [], opts = s.options;
38466 for(var i = 0, len = opts.length;i < len; i++){
38468 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
38470 this.value = value;
38472 d.push([value, o.text]);
38474 this.store = new Roo.data.SimpleStore({
38476 fields: ['value', 'text'],
38479 this.valueField = 'value';
38480 this.displayField = 'text';
38482 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
38483 if(!this.lazyRender){
38484 this.target = true;
38485 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
38486 s.parentNode.removeChild(s); // remove it
38487 this.render(this.el.parentNode);
38489 s.parentNode.removeChild(s); // remove it
38494 this.store = Roo.factory(this.store, Roo.data);
38497 this.selectedIndex = -1;
38498 if(this.mode == 'local'){
38499 if(config.queryDelay === undefined){
38500 this.queryDelay = 10;
38502 if(config.minChars === undefined){
38508 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38510 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38513 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38514 * rendering into an Roo.Editor, defaults to false)
38517 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38518 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38521 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38524 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38525 * the dropdown list (defaults to undefined, with no header element)
38529 * @cfg {String/Roo.Template} tpl The template to use to render the output
38533 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38535 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38537 listWidth: undefined,
38539 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38540 * mode = 'remote' or 'text' if mode = 'local')
38542 displayField: undefined,
38544 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38545 * mode = 'remote' or 'value' if mode = 'local').
38546 * Note: use of a valueField requires the user make a selection
38547 * in order for a value to be mapped.
38549 valueField: undefined,
38553 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38554 * field's data value (defaults to the underlying DOM element's name)
38556 hiddenName: undefined,
38558 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38562 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38564 selectedClass: 'x-combo-selected',
38566 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38567 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38568 * which displays a downward arrow icon).
38570 triggerClass : 'x-form-arrow-trigger',
38572 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38576 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38577 * anchor positions (defaults to 'tl-bl')
38579 listAlign: 'tl-bl?',
38581 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38585 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38586 * query specified by the allQuery config option (defaults to 'query')
38588 triggerAction: 'query',
38590 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38591 * (defaults to 4, does not apply if editable = false)
38595 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38596 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38600 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38601 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38605 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38606 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38610 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38611 * when editable = true (defaults to false)
38613 selectOnFocus:false,
38615 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38617 queryParam: 'query',
38619 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38620 * when mode = 'remote' (defaults to 'Loading...')
38622 loadingText: 'Loading...',
38624 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38628 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38632 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38633 * traditional select (defaults to true)
38637 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38641 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38645 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38646 * listWidth has a higher value)
38650 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38651 * allow the user to set arbitrary text into the field (defaults to false)
38653 forceSelection:false,
38655 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38656 * if typeAhead = true (defaults to 250)
38658 typeAheadDelay : 250,
38660 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38661 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38663 valueNotFoundText : undefined,
38665 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38667 blockFocus : false,
38670 * @cfg {Boolean} disableClear Disable showing of clear button.
38672 disableClear : false,
38674 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38676 alwaysQuery : false,
38682 // element that contains real text value.. (when hidden is used..)
38685 onRender : function(ct, position){
38686 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38687 if(this.hiddenName){
38688 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38690 this.hiddenField.value =
38691 this.hiddenValue !== undefined ? this.hiddenValue :
38692 this.value !== undefined ? this.value : '';
38694 // prevent input submission
38695 this.el.dom.removeAttribute('name');
38700 this.el.dom.setAttribute('autocomplete', 'off');
38703 var cls = 'x-combo-list';
38705 this.list = new Roo.Layer({
38706 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38709 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38710 this.list.setWidth(lw);
38711 this.list.swallowEvent('mousewheel');
38712 this.assetHeight = 0;
38715 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38716 this.assetHeight += this.header.getHeight();
38719 this.innerList = this.list.createChild({cls:cls+'-inner'});
38720 this.innerList.on('mouseover', this.onViewOver, this);
38721 this.innerList.on('mousemove', this.onViewMove, this);
38722 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38724 if(this.allowBlank && !this.pageSize && !this.disableClear){
38725 this.footer = this.list.createChild({cls:cls+'-ft'});
38726 this.pageTb = new Roo.Toolbar(this.footer);
38730 this.footer = this.list.createChild({cls:cls+'-ft'});
38731 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38732 {pageSize: this.pageSize});
38736 if (this.pageTb && this.allowBlank && !this.disableClear) {
38738 this.pageTb.add(new Roo.Toolbar.Fill(), {
38739 cls: 'x-btn-icon x-btn-clear',
38741 handler: function()
38744 _this.clearValue();
38745 _this.onSelect(false, -1);
38750 this.assetHeight += this.footer.getHeight();
38755 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38758 this.view = new Roo.View(this.innerList, this.tpl, {
38759 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38762 this.view.on('click', this.onViewClick, this);
38764 this.store.on('beforeload', this.onBeforeLoad, this);
38765 this.store.on('load', this.onLoad, this);
38766 this.store.on('loadexception', this.onLoadException, this);
38768 if(this.resizable){
38769 this.resizer = new Roo.Resizable(this.list, {
38770 pinned:true, handles:'se'
38772 this.resizer.on('resize', function(r, w, h){
38773 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38774 this.listWidth = w;
38775 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38776 this.restrictHeight();
38778 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38780 if(!this.editable){
38781 this.editable = true;
38782 this.setEditable(false);
38786 if (typeof(this.events.add.listeners) != 'undefined') {
38788 this.addicon = this.wrap.createChild(
38789 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38791 this.addicon.on('click', function(e) {
38792 this.fireEvent('add', this);
38795 if (typeof(this.events.edit.listeners) != 'undefined') {
38797 this.editicon = this.wrap.createChild(
38798 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38799 if (this.addicon) {
38800 this.editicon.setStyle('margin-left', '40px');
38802 this.editicon.on('click', function(e) {
38804 // we fire even if inothing is selected..
38805 this.fireEvent('edit', this, this.lastData );
38815 initEvents : function(){
38816 Roo.form.ComboBox.superclass.initEvents.call(this);
38818 this.keyNav = new Roo.KeyNav(this.el, {
38819 "up" : function(e){
38820 this.inKeyMode = true;
38824 "down" : function(e){
38825 if(!this.isExpanded()){
38826 this.onTriggerClick();
38828 this.inKeyMode = true;
38833 "enter" : function(e){
38834 this.onViewClick();
38838 "esc" : function(e){
38842 "tab" : function(e){
38843 this.onViewClick(false);
38844 this.fireEvent("specialkey", this, e);
38850 doRelay : function(foo, bar, hname){
38851 if(hname == 'down' || this.scope.isExpanded()){
38852 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38859 this.queryDelay = Math.max(this.queryDelay || 10,
38860 this.mode == 'local' ? 10 : 250);
38861 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38862 if(this.typeAhead){
38863 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38865 if(this.editable !== false){
38866 this.el.on("keyup", this.onKeyUp, this);
38868 if(this.forceSelection){
38869 this.on('blur', this.doForce, this);
38873 onDestroy : function(){
38875 this.view.setStore(null);
38876 this.view.el.removeAllListeners();
38877 this.view.el.remove();
38878 this.view.purgeListeners();
38881 this.list.destroy();
38884 this.store.un('beforeload', this.onBeforeLoad, this);
38885 this.store.un('load', this.onLoad, this);
38886 this.store.un('loadexception', this.onLoadException, this);
38888 Roo.form.ComboBox.superclass.onDestroy.call(this);
38892 fireKey : function(e){
38893 if(e.isNavKeyPress() && !this.list.isVisible()){
38894 this.fireEvent("specialkey", this, e);
38899 onResize: function(w, h){
38900 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
38902 if(typeof w != 'number'){
38903 // we do not handle it!?!?
38906 var tw = this.trigger.getWidth();
38907 tw += this.addicon ? this.addicon.getWidth() : 0;
38908 tw += this.editicon ? this.editicon.getWidth() : 0;
38910 this.el.setWidth( this.adjustWidth('input', x));
38912 this.trigger.setStyle('left', x+'px');
38914 if(this.list && this.listWidth === undefined){
38915 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38916 this.list.setWidth(lw);
38917 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38925 * Allow or prevent the user from directly editing the field text. If false is passed,
38926 * the user will only be able to select from the items defined in the dropdown list. This method
38927 * is the runtime equivalent of setting the 'editable' config option at config time.
38928 * @param {Boolean} value True to allow the user to directly edit the field text
38930 setEditable : function(value){
38931 if(value == this.editable){
38934 this.editable = value;
38936 this.el.dom.setAttribute('readOnly', true);
38937 this.el.on('mousedown', this.onTriggerClick, this);
38938 this.el.addClass('x-combo-noedit');
38940 this.el.dom.setAttribute('readOnly', false);
38941 this.el.un('mousedown', this.onTriggerClick, this);
38942 this.el.removeClass('x-combo-noedit');
38947 onBeforeLoad : function(){
38948 if(!this.hasFocus){
38951 this.innerList.update(this.loadingText ?
38952 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
38953 this.restrictHeight();
38954 this.selectedIndex = -1;
38958 onLoad : function(){
38959 if(!this.hasFocus){
38962 if(this.store.getCount() > 0){
38964 this.restrictHeight();
38965 if(this.lastQuery == this.allQuery){
38967 this.el.dom.select();
38969 if(!this.selectByValue(this.value, true)){
38970 this.select(0, true);
38974 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38975 this.taTask.delay(this.typeAheadDelay);
38979 this.onEmptyResults();
38984 onLoadException : function()
38987 Roo.log(this.store.reader.jsonData);
38988 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
38989 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38995 onTypeAhead : function(){
38996 if(this.store.getCount() > 0){
38997 var r = this.store.getAt(0);
38998 var newValue = r.data[this.displayField];
38999 var len = newValue.length;
39000 var selStart = this.getRawValue().length;
39001 if(selStart != len){
39002 this.setRawValue(newValue);
39003 this.selectText(selStart, newValue.length);
39009 onSelect : function(record, index){
39010 if(this.fireEvent('beforeselect', this, record, index) !== false){
39011 this.setFromData(index > -1 ? record.data : false);
39013 this.fireEvent('select', this, record, index);
39018 * Returns the currently selected field value or empty string if no value is set.
39019 * @return {String} value The selected value
39021 getValue : function(){
39022 if(this.valueField){
39023 return typeof this.value != 'undefined' ? this.value : '';
39025 return Roo.form.ComboBox.superclass.getValue.call(this);
39030 * Clears any text/value currently set in the field
39032 clearValue : function(){
39033 if(this.hiddenField){
39034 this.hiddenField.value = '';
39037 this.setRawValue('');
39038 this.lastSelectionText = '';
39043 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39044 * will be displayed in the field. If the value does not match the data value of an existing item,
39045 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39046 * Otherwise the field will be blank (although the value will still be set).
39047 * @param {String} value The value to match
39049 setValue : function(v){
39051 if(this.valueField){
39052 var r = this.findRecord(this.valueField, v);
39054 text = r.data[this.displayField];
39055 }else if(this.valueNotFoundText !== undefined){
39056 text = this.valueNotFoundText;
39059 this.lastSelectionText = text;
39060 if(this.hiddenField){
39061 this.hiddenField.value = v;
39063 Roo.form.ComboBox.superclass.setValue.call(this, text);
39067 * @property {Object} the last set data for the element
39072 * Sets the value of the field based on a object which is related to the record format for the store.
39073 * @param {Object} value the value to set as. or false on reset?
39075 setFromData : function(o){
39076 var dv = ''; // display value
39077 var vv = ''; // value value..
39079 if (this.displayField) {
39080 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39082 // this is an error condition!!!
39083 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39086 if(this.valueField){
39087 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39089 if(this.hiddenField){
39090 this.hiddenField.value = vv;
39092 this.lastSelectionText = dv;
39093 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39097 // no hidden field.. - we store the value in 'value', but still display
39098 // display field!!!!
39099 this.lastSelectionText = dv;
39100 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39106 reset : function(){
39107 // overridden so that last data is reset..
39108 this.setValue(this.originalValue);
39109 this.clearInvalid();
39110 this.lastData = false;
39112 this.view.clearSelections();
39116 findRecord : function(prop, value){
39118 if(this.store.getCount() > 0){
39119 this.store.each(function(r){
39120 if(r.data[prop] == value){
39130 getName: function()
39132 // returns hidden if it's set..
39133 if (!this.rendered) {return ''};
39134 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39138 onViewMove : function(e, t){
39139 this.inKeyMode = false;
39143 onViewOver : function(e, t){
39144 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39147 var item = this.view.findItemFromChild(t);
39149 var index = this.view.indexOf(item);
39150 this.select(index, false);
39155 onViewClick : function(doFocus)
39157 var index = this.view.getSelectedIndexes()[0];
39158 var r = this.store.getAt(index);
39160 this.onSelect(r, index);
39162 if(doFocus !== false && !this.blockFocus){
39168 restrictHeight : function(){
39169 this.innerList.dom.style.height = '';
39170 var inner = this.innerList.dom;
39171 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39172 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39173 this.list.beginUpdate();
39174 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39175 this.list.alignTo(this.el, this.listAlign);
39176 this.list.endUpdate();
39180 onEmptyResults : function(){
39185 * Returns true if the dropdown list is expanded, else false.
39187 isExpanded : function(){
39188 return this.list.isVisible();
39192 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39193 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39194 * @param {String} value The data value of the item to select
39195 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39196 * selected item if it is not currently in view (defaults to true)
39197 * @return {Boolean} True if the value matched an item in the list, else false
39199 selectByValue : function(v, scrollIntoView){
39200 if(v !== undefined && v !== null){
39201 var r = this.findRecord(this.valueField || this.displayField, v);
39203 this.select(this.store.indexOf(r), scrollIntoView);
39211 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39212 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39213 * @param {Number} index The zero-based index of the list item to select
39214 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39215 * selected item if it is not currently in view (defaults to true)
39217 select : function(index, scrollIntoView){
39218 this.selectedIndex = index;
39219 this.view.select(index);
39220 if(scrollIntoView !== false){
39221 var el = this.view.getNode(index);
39223 this.innerList.scrollChildIntoView(el, false);
39229 selectNext : function(){
39230 var ct = this.store.getCount();
39232 if(this.selectedIndex == -1){
39234 }else if(this.selectedIndex < ct-1){
39235 this.select(this.selectedIndex+1);
39241 selectPrev : function(){
39242 var ct = this.store.getCount();
39244 if(this.selectedIndex == -1){
39246 }else if(this.selectedIndex != 0){
39247 this.select(this.selectedIndex-1);
39253 onKeyUp : function(e){
39254 if(this.editable !== false && !e.isSpecialKey()){
39255 this.lastKey = e.getKey();
39256 this.dqTask.delay(this.queryDelay);
39261 validateBlur : function(){
39262 return !this.list || !this.list.isVisible();
39266 initQuery : function(){
39267 this.doQuery(this.getRawValue());
39271 doForce : function(){
39272 if(this.el.dom.value.length > 0){
39273 this.el.dom.value =
39274 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39280 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39281 * query allowing the query action to be canceled if needed.
39282 * @param {String} query The SQL query to execute
39283 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39284 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39285 * saved in the current store (defaults to false)
39287 doQuery : function(q, forceAll){
39288 if(q === undefined || q === null){
39293 forceAll: forceAll,
39297 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39301 forceAll = qe.forceAll;
39302 if(forceAll === true || (q.length >= this.minChars)){
39303 if(this.lastQuery != q || this.alwaysQuery){
39304 this.lastQuery = q;
39305 if(this.mode == 'local'){
39306 this.selectedIndex = -1;
39308 this.store.clearFilter();
39310 this.store.filter(this.displayField, q);
39314 this.store.baseParams[this.queryParam] = q;
39316 params: this.getParams(q)
39321 this.selectedIndex = -1;
39328 getParams : function(q){
39330 //p[this.queryParam] = q;
39333 p.limit = this.pageSize;
39339 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39341 collapse : function(){
39342 if(!this.isExpanded()){
39346 Roo.get(document).un('mousedown', this.collapseIf, this);
39347 Roo.get(document).un('mousewheel', this.collapseIf, this);
39348 if (!this.editable) {
39349 Roo.get(document).un('keydown', this.listKeyPress, this);
39351 this.fireEvent('collapse', this);
39355 collapseIf : function(e){
39356 if(!e.within(this.wrap) && !e.within(this.list)){
39362 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39364 expand : function(){
39365 if(this.isExpanded() || !this.hasFocus){
39368 this.list.alignTo(this.el, this.listAlign);
39370 Roo.get(document).on('mousedown', this.collapseIf, this);
39371 Roo.get(document).on('mousewheel', this.collapseIf, this);
39372 if (!this.editable) {
39373 Roo.get(document).on('keydown', this.listKeyPress, this);
39376 this.fireEvent('expand', this);
39380 // Implements the default empty TriggerField.onTriggerClick function
39381 onTriggerClick : function(){
39385 if(this.isExpanded()){
39387 if (!this.blockFocus) {
39392 this.hasFocus = true;
39393 if(this.triggerAction == 'all') {
39394 this.doQuery(this.allQuery, true);
39396 this.doQuery(this.getRawValue());
39398 if (!this.blockFocus) {
39403 listKeyPress : function(e)
39405 //Roo.log('listkeypress');
39406 // scroll to first matching element based on key pres..
39407 if (e.isSpecialKey()) {
39410 var k = String.fromCharCode(e.getKey()).toUpperCase();
39413 var csel = this.view.getSelectedNodes();
39414 var cselitem = false;
39416 var ix = this.view.indexOf(csel[0]);
39417 cselitem = this.store.getAt(ix);
39418 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39424 this.store.each(function(v) {
39426 // start at existing selection.
39427 if (cselitem.id == v.id) {
39433 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39434 match = this.store.indexOf(v);
39439 if (match === false) {
39440 return true; // no more action?
39443 this.view.select(match);
39444 var sn = Roo.get(this.view.getSelectedNodes()[0])
39445 sn.scrollIntoView(sn.dom.parentNode, false);
39449 * @cfg {Boolean} grow
39453 * @cfg {Number} growMin
39457 * @cfg {Number} growMax
39465 * Copyright(c) 2010-2012, Roo J Solutions Limited
39472 * @class Roo.form.ComboBoxArray
39473 * @extends Roo.form.TextField
39474 * A facebook style adder... for lists of email / people / countries etc...
39475 * pick multiple items from a combo box, and shows each one.
39477 * Fred [x] Brian [x] [Pick another |v]
39480 * For this to work: it needs various extra information
39481 * - normal combo problay has
39483 * + displayField, valueField
39485 * For our purpose...
39488 * If we change from 'extends' to wrapping...
39495 * Create a new ComboBoxArray.
39496 * @param {Object} config Configuration options
39500 Roo.form.ComboBoxArray = function(config)
39503 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
39505 this.items = new Roo.util.MixedCollection(false);
39507 // construct the child combo...
39517 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39520 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39525 // behavies liek a hiddne field
39526 inputType: 'hidden',
39528 * @cfg {Number} width The width of the box that displays the selected element
39535 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39539 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39541 hiddenName : false,
39544 // private the array of items that are displayed..
39546 // private - the hidden field el.
39548 // private - the filed el..
39551 //validateValue : function() { return true; }, // all values are ok!
39552 //onAddClick: function() { },
39554 onRender : function(ct, position)
39557 // create the standard hidden element
39558 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39561 // give fake names to child combo;
39562 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39563 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39565 this.combo = Roo.factory(this.combo, Roo.form);
39566 this.combo.onRender(ct, position);
39567 if (typeof(this.combo.width) != 'undefined') {
39568 this.combo.onResize(this.combo.width,0);
39571 this.combo.initEvents();
39573 // assigned so form know we need to do this..
39574 this.store = this.combo.store;
39575 this.valueField = this.combo.valueField;
39576 this.displayField = this.combo.displayField ;
39579 this.combo.wrap.addClass('x-cbarray-grp');
39581 var cbwrap = this.combo.wrap.createChild(
39582 {tag: 'div', cls: 'x-cbarray-cb'},
39587 this.hiddenEl = this.combo.wrap.createChild({
39588 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39590 this.el = this.combo.wrap.createChild({
39591 tag: 'input', type:'hidden' , name: this.name, value : ''
39593 // this.el.dom.removeAttribute("name");
39596 this.outerWrap = this.combo.wrap;
39597 this.wrap = cbwrap;
39599 this.outerWrap.setWidth(this.width);
39600 this.outerWrap.dom.removeChild(this.el.dom);
39602 this.wrap.dom.appendChild(this.el.dom);
39603 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39604 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39606 this.combo.trigger.setStyle('position','relative');
39607 this.combo.trigger.setStyle('left', '0px');
39608 this.combo.trigger.setStyle('top', '2px');
39610 this.combo.el.setStyle('vertical-align', 'text-bottom');
39612 //this.trigger.setStyle('vertical-align', 'top');
39614 // this should use the code from combo really... on('add' ....)
39618 this.adder = this.outerWrap.createChild(
39619 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39621 this.adder.on('click', function(e) {
39622 _t.fireEvent('adderclick', this, e);
39626 //this.adder.on('click', this.onAddClick, _t);
39629 this.combo.on('select', function(cb, rec, ix) {
39630 this.addItem(rec.data);
39633 cb.el.dom.value = '';
39634 //cb.lastData = rec.data;
39643 getName: function()
39645 // returns hidden if it's set..
39646 if (!this.rendered) {return ''};
39647 return this.hiddenName ? this.hiddenName : this.name;
39652 onResize: function(w, h){
39655 // not sure if this is needed..
39656 //this.combo.onResize(w,h);
39658 if(typeof w != 'number'){
39659 // we do not handle it!?!?
39662 var tw = this.combo.trigger.getWidth();
39663 tw += this.addicon ? this.addicon.getWidth() : 0;
39664 tw += this.editicon ? this.editicon.getWidth() : 0;
39666 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39668 this.combo.trigger.setStyle('left', '0px');
39670 if(this.list && this.listWidth === undefined){
39671 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39672 this.list.setWidth(lw);
39673 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39680 addItem: function(rec)
39682 var valueField = this.combo.valueField;
39683 var displayField = this.combo.displayField;
39684 if (this.items.indexOfKey(rec[valueField]) > -1) {
39685 //console.log("GOT " + rec.data.id);
39689 var x = new Roo.form.ComboBoxArray.Item({
39690 //id : rec[this.idField],
39692 displayField : displayField ,
39693 tipField : displayField ,
39697 this.items.add(rec[valueField],x);
39698 // add it before the element..
39699 this.updateHiddenEl();
39700 x.render(this.outerWrap, this.wrap.dom);
39701 // add the image handler..
39704 updateHiddenEl : function()
39707 if (!this.hiddenEl) {
39711 var idField = this.combo.valueField;
39713 this.items.each(function(f) {
39714 ar.push(f.data[idField]);
39717 this.hiddenEl.dom.value = ar.join(',');
39723 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39724 this.items.each(function(f) {
39727 this.el.dom.value = '';
39728 if (this.hiddenEl) {
39729 this.hiddenEl.dom.value = '';
39733 getValue: function()
39735 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39737 setValue: function(v) // not a valid action - must use addItems..
39744 if (this.store.isLocal && (typeof(v) == 'string')) {
39745 // then we can use the store to find the values..
39746 // comma seperated at present.. this needs to allow JSON based encoding..
39747 this.hiddenEl.value = v;
39749 Roo.each(v.split(','), function(k) {
39750 Roo.log("CHECK " + this.valueField + ',' + k);
39751 var li = this.store.query(this.valueField, k);
39756 add[this.valueField] = k;
39757 add[this.displayField] = li.item(0).data[this.displayField];
39763 if (typeof(v) == 'object') {
39764 // then let's assume it's an array of objects..
39765 Roo.each(v, function(l) {
39773 setFromData: function(v)
39775 // this recieves an object, if setValues is called.
39777 this.el.dom.value = v[this.displayField];
39778 this.hiddenEl.dom.value = v[this.valueField];
39779 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39782 var kv = v[this.valueField];
39783 var dv = v[this.displayField];
39784 kv = typeof(kv) != 'string' ? '' : kv;
39785 dv = typeof(dv) != 'string' ? '' : dv;
39788 var keys = kv.split(',');
39789 var display = dv.split(',');
39790 for (var i = 0 ; i < keys.length; i++) {
39793 add[this.valueField] = keys[i];
39794 add[this.displayField] = display[i];
39802 validateValue : function(value){
39803 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39812 * @class Roo.form.ComboBoxArray.Item
39813 * @extends Roo.BoxComponent
39814 * A selected item in the list
39815 * Fred [x] Brian [x] [Pick another |v]
39818 * Create a new item.
39819 * @param {Object} config Configuration options
39822 Roo.form.ComboBoxArray.Item = function(config) {
39823 config.id = Roo.id();
39824 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39827 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39830 displayField : false,
39834 defaultAutoCreate : {
39836 cls: 'x-cbarray-item',
39843 src : Roo.BLANK_IMAGE_URL ,
39851 onRender : function(ct, position)
39853 Roo.form.Field.superclass.onRender.call(this, ct, position);
39856 var cfg = this.getAutoCreate();
39857 this.el = ct.createChild(cfg, position);
39860 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39862 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39863 this.cb.renderer(this.data) :
39864 String.format('{0}',this.data[this.displayField]);
39867 this.el.child('div').dom.setAttribute('qtip',
39868 String.format('{0}',this.data[this.tipField])
39871 this.el.child('img').on('click', this.remove, this);
39875 remove : function()
39878 this.cb.items.remove(this);
39879 this.el.child('img').un('click', this.remove, this);
39881 this.cb.updateHiddenEl();
39887 * Ext JS Library 1.1.1
39888 * Copyright(c) 2006-2007, Ext JS, LLC.
39890 * Originally Released Under LGPL - original licence link has changed is not relivant.
39893 * <script type="text/javascript">
39896 * @class Roo.form.Checkbox
39897 * @extends Roo.form.Field
39898 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
39900 * Creates a new Checkbox
39901 * @param {Object} config Configuration options
39903 Roo.form.Checkbox = function(config){
39904 Roo.form.Checkbox.superclass.constructor.call(this, config);
39908 * Fires when the checkbox is checked or unchecked.
39909 * @param {Roo.form.Checkbox} this This checkbox
39910 * @param {Boolean} checked The new checked value
39916 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
39918 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
39920 focusClass : undefined,
39922 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
39924 fieldClass: "x-form-field",
39926 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
39930 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39931 * {tag: "input", type: "checkbox", autocomplete: "off"})
39933 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
39935 * @cfg {String} boxLabel The text that appears beside the checkbox
39939 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
39943 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
39945 valueOff: '0', // value when not checked..
39947 actionMode : 'viewEl',
39950 itemCls : 'x-menu-check-item x-form-item',
39951 groupClass : 'x-menu-group-item',
39952 inputType : 'hidden',
39955 inSetChecked: false, // check that we are not calling self...
39957 inputElement: false, // real input element?
39958 basedOn: false, // ????
39960 isFormField: true, // not sure where this is needed!!!!
39962 onResize : function(){
39963 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
39964 if(!this.boxLabel){
39965 this.el.alignTo(this.wrap, 'c-c');
39969 initEvents : function(){
39970 Roo.form.Checkbox.superclass.initEvents.call(this);
39971 this.el.on("click", this.onClick, this);
39972 this.el.on("change", this.onClick, this);
39976 getResizeEl : function(){
39980 getPositionEl : function(){
39985 onRender : function(ct, position){
39986 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
39988 if(this.inputValue !== undefined){
39989 this.el.dom.value = this.inputValue;
39992 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
39993 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
39994 var viewEl = this.wrap.createChild({
39995 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
39996 this.viewEl = viewEl;
39997 this.wrap.on('click', this.onClick, this);
39999 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40000 this.el.on('propertychange', this.setFromHidden, this); //ie
40005 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40006 // viewEl.on('click', this.onClick, this);
40008 //if(this.checked){
40009 this.setChecked(this.checked);
40011 //this.checked = this.el.dom;
40017 initValue : Roo.emptyFn,
40020 * Returns the checked state of the checkbox.
40021 * @return {Boolean} True if checked, else false
40023 getValue : function(){
40025 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40027 return this.valueOff;
40032 onClick : function(){
40033 this.setChecked(!this.checked);
40035 //if(this.el.dom.checked != this.checked){
40036 // this.setValue(this.el.dom.checked);
40041 * Sets the checked state of the checkbox.
40042 * On is always based on a string comparison between inputValue and the param.
40043 * @param {Boolean/String} value - the value to set
40044 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40046 setValue : function(v,suppressEvent){
40049 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40050 //if(this.el && this.el.dom){
40051 // this.el.dom.checked = this.checked;
40052 // this.el.dom.defaultChecked = this.checked;
40054 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40055 //this.fireEvent("check", this, this.checked);
40058 setChecked : function(state,suppressEvent)
40060 if (this.inSetChecked) {
40061 this.checked = state;
40067 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40069 this.checked = state;
40070 if(suppressEvent !== true){
40071 this.fireEvent('check', this, state);
40073 this.inSetChecked = true;
40074 this.el.dom.value = state ? this.inputValue : this.valueOff;
40075 this.inSetChecked = false;
40078 // handle setting of hidden value by some other method!!?!?
40079 setFromHidden: function()
40084 //console.log("SET FROM HIDDEN");
40085 //alert('setFrom hidden');
40086 this.setValue(this.el.dom.value);
40089 onDestroy : function()
40092 Roo.get(this.viewEl).remove();
40095 Roo.form.Checkbox.superclass.onDestroy.call(this);
40100 * Ext JS Library 1.1.1
40101 * Copyright(c) 2006-2007, Ext JS, LLC.
40103 * Originally Released Under LGPL - original licence link has changed is not relivant.
40106 * <script type="text/javascript">
40110 * @class Roo.form.Radio
40111 * @extends Roo.form.Checkbox
40112 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40113 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40115 * Creates a new Radio
40116 * @param {Object} config Configuration options
40118 Roo.form.Radio = function(){
40119 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40121 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40122 inputType: 'radio',
40125 * If this radio is part of a group, it will return the selected value
40128 getGroupValue : function(){
40129 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40133 onRender : function(ct, position){
40134 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40136 if(this.inputValue !== undefined){
40137 this.el.dom.value = this.inputValue;
40140 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40141 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40142 //var viewEl = this.wrap.createChild({
40143 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40144 //this.viewEl = viewEl;
40145 //this.wrap.on('click', this.onClick, this);
40147 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40148 //this.el.on('propertychange', this.setFromHidden, this); //ie
40153 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40154 // viewEl.on('click', this.onClick, this);
40157 this.el.dom.checked = 'checked' ;
40163 });//<script type="text/javascript">
40166 * Ext JS Library 1.1.1
40167 * Copyright(c) 2006-2007, Ext JS, LLC.
40168 * licensing@extjs.com
40170 * http://www.extjs.com/license
40176 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40177 * - IE ? - no idea how much works there.
40185 * @class Ext.form.HtmlEditor
40186 * @extends Ext.form.Field
40187 * Provides a lightweight HTML Editor component.
40189 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40191 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40192 * supported by this editor.</b><br/><br/>
40193 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40194 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40196 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40198 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40202 * @cfg {String} createLinkText The default text for the create link prompt
40204 createLinkText : 'Please enter the URL for the link:',
40206 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40208 defaultLinkValue : 'http:/'+'/',
40211 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40216 * @cfg {Number} height (in pixels)
40220 * @cfg {Number} width (in pixels)
40225 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40228 stylesheets: false,
40233 // private properties
40234 validationEvent : false,
40236 initialized : false,
40238 sourceEditMode : false,
40239 onFocus : Roo.emptyFn,
40241 hideMode:'offsets',
40243 defaultAutoCreate : { // modified by initCompnoent..
40245 style:"width:500px;height:300px;",
40246 autocomplete: "off"
40250 initComponent : function(){
40253 * @event initialize
40254 * Fires when the editor is fully initialized (including the iframe)
40255 * @param {HtmlEditor} this
40260 * Fires when the editor is first receives the focus. Any insertion must wait
40261 * until after this event.
40262 * @param {HtmlEditor} this
40266 * @event beforesync
40267 * Fires before the textarea is updated with content from the editor iframe. Return false
40268 * to cancel the sync.
40269 * @param {HtmlEditor} this
40270 * @param {String} html
40274 * @event beforepush
40275 * Fires before the iframe editor is updated with content from the textarea. Return false
40276 * to cancel the push.
40277 * @param {HtmlEditor} this
40278 * @param {String} html
40283 * Fires when the textarea is updated with content from the editor iframe.
40284 * @param {HtmlEditor} this
40285 * @param {String} html
40290 * Fires when the iframe editor is updated with content from the textarea.
40291 * @param {HtmlEditor} this
40292 * @param {String} html
40296 * @event editmodechange
40297 * Fires when the editor switches edit modes
40298 * @param {HtmlEditor} this
40299 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40301 editmodechange: true,
40303 * @event editorevent
40304 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40305 * @param {HtmlEditor} this
40309 this.defaultAutoCreate = {
40311 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40312 autocomplete: "off"
40317 * Protected method that will not generally be called directly. It
40318 * is called when the editor creates its toolbar. Override this method if you need to
40319 * add custom toolbar buttons.
40320 * @param {HtmlEditor} editor
40322 createToolbar : function(editor){
40323 if (!editor.toolbars || !editor.toolbars.length) {
40324 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40327 for (var i =0 ; i < editor.toolbars.length;i++) {
40328 editor.toolbars[i] = Roo.factory(
40329 typeof(editor.toolbars[i]) == 'string' ?
40330 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40331 Roo.form.HtmlEditor);
40332 editor.toolbars[i].init(editor);
40339 * Protected method that will not generally be called directly. It
40340 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40341 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40343 getDocMarkup : function(){
40346 if (this.stylesheets === false) {
40348 Roo.get(document.head).select('style').each(function(node) {
40349 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40352 Roo.get(document.head).select('link').each(function(node) {
40353 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40356 } else if (!this.stylesheets.length) {
40358 st = '<style type="text/css">' +
40359 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40362 Roo.each(this.stylesheets, function(s) {
40363 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40368 st += '<style type="text/css">' +
40369 'IMG { cursor: pointer } ' +
40373 return '<html><head>' + st +
40374 //<style type="text/css">' +
40375 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40377 ' </head><body class="roo-htmleditor-body"></body></html>';
40381 onRender : function(ct, position)
40384 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40385 this.el.dom.style.border = '0 none';
40386 this.el.dom.setAttribute('tabIndex', -1);
40387 this.el.addClass('x-hidden');
40388 if(Roo.isIE){ // fix IE 1px bogus margin
40389 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40391 this.wrap = this.el.wrap({
40392 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40395 if (this.resizable) {
40396 this.resizeEl = new Roo.Resizable(this.wrap, {
40400 minHeight : this.height,
40401 height: this.height,
40402 handles : this.resizable,
40405 resize : function(r, w, h) {
40406 _t.onResize(w,h); // -something
40413 this.frameId = Roo.id();
40415 this.createToolbar(this);
40419 var iframe = this.wrap.createChild({
40422 name: this.frameId,
40423 frameBorder : 'no',
40424 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
40428 // console.log(iframe);
40429 //this.wrap.dom.appendChild(iframe);
40431 this.iframe = iframe.dom;
40433 this.assignDocWin();
40435 this.doc.designMode = 'on';
40438 this.doc.write(this.getDocMarkup());
40442 var task = { // must defer to wait for browser to be ready
40444 //console.log("run task?" + this.doc.readyState);
40445 this.assignDocWin();
40446 if(this.doc.body || this.doc.readyState == 'complete'){
40448 this.doc.designMode="on";
40452 Roo.TaskMgr.stop(task);
40453 this.initEditor.defer(10, this);
40460 Roo.TaskMgr.start(task);
40463 this.setSize(this.wrap.getSize());
40465 if (this.resizeEl) {
40466 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
40467 // should trigger onReize..
40472 onResize : function(w, h)
40474 //Roo.log('resize: ' +w + ',' + h );
40475 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
40476 if(this.el && this.iframe){
40477 if(typeof w == 'number'){
40478 var aw = w - this.wrap.getFrameWidth('lr');
40479 this.el.setWidth(this.adjustWidth('textarea', aw));
40480 this.iframe.style.width = aw + 'px';
40482 if(typeof h == 'number'){
40484 for (var i =0; i < this.toolbars.length;i++) {
40485 // fixme - ask toolbars for heights?
40486 tbh += this.toolbars[i].tb.el.getHeight();
40487 if (this.toolbars[i].footer) {
40488 tbh += this.toolbars[i].footer.el.getHeight();
40495 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
40496 ah -= 5; // knock a few pixes off for look..
40497 this.el.setHeight(this.adjustWidth('textarea', ah));
40498 this.iframe.style.height = ah + 'px';
40500 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
40507 * Toggles the editor between standard and source edit mode.
40508 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
40510 toggleSourceEdit : function(sourceEditMode){
40512 this.sourceEditMode = sourceEditMode === true;
40514 if(this.sourceEditMode){
40516 // Roo.log(this.syncValue());
40518 this.iframe.className = 'x-hidden';
40519 this.el.removeClass('x-hidden');
40520 this.el.dom.removeAttribute('tabIndex');
40524 // Roo.log(this.pushValue());
40526 this.iframe.className = '';
40527 this.el.addClass('x-hidden');
40528 this.el.dom.setAttribute('tabIndex', -1);
40531 this.setSize(this.wrap.getSize());
40532 this.fireEvent('editmodechange', this, this.sourceEditMode);
40535 // private used internally
40536 createLink : function(){
40537 var url = prompt(this.createLinkText, this.defaultLinkValue);
40538 if(url && url != 'http:/'+'/'){
40539 this.relayCmd('createlink', url);
40543 // private (for BoxComponent)
40544 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40546 // private (for BoxComponent)
40547 getResizeEl : function(){
40551 // private (for BoxComponent)
40552 getPositionEl : function(){
40557 initEvents : function(){
40558 this.originalValue = this.getValue();
40562 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40565 markInvalid : Roo.emptyFn,
40567 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40570 clearInvalid : Roo.emptyFn,
40572 setValue : function(v){
40573 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40578 * Protected method that will not generally be called directly. If you need/want
40579 * custom HTML cleanup, this is the method you should override.
40580 * @param {String} html The HTML to be cleaned
40581 * return {String} The cleaned HTML
40583 cleanHtml : function(html){
40584 html = String(html);
40585 if(html.length > 5){
40586 if(Roo.isSafari){ // strip safari nonsense
40587 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40590 if(html == ' '){
40597 * Protected method that will not generally be called directly. Syncs the contents
40598 * of the editor iframe with the textarea.
40600 syncValue : function(){
40601 if(this.initialized){
40602 var bd = (this.doc.body || this.doc.documentElement);
40603 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40604 var html = bd.innerHTML;
40606 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40607 var m = bs.match(/text-align:(.*?);/i);
40609 html = '<div style="'+m[0]+'">' + html + '</div>';
40612 html = this.cleanHtml(html);
40613 // fix up the special chars.. normaly like back quotes in word...
40614 // however we do not want to do this with chinese..
40615 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40616 var cc = b.charCodeAt();
40618 (cc >= 0x4E00 && cc < 0xA000 ) ||
40619 (cc >= 0x3400 && cc < 0x4E00 ) ||
40620 (cc >= 0xf900 && cc < 0xfb00 )
40626 if(this.fireEvent('beforesync', this, html) !== false){
40627 this.el.dom.value = html;
40628 this.fireEvent('sync', this, html);
40634 * Protected method that will not generally be called directly. Pushes the value of the textarea
40635 * into the iframe editor.
40637 pushValue : function(){
40638 if(this.initialized){
40639 var v = this.el.dom.value;
40645 if(this.fireEvent('beforepush', this, v) !== false){
40646 var d = (this.doc.body || this.doc.documentElement);
40648 this.cleanUpPaste();
40649 this.el.dom.value = d.innerHTML;
40650 this.fireEvent('push', this, v);
40656 deferFocus : function(){
40657 this.focus.defer(10, this);
40661 focus : function(){
40662 if(this.win && !this.sourceEditMode){
40669 assignDocWin: function()
40671 var iframe = this.iframe;
40674 this.doc = iframe.contentWindow.document;
40675 this.win = iframe.contentWindow;
40677 if (!Roo.get(this.frameId)) {
40680 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40681 this.win = Roo.get(this.frameId).dom.contentWindow;
40686 initEditor : function(){
40687 //console.log("INIT EDITOR");
40688 this.assignDocWin();
40692 this.doc.designMode="on";
40694 this.doc.write(this.getDocMarkup());
40697 var dbody = (this.doc.body || this.doc.documentElement);
40698 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40699 // this copies styles from the containing element into thsi one..
40700 // not sure why we need all of this..
40701 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40702 ss['background-attachment'] = 'fixed'; // w3c
40703 dbody.bgProperties = 'fixed'; // ie
40704 Roo.DomHelper.applyStyles(dbody, ss);
40705 Roo.EventManager.on(this.doc, {
40706 //'mousedown': this.onEditorEvent,
40707 'mouseup': this.onEditorEvent,
40708 'dblclick': this.onEditorEvent,
40709 'click': this.onEditorEvent,
40710 'keyup': this.onEditorEvent,
40715 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40717 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40718 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40720 this.initialized = true;
40722 this.fireEvent('initialize', this);
40727 onDestroy : function(){
40733 for (var i =0; i < this.toolbars.length;i++) {
40734 // fixme - ask toolbars for heights?
40735 this.toolbars[i].onDestroy();
40738 this.wrap.dom.innerHTML = '';
40739 this.wrap.remove();
40744 onFirstFocus : function(){
40746 this.assignDocWin();
40749 this.activated = true;
40750 for (var i =0; i < this.toolbars.length;i++) {
40751 this.toolbars[i].onFirstFocus();
40754 if(Roo.isGecko){ // prevent silly gecko errors
40756 var s = this.win.getSelection();
40757 if(!s.focusNode || s.focusNode.nodeType != 3){
40758 var r = s.getRangeAt(0);
40759 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40764 this.execCmd('useCSS', true);
40765 this.execCmd('styleWithCSS', false);
40768 this.fireEvent('activate', this);
40772 adjustFont: function(btn){
40773 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40774 //if(Roo.isSafari){ // safari
40777 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40778 if(Roo.isSafari){ // safari
40779 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40780 v = (v < 10) ? 10 : v;
40781 v = (v > 48) ? 48 : v;
40782 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40787 v = Math.max(1, v+adjust);
40789 this.execCmd('FontSize', v );
40792 onEditorEvent : function(e){
40793 this.fireEvent('editorevent', this, e);
40794 // this.updateToolbar();
40795 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40798 insertTag : function(tg)
40800 // could be a bit smarter... -> wrap the current selected tRoo..
40801 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
40803 range = this.createRange(this.getSelection());
40804 var wrappingNode = this.doc.createElement(tg.toLowerCase());
40805 wrappingNode.appendChild(range.extractContents());
40806 range.insertNode(wrappingNode);
40813 this.execCmd("formatblock", tg);
40817 insertText : function(txt)
40821 var range = this.createRange();
40822 range.deleteContents();
40823 //alert(Sender.getAttribute('label'));
40825 range.insertNode(this.doc.createTextNode(txt));
40829 relayBtnCmd : function(btn){
40830 this.relayCmd(btn.cmd);
40834 * Executes a Midas editor command on the editor document and performs necessary focus and
40835 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40836 * @param {String} cmd The Midas command
40837 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40839 relayCmd : function(cmd, value){
40841 this.execCmd(cmd, value);
40842 this.fireEvent('editorevent', this);
40843 //this.updateToolbar();
40848 * Executes a Midas editor command directly on the editor document.
40849 * For visual commands, you should use {@link #relayCmd} instead.
40850 * <b>This should only be called after the editor is initialized.</b>
40851 * @param {String} cmd The Midas command
40852 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40854 execCmd : function(cmd, value){
40855 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40862 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40864 * @param {String} text | dom node..
40866 insertAtCursor : function(text)
40871 if(!this.activated){
40877 var r = this.doc.selection.createRange();
40888 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40892 // from jquery ui (MIT licenced)
40894 var win = this.win;
40896 if (win.getSelection && win.getSelection().getRangeAt) {
40897 range = win.getSelection().getRangeAt(0);
40898 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
40899 range.insertNode(node);
40900 } else if (win.document.selection && win.document.selection.createRange) {
40901 // no firefox support
40902 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40903 win.document.selection.createRange().pasteHTML(txt);
40905 // no firefox support
40906 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40907 this.execCmd('InsertHTML', txt);
40916 mozKeyPress : function(e){
40918 var c = e.getCharCode(), cmd;
40921 c = String.fromCharCode(c).toLowerCase();
40935 this.cleanUpPaste.defer(100, this);
40943 e.preventDefault();
40951 fixKeys : function(){ // load time branching for fastest keydown performance
40953 return function(e){
40954 var k = e.getKey(), r;
40957 r = this.doc.selection.createRange();
40960 r.pasteHTML('    ');
40967 r = this.doc.selection.createRange();
40969 var target = r.parentElement();
40970 if(!target || target.tagName.toLowerCase() != 'li'){
40972 r.pasteHTML('<br />');
40978 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40979 this.cleanUpPaste.defer(100, this);
40985 }else if(Roo.isOpera){
40986 return function(e){
40987 var k = e.getKey();
40991 this.execCmd('InsertHTML','    ');
40994 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40995 this.cleanUpPaste.defer(100, this);
41000 }else if(Roo.isSafari){
41001 return function(e){
41002 var k = e.getKey();
41006 this.execCmd('InsertText','\t');
41010 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41011 this.cleanUpPaste.defer(100, this);
41019 getAllAncestors: function()
41021 var p = this.getSelectedNode();
41024 a.push(p); // push blank onto stack..
41025 p = this.getParentElement();
41029 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41033 a.push(this.doc.body);
41037 lastSelNode : false,
41040 getSelection : function()
41042 this.assignDocWin();
41043 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41046 getSelectedNode: function()
41048 // this may only work on Gecko!!!
41050 // should we cache this!!!!
41055 var range = this.createRange(this.getSelection()).cloneRange();
41058 var parent = range.parentElement();
41060 var testRange = range.duplicate();
41061 testRange.moveToElementText(parent);
41062 if (testRange.inRange(range)) {
41065 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41068 parent = parent.parentElement;
41073 // is ancestor a text element.
41074 var ac = range.commonAncestorContainer;
41075 if (ac.nodeType == 3) {
41076 ac = ac.parentNode;
41079 var ar = ac.childNodes;
41082 var other_nodes = [];
41083 var has_other_nodes = false;
41084 for (var i=0;i<ar.length;i++) {
41085 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41088 // fullly contained node.
41090 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41095 // probably selected..
41096 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41097 other_nodes.push(ar[i]);
41101 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41106 has_other_nodes = true;
41108 if (!nodes.length && other_nodes.length) {
41109 nodes= other_nodes;
41111 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41117 createRange: function(sel)
41119 // this has strange effects when using with
41120 // top toolbar - not sure if it's a great idea.
41121 //this.editor.contentWindow.focus();
41122 if (typeof sel != "undefined") {
41124 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41126 return this.doc.createRange();
41129 return this.doc.createRange();
41132 getParentElement: function()
41135 this.assignDocWin();
41136 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41138 var range = this.createRange(sel);
41141 var p = range.commonAncestorContainer;
41142 while (p.nodeType == 3) { // text node
41153 * Range intersection.. the hard stuff...
41157 * [ -- selected range --- ]
41161 * if end is before start or hits it. fail.
41162 * if start is after end or hits it fail.
41164 * if either hits (but other is outside. - then it's not
41170 // @see http://www.thismuchiknow.co.uk/?p=64.
41171 rangeIntersectsNode : function(range, node)
41173 var nodeRange = node.ownerDocument.createRange();
41175 nodeRange.selectNode(node);
41177 nodeRange.selectNodeContents(node);
41180 var rangeStartRange = range.cloneRange();
41181 rangeStartRange.collapse(true);
41183 var rangeEndRange = range.cloneRange();
41184 rangeEndRange.collapse(false);
41186 var nodeStartRange = nodeRange.cloneRange();
41187 nodeStartRange.collapse(true);
41189 var nodeEndRange = nodeRange.cloneRange();
41190 nodeEndRange.collapse(false);
41192 return rangeStartRange.compareBoundaryPoints(
41193 Range.START_TO_START, nodeEndRange) == -1 &&
41194 rangeEndRange.compareBoundaryPoints(
41195 Range.START_TO_START, nodeStartRange) == 1;
41199 rangeCompareNode : function(range, node)
41201 var nodeRange = node.ownerDocument.createRange();
41203 nodeRange.selectNode(node);
41205 nodeRange.selectNodeContents(node);
41209 range.collapse(true);
41211 nodeRange.collapse(true);
41213 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41214 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41216 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41218 var nodeIsBefore = ss == 1;
41219 var nodeIsAfter = ee == -1;
41221 if (nodeIsBefore && nodeIsAfter)
41223 if (!nodeIsBefore && nodeIsAfter)
41224 return 1; //right trailed.
41226 if (nodeIsBefore && !nodeIsAfter)
41227 return 2; // left trailed.
41232 // private? - in a new class?
41233 cleanUpPaste : function()
41235 // cleans up the whole document..
41236 Roo.log('cleanuppaste');
41237 this.cleanUpChildren(this.doc.body);
41238 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41239 if (clean != this.doc.body.innerHTML) {
41240 this.doc.body.innerHTML = clean;
41245 cleanWordChars : function(input) {// change the chars to hex code
41246 var he = Roo.form.HtmlEditor;
41248 var output = input;
41249 Roo.each(he.swapCodes, function(sw) {
41250 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41252 output = output.replace(swapper, sw[1]);
41259 cleanUpChildren : function (n)
41261 if (!n.childNodes.length) {
41264 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41265 this.cleanUpChild(n.childNodes[i]);
41272 cleanUpChild : function (node)
41275 //console.log(node);
41276 if (node.nodeName == "#text") {
41277 // clean up silly Windows -- stuff?
41280 if (node.nodeName == "#comment") {
41281 node.parentNode.removeChild(node);
41282 // clean up silly Windows -- stuff?
41286 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41288 node.parentNode.removeChild(node);
41293 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41295 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41296 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41298 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41299 // remove_keep_children = true;
41302 if (remove_keep_children) {
41303 this.cleanUpChildren(node);
41304 // inserts everything just before this node...
41305 while (node.childNodes.length) {
41306 var cn = node.childNodes[0];
41307 node.removeChild(cn);
41308 node.parentNode.insertBefore(cn, node);
41310 node.parentNode.removeChild(node);
41314 if (!node.attributes || !node.attributes.length) {
41315 this.cleanUpChildren(node);
41319 function cleanAttr(n,v)
41322 if (v.match(/^\./) || v.match(/^\//)) {
41325 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41328 if (v.match(/^#/)) {
41331 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41332 node.removeAttribute(n);
41336 function cleanStyle(n,v)
41338 if (v.match(/expression/)) { //XSS?? should we even bother..
41339 node.removeAttribute(n);
41342 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
41343 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
41346 var parts = v.split(/;/);
41349 Roo.each(parts, function(p) {
41350 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41354 var l = p.split(':').shift().replace(/\s+/g,'');
41355 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41358 if ( cblack.indexOf(l) > -1) {
41359 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41360 //node.removeAttribute(n);
41364 // only allow 'c whitelisted system attributes'
41365 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41366 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41367 //node.removeAttribute(n);
41377 if (clean.length) {
41378 node.setAttribute(n, clean.join(';'));
41380 node.removeAttribute(n);
41386 for (var i = node.attributes.length-1; i > -1 ; i--) {
41387 var a = node.attributes[i];
41390 if (a.name.toLowerCase().substr(0,2)=='on') {
41391 node.removeAttribute(a.name);
41394 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41395 node.removeAttribute(a.name);
41398 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41399 cleanAttr(a.name,a.value); // fixme..
41402 if (a.name == 'style') {
41403 cleanStyle(a.name,a.value);
41406 /// clean up MS crap..
41407 // tecnically this should be a list of valid class'es..
41410 if (a.name == 'class') {
41411 if (a.value.match(/^Mso/)) {
41412 node.className = '';
41415 if (a.value.match(/body/)) {
41416 node.className = '';
41427 this.cleanUpChildren(node);
41433 // hide stuff that is not compatible
41447 * @event specialkey
41451 * @cfg {String} fieldClass @hide
41454 * @cfg {String} focusClass @hide
41457 * @cfg {String} autoCreate @hide
41460 * @cfg {String} inputType @hide
41463 * @cfg {String} invalidClass @hide
41466 * @cfg {String} invalidText @hide
41469 * @cfg {String} msgFx @hide
41472 * @cfg {String} validateOnBlur @hide
41476 Roo.form.HtmlEditor.white = [
41477 'area', 'br', 'img', 'input', 'hr', 'wbr',
41479 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
41480 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
41481 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
41482 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
41483 'table', 'ul', 'xmp',
41485 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
41488 'dir', 'menu', 'ol', 'ul', 'dl',
41494 Roo.form.HtmlEditor.black = [
41495 // 'embed', 'object', // enable - backend responsiblity to clean thiese
41497 'base', 'basefont', 'bgsound', 'blink', 'body',
41498 'frame', 'frameset', 'head', 'html', 'ilayer',
41499 'iframe', 'layer', 'link', 'meta', 'object',
41500 'script', 'style' ,'title', 'xml' // clean later..
41502 Roo.form.HtmlEditor.clean = [
41503 'script', 'style', 'title', 'xml'
41505 Roo.form.HtmlEditor.remove = [
41510 Roo.form.HtmlEditor.ablack = [
41514 Roo.form.HtmlEditor.aclean = [
41515 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
41519 Roo.form.HtmlEditor.pwhite= [
41520 'http', 'https', 'mailto'
41523 // white listed style attributes.
41524 Roo.form.HtmlEditor.cwhite= [
41525 // 'text-align', /// default is to allow most things..
41531 // black listed style attributes.
41532 Roo.form.HtmlEditor.cblack= [
41533 // 'font-size' -- this can be set by the project
41537 Roo.form.HtmlEditor.swapCodes =[
41548 // <script type="text/javascript">
41551 * Ext JS Library 1.1.1
41552 * Copyright(c) 2006-2007, Ext JS, LLC.
41558 * @class Roo.form.HtmlEditorToolbar1
41563 new Roo.form.HtmlEditor({
41566 new Roo.form.HtmlEditorToolbar1({
41567 disable : { fonts: 1 , format: 1, ..., ... , ...],
41573 * @cfg {Object} disable List of elements to disable..
41574 * @cfg {Array} btns List of additional buttons.
41578 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
41581 Roo.form.HtmlEditor.ToolbarStandard = function(config)
41584 Roo.apply(this, config);
41586 // default disabled, based on 'good practice'..
41587 this.disable = this.disable || {};
41588 Roo.applyIf(this.disable, {
41591 specialElements : true
41595 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41596 // dont call parent... till later.
41599 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41607 * @cfg {Object} disable List of toolbar elements to disable
41612 * @cfg {Array} fontFamilies An array of available font families
41630 // "á" , ?? a acute?
41635 "°" // , // degrees
41637 // "é" , // e ecute
41638 // "ú" , // u ecute?
41641 specialElements : [
41643 text: "Insert Table",
41646 ihtml : '<table><tr><td>Cell</td></tr></table>'
41650 text: "Insert Image",
41653 ihtml : '<img src="about:blank"/>'
41662 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41663 "input:submit", "input:button", "select", "textarea", "label" ],
41666 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41668 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
41672 * @cfg {String} defaultFont default font to use.
41674 defaultFont: 'tahoma',
41676 fontSelect : false,
41679 formatCombo : false,
41681 init : function(editor)
41683 this.editor = editor;
41686 var fid = editor.frameId;
41688 function btn(id, toggle, handler){
41689 var xid = fid + '-'+ id ;
41693 cls : 'x-btn-icon x-edit-'+id,
41694 enableToggle:toggle !== false,
41695 scope: editor, // was editor...
41696 handler:handler||editor.relayBtnCmd,
41697 clickEvent:'mousedown',
41698 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41705 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41707 // stop form submits
41708 tb.el.on('click', function(e){
41709 e.preventDefault(); // what does this do?
41712 if(!this.disable.font) { // && !Roo.isSafari){
41713 /* why no safari for fonts
41714 editor.fontSelect = tb.el.createChild({
41717 cls:'x-font-select',
41718 html: this.createFontOptions()
41721 editor.fontSelect.on('change', function(){
41722 var font = editor.fontSelect.dom.value;
41723 editor.relayCmd('fontname', font);
41724 editor.deferFocus();
41728 editor.fontSelect.dom,
41734 if(!this.disable.formats){
41735 this.formatCombo = new Roo.form.ComboBox({
41736 store: new Roo.data.SimpleStore({
41739 data : this.formats // from states.js
41743 //autoCreate : {tag: "div", size: "20"},
41744 displayField:'tag',
41748 triggerAction: 'all',
41749 emptyText:'Add tag',
41750 selectOnFocus:true,
41753 'select': function(c, r, i) {
41754 editor.insertTag(r.get('tag'));
41760 tb.addField(this.formatCombo);
41764 if(!this.disable.format){
41771 if(!this.disable.fontSize){
41776 btn('increasefontsize', false, editor.adjustFont),
41777 btn('decreasefontsize', false, editor.adjustFont)
41782 if(!this.disable.colors){
41785 id:editor.frameId +'-forecolor',
41786 cls:'x-btn-icon x-edit-forecolor',
41787 clickEvent:'mousedown',
41788 tooltip: this.buttonTips['forecolor'] || undefined,
41790 menu : new Roo.menu.ColorMenu({
41791 allowReselect: true,
41792 focus: Roo.emptyFn,
41795 selectHandler: function(cp, color){
41796 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41797 editor.deferFocus();
41800 clickEvent:'mousedown'
41803 id:editor.frameId +'backcolor',
41804 cls:'x-btn-icon x-edit-backcolor',
41805 clickEvent:'mousedown',
41806 tooltip: this.buttonTips['backcolor'] || undefined,
41808 menu : new Roo.menu.ColorMenu({
41809 focus: Roo.emptyFn,
41812 allowReselect: true,
41813 selectHandler: function(cp, color){
41815 editor.execCmd('useCSS', false);
41816 editor.execCmd('hilitecolor', color);
41817 editor.execCmd('useCSS', true);
41818 editor.deferFocus();
41820 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41821 Roo.isSafari || Roo.isIE ? '#'+color : color);
41822 editor.deferFocus();
41826 clickEvent:'mousedown'
41831 // now add all the items...
41834 if(!this.disable.alignments){
41837 btn('justifyleft'),
41838 btn('justifycenter'),
41839 btn('justifyright')
41843 //if(!Roo.isSafari){
41844 if(!this.disable.links){
41847 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41851 if(!this.disable.lists){
41854 btn('insertorderedlist'),
41855 btn('insertunorderedlist')
41858 if(!this.disable.sourceEdit){
41861 btn('sourceedit', true, function(btn){
41862 this.toggleSourceEdit(btn.pressed);
41869 // special menu.. - needs to be tidied up..
41870 if (!this.disable.special) {
41873 cls: 'x-edit-none',
41879 for (var i =0; i < this.specialChars.length; i++) {
41880 smenu.menu.items.push({
41882 html: this.specialChars[i],
41883 handler: function(a,b) {
41884 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41885 //editor.insertAtCursor(a.html);
41898 if (!this.disable.specialElements) {
41901 cls: 'x-edit-none',
41906 for (var i =0; i < this.specialElements.length; i++) {
41907 semenu.menu.items.push(
41909 handler: function(a,b) {
41910 editor.insertAtCursor(this.ihtml);
41912 }, this.specialElements[i])
41924 for(var i =0; i< this.btns.length;i++) {
41925 var b = Roo.factory(this.btns[i],Roo.form);
41926 b.cls = 'x-edit-none';
41935 // disable everything...
41937 this.tb.items.each(function(item){
41938 if(item.id != editor.frameId+ '-sourceedit'){
41942 this.rendered = true;
41944 // the all the btns;
41945 editor.on('editorevent', this.updateToolbar, this);
41946 // other toolbars need to implement this..
41947 //editor.on('editmodechange', this.updateToolbar, this);
41953 * Protected method that will not generally be called directly. It triggers
41954 * a toolbar update by reading the markup state of the current selection in the editor.
41956 updateToolbar: function(){
41958 if(!this.editor.activated){
41959 this.editor.onFirstFocus();
41963 var btns = this.tb.items.map,
41964 doc = this.editor.doc,
41965 frameId = this.editor.frameId;
41967 if(!this.disable.font && !Roo.isSafari){
41969 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
41970 if(name != this.fontSelect.dom.value){
41971 this.fontSelect.dom.value = name;
41975 if(!this.disable.format){
41976 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
41977 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
41978 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
41980 if(!this.disable.alignments){
41981 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
41982 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
41983 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
41985 if(!Roo.isSafari && !this.disable.lists){
41986 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
41987 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
41990 var ans = this.editor.getAllAncestors();
41991 if (this.formatCombo) {
41994 var store = this.formatCombo.store;
41995 this.formatCombo.setValue("");
41996 for (var i =0; i < ans.length;i++) {
41997 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
41999 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42007 // hides menus... - so this cant be on a menu...
42008 Roo.menu.MenuMgr.hideAll();
42010 //this.editorsyncValue();
42014 createFontOptions : function(){
42015 var buf = [], fs = this.fontFamilies, ff, lc;
42019 for(var i = 0, len = fs.length; i< len; i++){
42021 lc = ff.toLowerCase();
42023 '<option value="',lc,'" style="font-family:',ff,';"',
42024 (this.defaultFont == lc ? ' selected="true">' : '>'),
42029 return buf.join('');
42032 toggleSourceEdit : function(sourceEditMode){
42033 if(sourceEditMode === undefined){
42034 sourceEditMode = !this.sourceEditMode;
42036 this.sourceEditMode = sourceEditMode === true;
42037 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42038 // just toggle the button?
42039 if(btn.pressed !== this.editor.sourceEditMode){
42040 btn.toggle(this.editor.sourceEditMode);
42044 if(this.sourceEditMode){
42045 this.tb.items.each(function(item){
42046 if(item.cmd != 'sourceedit'){
42052 if(this.initialized){
42053 this.tb.items.each(function(item){
42059 // tell the editor that it's been pressed..
42060 this.editor.toggleSourceEdit(sourceEditMode);
42064 * Object collection of toolbar tooltips for the buttons in the editor. The key
42065 * is the command id associated with that button and the value is a valid QuickTips object.
42070 title: 'Bold (Ctrl+B)',
42071 text: 'Make the selected text bold.',
42072 cls: 'x-html-editor-tip'
42075 title: 'Italic (Ctrl+I)',
42076 text: 'Make the selected text italic.',
42077 cls: 'x-html-editor-tip'
42085 title: 'Bold (Ctrl+B)',
42086 text: 'Make the selected text bold.',
42087 cls: 'x-html-editor-tip'
42090 title: 'Italic (Ctrl+I)',
42091 text: 'Make the selected text italic.',
42092 cls: 'x-html-editor-tip'
42095 title: 'Underline (Ctrl+U)',
42096 text: 'Underline the selected text.',
42097 cls: 'x-html-editor-tip'
42099 increasefontsize : {
42100 title: 'Grow Text',
42101 text: 'Increase the font size.',
42102 cls: 'x-html-editor-tip'
42104 decreasefontsize : {
42105 title: 'Shrink Text',
42106 text: 'Decrease the font size.',
42107 cls: 'x-html-editor-tip'
42110 title: 'Text Highlight Color',
42111 text: 'Change the background color of the selected text.',
42112 cls: 'x-html-editor-tip'
42115 title: 'Font Color',
42116 text: 'Change the color of the selected text.',
42117 cls: 'x-html-editor-tip'
42120 title: 'Align Text Left',
42121 text: 'Align text to the left.',
42122 cls: 'x-html-editor-tip'
42125 title: 'Center Text',
42126 text: 'Center text in the editor.',
42127 cls: 'x-html-editor-tip'
42130 title: 'Align Text Right',
42131 text: 'Align text to the right.',
42132 cls: 'x-html-editor-tip'
42134 insertunorderedlist : {
42135 title: 'Bullet List',
42136 text: 'Start a bulleted list.',
42137 cls: 'x-html-editor-tip'
42139 insertorderedlist : {
42140 title: 'Numbered List',
42141 text: 'Start a numbered list.',
42142 cls: 'x-html-editor-tip'
42145 title: 'Hyperlink',
42146 text: 'Make the selected text a hyperlink.',
42147 cls: 'x-html-editor-tip'
42150 title: 'Source Edit',
42151 text: 'Switch to source editing mode.',
42152 cls: 'x-html-editor-tip'
42156 onDestroy : function(){
42159 this.tb.items.each(function(item){
42161 item.menu.removeAll();
42163 item.menu.el.destroy();
42171 onFirstFocus: function() {
42172 this.tb.items.each(function(item){
42181 // <script type="text/javascript">
42184 * Ext JS Library 1.1.1
42185 * Copyright(c) 2006-2007, Ext JS, LLC.
42192 * @class Roo.form.HtmlEditor.ToolbarContext
42197 new Roo.form.HtmlEditor({
42200 { xtype: 'ToolbarStandard', styles : {} }
42201 { xtype: 'ToolbarContext', disable : {} }
42207 * @config : {Object} disable List of elements to disable.. (not done yet.)
42208 * @config : {Object} styles Map of styles available.
42212 Roo.form.HtmlEditor.ToolbarContext = function(config)
42215 Roo.apply(this, config);
42216 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42217 // dont call parent... till later.
42218 this.styles = this.styles || {};
42223 Roo.form.HtmlEditor.ToolbarContext.types = {
42235 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42297 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42302 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42312 style : 'fontFamily',
42313 displayField: 'display',
42314 optname : 'font-family',
42363 // should we really allow this??
42364 // should this just be
42375 style : 'fontFamily',
42376 displayField: 'display',
42377 optname : 'font-family',
42384 style : 'fontFamily',
42385 displayField: 'display',
42386 optname : 'font-family',
42393 style : 'fontFamily',
42394 displayField: 'display',
42395 optname : 'font-family',
42406 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
42407 Roo.form.HtmlEditor.ToolbarContext.stores = false;
42409 Roo.form.HtmlEditor.ToolbarContext.options = {
42411 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
42412 [ 'Courier New', 'Courier New'],
42413 [ 'Tahoma', 'Tahoma'],
42414 [ 'Times New Roman,serif', 'Times'],
42415 [ 'Verdana','Verdana' ]
42419 // fixme - these need to be configurable..
42422 Roo.form.HtmlEditor.ToolbarContext.types
42425 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42433 * @cfg {Object} disable List of toolbar elements to disable
42438 * @cfg {Object} styles List of styles
42439 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42441 * These must be defined in the page, so they get rendered correctly..
42452 init : function(editor)
42454 this.editor = editor;
42457 var fid = editor.frameId;
42459 function btn(id, toggle, handler){
42460 var xid = fid + '-'+ id ;
42464 cls : 'x-btn-icon x-edit-'+id,
42465 enableToggle:toggle !== false,
42466 scope: editor, // was editor...
42467 handler:handler||editor.relayBtnCmd,
42468 clickEvent:'mousedown',
42469 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42473 // create a new element.
42474 var wdiv = editor.wrap.createChild({
42476 }, editor.wrap.dom.firstChild.nextSibling, true);
42478 // can we do this more than once??
42480 // stop form submits
42483 // disable everything...
42484 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42485 this.toolbars = {};
42487 for (var i in ty) {
42489 this.toolbars[i] = this.buildToolbar(ty[i],i);
42491 this.tb = this.toolbars.BODY;
42493 this.buildFooter();
42494 this.footer.show();
42495 editor.on('hide', function( ) { this.footer.hide() }, this);
42496 editor.on('show', function( ) { this.footer.show() }, this);
42499 this.rendered = true;
42501 // the all the btns;
42502 editor.on('editorevent', this.updateToolbar, this);
42503 // other toolbars need to implement this..
42504 //editor.on('editmodechange', this.updateToolbar, this);
42510 * Protected method that will not generally be called directly. It triggers
42511 * a toolbar update by reading the markup state of the current selection in the editor.
42513 updateToolbar: function(editor,ev,sel){
42516 // capture mouse up - this is handy for selecting images..
42517 // perhaps should go somewhere else...
42518 if(!this.editor.activated){
42519 this.editor.onFirstFocus();
42523 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42524 // selectNode - might want to handle IE?
42526 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42527 ev.target && ev.target.tagName == 'IMG') {
42528 // they have click on an image...
42529 // let's see if we can change the selection...
42532 var nodeRange = sel.ownerDocument.createRange();
42534 nodeRange.selectNode(sel);
42536 nodeRange.selectNodeContents(sel);
42538 //nodeRange.collapse(true);
42539 var s = editor.win.getSelection();
42540 s.removeAllRanges();
42541 s.addRange(nodeRange);
42545 var updateFooter = sel ? false : true;
42548 var ans = this.editor.getAllAncestors();
42551 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42554 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42555 sel = sel ? sel : this.editor.doc.body;
42556 sel = sel.tagName.length ? sel : this.editor.doc.body;
42559 // pick a menu that exists..
42560 var tn = sel.tagName.toUpperCase();
42561 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42563 tn = sel.tagName.toUpperCase();
42565 var lastSel = this.tb.selectedNode
42567 this.tb.selectedNode = sel;
42569 // if current menu does not match..
42570 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42573 ///console.log("show: " + tn);
42574 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42577 this.tb.items.first().el.innerHTML = tn + ': ';
42580 // update attributes
42581 if (this.tb.fields) {
42582 this.tb.fields.each(function(e) {
42584 e.setValue(sel.style[e.stylename]);
42587 e.setValue(sel.getAttribute(e.attrname));
42591 var hasStyles = false;
42592 for(var i in this.styles) {
42599 var st = this.tb.fields.item(0);
42601 st.store.removeAll();
42604 var cn = sel.className.split(/\s+/);
42607 if (this.styles['*']) {
42609 Roo.each(this.styles['*'], function(v) {
42610 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42613 if (this.styles[tn]) {
42614 Roo.each(this.styles[tn], function(v) {
42615 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42619 st.store.loadData(avs);
42623 // flag our selected Node.
42624 this.tb.selectedNode = sel;
42627 Roo.menu.MenuMgr.hideAll();
42631 if (!updateFooter) {
42632 //this.footDisp.dom.innerHTML = '';
42635 // update the footer
42639 this.footerEls = ans.reverse();
42640 Roo.each(this.footerEls, function(a,i) {
42641 if (!a) { return; }
42642 html += html.length ? ' > ' : '';
42644 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42649 var sz = this.footDisp.up('td').getSize();
42650 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42651 this.footDisp.dom.style.marginLeft = '5px';
42653 this.footDisp.dom.style.overflow = 'hidden';
42655 this.footDisp.dom.innerHTML = html;
42657 //this.editorsyncValue();
42664 onDestroy : function(){
42667 this.tb.items.each(function(item){
42669 item.menu.removeAll();
42671 item.menu.el.destroy();
42679 onFirstFocus: function() {
42680 // need to do this for all the toolbars..
42681 this.tb.items.each(function(item){
42685 buildToolbar: function(tlist, nm)
42687 var editor = this.editor;
42688 // create a new element.
42689 var wdiv = editor.wrap.createChild({
42691 }, editor.wrap.dom.firstChild.nextSibling, true);
42694 var tb = new Roo.Toolbar(wdiv);
42697 tb.add(nm+ ": ");
42700 for(var i in this.styles) {
42705 if (styles && styles.length) {
42707 // this needs a multi-select checkbox...
42708 tb.addField( new Roo.form.ComboBox({
42709 store: new Roo.data.SimpleStore({
42711 fields: ['val', 'selected'],
42714 name : '-roo-edit-className',
42715 attrname : 'className',
42716 displayField: 'val',
42720 triggerAction: 'all',
42721 emptyText:'Select Style',
42722 selectOnFocus:true,
42725 'select': function(c, r, i) {
42726 // initial support only for on class per el..
42727 tb.selectedNode.className = r ? r.get('val') : '';
42728 editor.syncValue();
42735 var tbc = Roo.form.HtmlEditor.ToolbarContext;
42736 var tbops = tbc.options;
42738 for (var i in tlist) {
42740 var item = tlist[i];
42741 tb.add(item.title + ": ");
42744 //optname == used so you can configure the options available..
42745 var opts = item.opts ? item.opts : false;
42746 if (item.optname) {
42747 opts = tbops[item.optname];
42752 // opts == pulldown..
42753 tb.addField( new Roo.form.ComboBox({
42754 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
42756 fields: ['val', 'display'],
42759 name : '-roo-edit-' + i,
42761 stylename : item.style ? item.style : false,
42762 displayField: item.displayField ? item.displayField : 'val',
42763 valueField : 'val',
42765 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
42767 triggerAction: 'all',
42768 emptyText:'Select',
42769 selectOnFocus:true,
42770 width: item.width ? item.width : 130,
42772 'select': function(c, r, i) {
42774 tb.selectedNode.style[c.stylename] = r.get('val');
42777 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42786 tb.addField( new Roo.form.TextField({
42789 //allowBlank:false,
42794 tb.addField( new Roo.form.TextField({
42795 name: '-roo-edit-' + i,
42802 'change' : function(f, nv, ov) {
42803 tb.selectedNode.setAttribute(f.attrname, nv);
42812 text: 'Remove Tag',
42815 click : function ()
42818 // undo does not work.
42820 var sn = tb.selectedNode;
42822 var pn = sn.parentNode;
42824 var stn = sn.childNodes[0];
42825 var en = sn.childNodes[sn.childNodes.length - 1 ];
42826 while (sn.childNodes.length) {
42827 var node = sn.childNodes[0];
42828 sn.removeChild(node);
42830 pn.insertBefore(node, sn);
42833 pn.removeChild(sn);
42834 var range = editor.createRange();
42836 range.setStart(stn,0);
42837 range.setEnd(en,0); //????
42838 //range.selectNode(sel);
42841 var selection = editor.getSelection();
42842 selection.removeAllRanges();
42843 selection.addRange(range);
42847 //_this.updateToolbar(null, null, pn);
42848 _this.updateToolbar(null, null, null);
42849 _this.footDisp.dom.innerHTML = '';
42859 tb.el.on('click', function(e){
42860 e.preventDefault(); // what does this do?
42862 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42865 // dont need to disable them... as they will get hidden
42870 buildFooter : function()
42873 var fel = this.editor.wrap.createChild();
42874 this.footer = new Roo.Toolbar(fel);
42875 // toolbar has scrolly on left / right?
42876 var footDisp= new Roo.Toolbar.Fill();
42882 handler : function() {
42883 _t.footDisp.scrollTo('left',0,true)
42887 this.footer.add( footDisp );
42892 handler : function() {
42894 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42898 var fel = Roo.get(footDisp.el);
42899 fel.addClass('x-editor-context');
42900 this.footDispWrap = fel;
42901 this.footDispWrap.overflow = 'hidden';
42903 this.footDisp = fel.createChild();
42904 this.footDispWrap.on('click', this.onContextClick, this)
42908 onContextClick : function (ev,dom)
42910 ev.preventDefault();
42911 var cn = dom.className;
42913 if (!cn.match(/x-ed-loc-/)) {
42916 var n = cn.split('-').pop();
42917 var ans = this.footerEls;
42921 var range = this.editor.createRange();
42923 range.selectNodeContents(sel);
42924 //range.selectNode(sel);
42927 var selection = this.editor.getSelection();
42928 selection.removeAllRanges();
42929 selection.addRange(range);
42933 this.updateToolbar(null, null, sel);
42950 * Ext JS Library 1.1.1
42951 * Copyright(c) 2006-2007, Ext JS, LLC.
42953 * Originally Released Under LGPL - original licence link has changed is not relivant.
42956 * <script type="text/javascript">
42960 * @class Roo.form.BasicForm
42961 * @extends Roo.util.Observable
42962 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
42964 * @param {String/HTMLElement/Roo.Element} el The form element or its id
42965 * @param {Object} config Configuration options
42967 Roo.form.BasicForm = function(el, config){
42968 this.allItems = [];
42969 this.childForms = [];
42970 Roo.apply(this, config);
42972 * The Roo.form.Field items in this form.
42973 * @type MixedCollection
42977 this.items = new Roo.util.MixedCollection(false, function(o){
42978 return o.id || (o.id = Roo.id());
42982 * @event beforeaction
42983 * Fires before any action is performed. Return false to cancel the action.
42984 * @param {Form} this
42985 * @param {Action} action The action to be performed
42987 beforeaction: true,
42989 * @event actionfailed
42990 * Fires when an action fails.
42991 * @param {Form} this
42992 * @param {Action} action The action that failed
42994 actionfailed : true,
42996 * @event actioncomplete
42997 * Fires when an action is completed.
42998 * @param {Form} this
42999 * @param {Action} action The action that completed
43001 actioncomplete : true
43006 Roo.form.BasicForm.superclass.constructor.call(this);
43009 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43011 * @cfg {String} method
43012 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43015 * @cfg {DataReader} reader
43016 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43017 * This is optional as there is built-in support for processing JSON.
43020 * @cfg {DataReader} errorReader
43021 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43022 * This is completely optional as there is built-in support for processing JSON.
43025 * @cfg {String} url
43026 * The URL to use for form actions if one isn't supplied in the action options.
43029 * @cfg {Boolean} fileUpload
43030 * Set to true if this form is a file upload.
43034 * @cfg {Object} baseParams
43035 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43040 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43045 activeAction : null,
43048 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43049 * or setValues() data instead of when the form was first created.
43051 trackResetOnLoad : false,
43055 * childForms - used for multi-tab forms
43058 childForms : false,
43061 * allItems - full list of fields.
43067 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43068 * element by passing it or its id or mask the form itself by passing in true.
43071 waitMsgTarget : false,
43074 initEl : function(el){
43075 this.el = Roo.get(el);
43076 this.id = this.el.id || Roo.id();
43077 this.el.on('submit', this.onSubmit, this);
43078 this.el.addClass('x-form');
43082 onSubmit : function(e){
43087 * Returns true if client-side validation on the form is successful.
43090 isValid : function(){
43092 this.items.each(function(f){
43101 * Returns true if any fields in this form have changed since their original load.
43104 isDirty : function(){
43106 this.items.each(function(f){
43116 * Performs a predefined action (submit or load) or custom actions you define on this form.
43117 * @param {String} actionName The name of the action type
43118 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43119 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43120 * accept other config options):
43122 Property Type Description
43123 ---------------- --------------- ----------------------------------------------------------------------------------
43124 url String The url for the action (defaults to the form's url)
43125 method String The form method to use (defaults to the form's method, or POST if not defined)
43126 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43127 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43128 validate the form on the client (defaults to false)
43130 * @return {BasicForm} this
43132 doAction : function(action, options){
43133 if(typeof action == 'string'){
43134 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43136 if(this.fireEvent('beforeaction', this, action) !== false){
43137 this.beforeAction(action);
43138 action.run.defer(100, action);
43144 * Shortcut to do a submit action.
43145 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43146 * @return {BasicForm} this
43148 submit : function(options){
43149 this.doAction('submit', options);
43154 * Shortcut to do a load action.
43155 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43156 * @return {BasicForm} this
43158 load : function(options){
43159 this.doAction('load', options);
43164 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43165 * @param {Record} record The record to edit
43166 * @return {BasicForm} this
43168 updateRecord : function(record){
43169 record.beginEdit();
43170 var fs = record.fields;
43171 fs.each(function(f){
43172 var field = this.findField(f.name);
43174 record.set(f.name, field.getValue());
43182 * Loads an Roo.data.Record into this form.
43183 * @param {Record} record The record to load
43184 * @return {BasicForm} this
43186 loadRecord : function(record){
43187 this.setValues(record.data);
43192 beforeAction : function(action){
43193 var o = action.options;
43196 if(this.waitMsgTarget === true){
43197 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43198 }else if(this.waitMsgTarget){
43199 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43200 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43202 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43208 afterAction : function(action, success){
43209 this.activeAction = null;
43210 var o = action.options;
43212 if(this.waitMsgTarget === true){
43214 }else if(this.waitMsgTarget){
43215 this.waitMsgTarget.unmask();
43217 Roo.MessageBox.updateProgress(1);
43218 Roo.MessageBox.hide();
43225 Roo.callback(o.success, o.scope, [this, action]);
43226 this.fireEvent('actioncomplete', this, action);
43230 // failure condition..
43231 // we have a scenario where updates need confirming.
43232 // eg. if a locking scenario exists..
43233 // we look for { errors : { needs_confirm : true }} in the response.
43235 (typeof(action.result) != 'undefined') &&
43236 (typeof(action.result.errors) != 'undefined') &&
43237 (typeof(action.result.errors.needs_confirm) != 'undefined')
43240 Roo.MessageBox.confirm(
43241 "Change requires confirmation",
43242 action.result.errorMsg,
43247 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43257 Roo.callback(o.failure, o.scope, [this, action]);
43258 // show an error message if no failed handler is set..
43259 if (!this.hasListener('actionfailed')) {
43260 Roo.MessageBox.alert("Error",
43261 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43262 action.result.errorMsg :
43263 "Saving Failed, please check your entries or try again"
43267 this.fireEvent('actionfailed', this, action);
43273 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43274 * @param {String} id The value to search for
43277 findField : function(id){
43278 var field = this.items.get(id);
43280 this.items.each(function(f){
43281 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43287 return field || null;
43291 * Add a secondary form to this one,
43292 * Used to provide tabbed forms. One form is primary, with hidden values
43293 * which mirror the elements from the other forms.
43295 * @param {Roo.form.Form} form to add.
43298 addForm : function(form)
43301 if (this.childForms.indexOf(form) > -1) {
43305 this.childForms.push(form);
43307 Roo.each(form.allItems, function (fe) {
43309 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43310 if (this.findField(n)) { // already added..
43313 var add = new Roo.form.Hidden({
43316 add.render(this.el);
43323 * Mark fields in this form invalid in bulk.
43324 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43325 * @return {BasicForm} this
43327 markInvalid : function(errors){
43328 if(errors instanceof Array){
43329 for(var i = 0, len = errors.length; i < len; i++){
43330 var fieldError = errors[i];
43331 var f = this.findField(fieldError.id);
43333 f.markInvalid(fieldError.msg);
43339 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43340 field.markInvalid(errors[id]);
43344 Roo.each(this.childForms || [], function (f) {
43345 f.markInvalid(errors);
43352 * Set values for fields in this form in bulk.
43353 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43354 * @return {BasicForm} this
43356 setValues : function(values){
43357 if(values instanceof Array){ // array of objects
43358 for(var i = 0, len = values.length; i < len; i++){
43360 var f = this.findField(v.id);
43362 f.setValue(v.value);
43363 if(this.trackResetOnLoad){
43364 f.originalValue = f.getValue();
43368 }else{ // object hash
43371 if(typeof values[id] != 'function' && (field = this.findField(id))){
43373 if (field.setFromData &&
43374 field.valueField &&
43375 field.displayField &&
43376 // combos' with local stores can
43377 // be queried via setValue()
43378 // to set their value..
43379 (field.store && !field.store.isLocal)
43383 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43384 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43385 field.setFromData(sd);
43388 field.setValue(values[id]);
43392 if(this.trackResetOnLoad){
43393 field.originalValue = field.getValue();
43399 Roo.each(this.childForms || [], function (f) {
43400 f.setValues(values);
43407 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43408 * they are returned as an array.
43409 * @param {Boolean} asString
43412 getValues : function(asString){
43413 if (this.childForms) {
43414 // copy values from the child forms
43415 Roo.each(this.childForms, function (f) {
43416 this.setValues(f.getValues());
43422 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43423 if(asString === true){
43426 return Roo.urlDecode(fs);
43430 * Returns the fields in this form as an object with key/value pairs.
43431 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43434 getFieldValues : function(with_hidden)
43436 if (this.childForms) {
43437 // copy values from the child forms
43438 // should this call getFieldValues - probably not as we do not currently copy
43439 // hidden fields when we generate..
43440 Roo.each(this.childForms, function (f) {
43441 this.setValues(f.getValues());
43446 this.items.each(function(f){
43447 if (!f.getName()) {
43450 var v = f.getValue();
43451 if (f.inputType =='radio') {
43452 if (typeof(ret[f.getName()]) == 'undefined') {
43453 ret[f.getName()] = ''; // empty..
43456 if (!f.el.dom.checked) {
43460 v = f.el.dom.value;
43464 // not sure if this supported any more..
43465 if ((typeof(v) == 'object') && f.getRawValue) {
43466 v = f.getRawValue() ; // dates..
43468 // combo boxes where name != hiddenName...
43469 if (f.name != f.getName()) {
43470 ret[f.name] = f.getRawValue();
43472 ret[f.getName()] = v;
43479 * Clears all invalid messages in this form.
43480 * @return {BasicForm} this
43482 clearInvalid : function(){
43483 this.items.each(function(f){
43487 Roo.each(this.childForms || [], function (f) {
43496 * Resets this form.
43497 * @return {BasicForm} this
43499 reset : function(){
43500 this.items.each(function(f){
43504 Roo.each(this.childForms || [], function (f) {
43513 * Add Roo.form components to this form.
43514 * @param {Field} field1
43515 * @param {Field} field2 (optional)
43516 * @param {Field} etc (optional)
43517 * @return {BasicForm} this
43520 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43526 * Removes a field from the items collection (does NOT remove its markup).
43527 * @param {Field} field
43528 * @return {BasicForm} this
43530 remove : function(field){
43531 this.items.remove(field);
43536 * Looks at the fields in this form, checks them for an id attribute,
43537 * and calls applyTo on the existing dom element with that id.
43538 * @return {BasicForm} this
43540 render : function(){
43541 this.items.each(function(f){
43542 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43550 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43551 * @param {Object} values
43552 * @return {BasicForm} this
43554 applyToFields : function(o){
43555 this.items.each(function(f){
43562 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43563 * @param {Object} values
43564 * @return {BasicForm} this
43566 applyIfToFields : function(o){
43567 this.items.each(function(f){
43575 Roo.BasicForm = Roo.form.BasicForm;/*
43577 * Ext JS Library 1.1.1
43578 * Copyright(c) 2006-2007, Ext JS, LLC.
43580 * Originally Released Under LGPL - original licence link has changed is not relivant.
43583 * <script type="text/javascript">
43587 * @class Roo.form.Form
43588 * @extends Roo.form.BasicForm
43589 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43591 * @param {Object} config Configuration options
43593 Roo.form.Form = function(config){
43595 if (config.items) {
43596 xitems = config.items;
43597 delete config.items;
43601 Roo.form.Form.superclass.constructor.call(this, null, config);
43602 this.url = this.url || this.action;
43604 this.root = new Roo.form.Layout(Roo.applyIf({
43608 this.active = this.root;
43610 * Array of all the buttons that have been added to this form via {@link addButton}
43614 this.allItems = [];
43617 * @event clientvalidation
43618 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43619 * @param {Form} this
43620 * @param {Boolean} valid true if the form has passed client-side validation
43622 clientvalidation: true,
43625 * Fires when the form is rendered
43626 * @param {Roo.form.Form} form
43631 if (this.progressUrl) {
43632 // push a hidden field onto the list of fields..
43636 name : 'UPLOAD_IDENTIFIER'
43641 Roo.each(xitems, this.addxtype, this);
43647 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43649 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43652 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43655 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43657 buttonAlign:'center',
43660 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43665 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43666 * This property cascades to child containers if not set.
43671 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43672 * fires a looping event with that state. This is required to bind buttons to the valid
43673 * state using the config value formBind:true on the button.
43675 monitorValid : false,
43678 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43683 * @cfg {String} progressUrl - Url to return progress data
43686 progressUrl : false,
43689 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43690 * fields are added and the column is closed. If no fields are passed the column remains open
43691 * until end() is called.
43692 * @param {Object} config The config to pass to the column
43693 * @param {Field} field1 (optional)
43694 * @param {Field} field2 (optional)
43695 * @param {Field} etc (optional)
43696 * @return Column The column container object
43698 column : function(c){
43699 var col = new Roo.form.Column(c);
43701 if(arguments.length > 1){ // duplicate code required because of Opera
43702 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43709 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43710 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43711 * until end() is called.
43712 * @param {Object} config The config to pass to the fieldset
43713 * @param {Field} field1 (optional)
43714 * @param {Field} field2 (optional)
43715 * @param {Field} etc (optional)
43716 * @return FieldSet The fieldset container object
43718 fieldset : function(c){
43719 var fs = new Roo.form.FieldSet(c);
43721 if(arguments.length > 1){ // duplicate code required because of Opera
43722 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43729 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43730 * fields are added and the container is closed. If no fields are passed the container remains open
43731 * until end() is called.
43732 * @param {Object} config The config to pass to the Layout
43733 * @param {Field} field1 (optional)
43734 * @param {Field} field2 (optional)
43735 * @param {Field} etc (optional)
43736 * @return Layout The container object
43738 container : function(c){
43739 var l = new Roo.form.Layout(c);
43741 if(arguments.length > 1){ // duplicate code required because of Opera
43742 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43749 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43750 * @param {Object} container A Roo.form.Layout or subclass of Layout
43751 * @return {Form} this
43753 start : function(c){
43754 // cascade label info
43755 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43756 this.active.stack.push(c);
43757 c.ownerCt = this.active;
43763 * Closes the current open container
43764 * @return {Form} this
43767 if(this.active == this.root){
43770 this.active = this.active.ownerCt;
43775 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43776 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43777 * as the label of the field.
43778 * @param {Field} field1
43779 * @param {Field} field2 (optional)
43780 * @param {Field} etc. (optional)
43781 * @return {Form} this
43784 this.active.stack.push.apply(this.active.stack, arguments);
43785 this.allItems.push.apply(this.allItems,arguments);
43787 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43788 if(a[i].isFormField){
43793 Roo.form.Form.superclass.add.apply(this, r);
43803 * Find any element that has been added to a form, using it's ID or name
43804 * This can include framesets, columns etc. along with regular fields..
43805 * @param {String} id - id or name to find.
43807 * @return {Element} e - or false if nothing found.
43809 findbyId : function(id)
43815 Roo.each(this.allItems, function(f){
43816 if (f.id == id || f.name == id ){
43827 * Render this form into the passed container. This should only be called once!
43828 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43829 * @return {Form} this
43831 render : function(ct)
43837 var o = this.autoCreate || {
43839 method : this.method || 'POST',
43840 id : this.id || Roo.id()
43842 this.initEl(ct.createChild(o));
43844 this.root.render(this.el);
43848 this.items.each(function(f){
43849 f.render('x-form-el-'+f.id);
43852 if(this.buttons.length > 0){
43853 // tables are required to maintain order and for correct IE layout
43854 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43855 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43856 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43858 var tr = tb.getElementsByTagName('tr')[0];
43859 for(var i = 0, len = this.buttons.length; i < len; i++) {
43860 var b = this.buttons[i];
43861 var td = document.createElement('td');
43862 td.className = 'x-form-btn-td';
43863 b.render(tr.appendChild(td));
43866 if(this.monitorValid){ // initialize after render
43867 this.startMonitoring();
43869 this.fireEvent('rendered', this);
43874 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43875 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43876 * object or a valid Roo.DomHelper element config
43877 * @param {Function} handler The function called when the button is clicked
43878 * @param {Object} scope (optional) The scope of the handler function
43879 * @return {Roo.Button}
43881 addButton : function(config, handler, scope){
43885 minWidth: this.minButtonWidth,
43888 if(typeof config == "string"){
43891 Roo.apply(bc, config);
43893 var btn = new Roo.Button(null, bc);
43894 this.buttons.push(btn);
43899 * Adds a series of form elements (using the xtype property as the factory method.
43900 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43901 * @param {Object} config
43904 addxtype : function()
43906 var ar = Array.prototype.slice.call(arguments, 0);
43908 for(var i = 0; i < ar.length; i++) {
43910 continue; // skip -- if this happends something invalid got sent, we
43911 // should ignore it, as basically that interface element will not show up
43912 // and that should be pretty obvious!!
43915 if (Roo.form[ar[i].xtype]) {
43917 var fe = Roo.factory(ar[i], Roo.form);
43923 fe.store.form = this;
43928 this.allItems.push(fe);
43929 if (fe.items && fe.addxtype) {
43930 fe.addxtype.apply(fe, fe.items);
43940 // console.log('adding ' + ar[i].xtype);
43942 if (ar[i].xtype == 'Button') {
43943 //console.log('adding button');
43944 //console.log(ar[i]);
43945 this.addButton(ar[i]);
43946 this.allItems.push(fe);
43950 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
43951 alert('end is not supported on xtype any more, use items');
43953 // //console.log('adding end');
43961 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
43962 * option "monitorValid"
43964 startMonitoring : function(){
43967 Roo.TaskMgr.start({
43968 run : this.bindHandler,
43969 interval : this.monitorPoll || 200,
43976 * Stops monitoring of the valid state of this form
43978 stopMonitoring : function(){
43979 this.bound = false;
43983 bindHandler : function(){
43985 return false; // stops binding
43988 this.items.each(function(f){
43989 if(!f.isValid(true)){
43994 for(var i = 0, len = this.buttons.length; i < len; i++){
43995 var btn = this.buttons[i];
43996 if(btn.formBind === true && btn.disabled === valid){
43997 btn.setDisabled(!valid);
44000 this.fireEvent('clientvalidation', this, valid);
44014 Roo.Form = Roo.form.Form;
44017 * Ext JS Library 1.1.1
44018 * Copyright(c) 2006-2007, Ext JS, LLC.
44020 * Originally Released Under LGPL - original licence link has changed is not relivant.
44023 * <script type="text/javascript">
44027 * @class Roo.form.Action
44028 * Internal Class used to handle form actions
44030 * @param {Roo.form.BasicForm} el The form element or its id
44031 * @param {Object} config Configuration options
44035 // define the action interface
44036 Roo.form.Action = function(form, options){
44038 this.options = options || {};
44041 * Client Validation Failed
44044 Roo.form.Action.CLIENT_INVALID = 'client';
44046 * Server Validation Failed
44049 Roo.form.Action.SERVER_INVALID = 'server';
44051 * Connect to Server Failed
44054 Roo.form.Action.CONNECT_FAILURE = 'connect';
44056 * Reading Data from Server Failed
44059 Roo.form.Action.LOAD_FAILURE = 'load';
44061 Roo.form.Action.prototype = {
44063 failureType : undefined,
44064 response : undefined,
44065 result : undefined,
44067 // interface method
44068 run : function(options){
44072 // interface method
44073 success : function(response){
44077 // interface method
44078 handleResponse : function(response){
44082 // default connection failure
44083 failure : function(response){
44085 this.response = response;
44086 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44087 this.form.afterAction(this, false);
44090 processResponse : function(response){
44091 this.response = response;
44092 if(!response.responseText){
44095 this.result = this.handleResponse(response);
44096 return this.result;
44099 // utility functions used internally
44100 getUrl : function(appendParams){
44101 var url = this.options.url || this.form.url || this.form.el.dom.action;
44103 var p = this.getParams();
44105 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44111 getMethod : function(){
44112 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44115 getParams : function(){
44116 var bp = this.form.baseParams;
44117 var p = this.options.params;
44119 if(typeof p == "object"){
44120 p = Roo.urlEncode(Roo.applyIf(p, bp));
44121 }else if(typeof p == 'string' && bp){
44122 p += '&' + Roo.urlEncode(bp);
44125 p = Roo.urlEncode(bp);
44130 createCallback : function(){
44132 success: this.success,
44133 failure: this.failure,
44135 timeout: (this.form.timeout*1000),
44136 upload: this.form.fileUpload ? this.success : undefined
44141 Roo.form.Action.Submit = function(form, options){
44142 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44145 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44148 haveProgress : false,
44149 uploadComplete : false,
44151 // uploadProgress indicator.
44152 uploadProgress : function()
44154 if (!this.form.progressUrl) {
44158 if (!this.haveProgress) {
44159 Roo.MessageBox.progress("Uploading", "Uploading");
44161 if (this.uploadComplete) {
44162 Roo.MessageBox.hide();
44166 this.haveProgress = true;
44168 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44170 var c = new Roo.data.Connection();
44172 url : this.form.progressUrl,
44177 success : function(req){
44178 //console.log(data);
44182 rdata = Roo.decode(req.responseText)
44184 Roo.log("Invalid data from server..");
44188 if (!rdata || !rdata.success) {
44190 Roo.MessageBox.alert(Roo.encode(rdata));
44193 var data = rdata.data;
44195 if (this.uploadComplete) {
44196 Roo.MessageBox.hide();
44201 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44202 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44205 this.uploadProgress.defer(2000,this);
44208 failure: function(data) {
44209 Roo.log('progress url failed ');
44220 // run get Values on the form, so it syncs any secondary forms.
44221 this.form.getValues();
44223 var o = this.options;
44224 var method = this.getMethod();
44225 var isPost = method == 'POST';
44226 if(o.clientValidation === false || this.form.isValid()){
44228 if (this.form.progressUrl) {
44229 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44230 (new Date() * 1) + '' + Math.random());
44235 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44236 form:this.form.el.dom,
44237 url:this.getUrl(!isPost),
44239 params:isPost ? this.getParams() : null,
44240 isUpload: this.form.fileUpload
44243 this.uploadProgress();
44245 }else if (o.clientValidation !== false){ // client validation failed
44246 this.failureType = Roo.form.Action.CLIENT_INVALID;
44247 this.form.afterAction(this, false);
44251 success : function(response)
44253 this.uploadComplete= true;
44254 if (this.haveProgress) {
44255 Roo.MessageBox.hide();
44259 var result = this.processResponse(response);
44260 if(result === true || result.success){
44261 this.form.afterAction(this, true);
44265 this.form.markInvalid(result.errors);
44266 this.failureType = Roo.form.Action.SERVER_INVALID;
44268 this.form.afterAction(this, false);
44270 failure : function(response)
44272 this.uploadComplete= true;
44273 if (this.haveProgress) {
44274 Roo.MessageBox.hide();
44277 this.response = response;
44278 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44279 this.form.afterAction(this, false);
44282 handleResponse : function(response){
44283 if(this.form.errorReader){
44284 var rs = this.form.errorReader.read(response);
44287 for(var i = 0, len = rs.records.length; i < len; i++) {
44288 var r = rs.records[i];
44289 errors[i] = r.data;
44292 if(errors.length < 1){
44296 success : rs.success,
44302 ret = Roo.decode(response.responseText);
44306 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44316 Roo.form.Action.Load = function(form, options){
44317 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44318 this.reader = this.form.reader;
44321 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44326 Roo.Ajax.request(Roo.apply(
44327 this.createCallback(), {
44328 method:this.getMethod(),
44329 url:this.getUrl(false),
44330 params:this.getParams()
44334 success : function(response){
44336 var result = this.processResponse(response);
44337 if(result === true || !result.success || !result.data){
44338 this.failureType = Roo.form.Action.LOAD_FAILURE;
44339 this.form.afterAction(this, false);
44342 this.form.clearInvalid();
44343 this.form.setValues(result.data);
44344 this.form.afterAction(this, true);
44347 handleResponse : function(response){
44348 if(this.form.reader){
44349 var rs = this.form.reader.read(response);
44350 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44352 success : rs.success,
44356 return Roo.decode(response.responseText);
44360 Roo.form.Action.ACTION_TYPES = {
44361 'load' : Roo.form.Action.Load,
44362 'submit' : Roo.form.Action.Submit
44365 * Ext JS Library 1.1.1
44366 * Copyright(c) 2006-2007, Ext JS, LLC.
44368 * Originally Released Under LGPL - original licence link has changed is not relivant.
44371 * <script type="text/javascript">
44375 * @class Roo.form.Layout
44376 * @extends Roo.Component
44377 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44379 * @param {Object} config Configuration options
44381 Roo.form.Layout = function(config){
44383 if (config.items) {
44384 xitems = config.items;
44385 delete config.items;
44387 Roo.form.Layout.superclass.constructor.call(this, config);
44389 Roo.each(xitems, this.addxtype, this);
44393 Roo.extend(Roo.form.Layout, Roo.Component, {
44395 * @cfg {String/Object} autoCreate
44396 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44399 * @cfg {String/Object/Function} style
44400 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44401 * a function which returns such a specification.
44404 * @cfg {String} labelAlign
44405 * Valid values are "left," "top" and "right" (defaults to "left")
44408 * @cfg {Number} labelWidth
44409 * Fixed width in pixels of all field labels (defaults to undefined)
44412 * @cfg {Boolean} clear
44413 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44417 * @cfg {String} labelSeparator
44418 * The separator to use after field labels (defaults to ':')
44420 labelSeparator : ':',
44422 * @cfg {Boolean} hideLabels
44423 * True to suppress the display of field labels in this layout (defaults to false)
44425 hideLabels : false,
44428 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44433 onRender : function(ct, position){
44434 if(this.el){ // from markup
44435 this.el = Roo.get(this.el);
44436 }else { // generate
44437 var cfg = this.getAutoCreate();
44438 this.el = ct.createChild(cfg, position);
44441 this.el.applyStyles(this.style);
44443 if(this.labelAlign){
44444 this.el.addClass('x-form-label-'+this.labelAlign);
44446 if(this.hideLabels){
44447 this.labelStyle = "display:none";
44448 this.elementStyle = "padding-left:0;";
44450 if(typeof this.labelWidth == 'number'){
44451 this.labelStyle = "width:"+this.labelWidth+"px;";
44452 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44454 if(this.labelAlign == 'top'){
44455 this.labelStyle = "width:auto;";
44456 this.elementStyle = "padding-left:0;";
44459 var stack = this.stack;
44460 var slen = stack.length;
44462 if(!this.fieldTpl){
44463 var t = new Roo.Template(
44464 '<div class="x-form-item {5}">',
44465 '<label for="{0}" style="{2}">{1}{4}</label>',
44466 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44468 '</div><div class="x-form-clear-left"></div>'
44470 t.disableFormats = true;
44472 Roo.form.Layout.prototype.fieldTpl = t;
44474 for(var i = 0; i < slen; i++) {
44475 if(stack[i].isFormField){
44476 this.renderField(stack[i]);
44478 this.renderComponent(stack[i]);
44483 this.el.createChild({cls:'x-form-clear'});
44488 renderField : function(f){
44489 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44492 f.labelStyle||this.labelStyle||'', //2
44493 this.elementStyle||'', //3
44494 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44495 f.itemCls||this.itemCls||'' //5
44496 ], true).getPrevSibling());
44500 renderComponent : function(c){
44501 c.render(c.isLayout ? this.el : this.el.createChild());
44504 * Adds a object form elements (using the xtype property as the factory method.)
44505 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44506 * @param {Object} config
44508 addxtype : function(o)
44510 // create the lement.
44511 o.form = this.form;
44512 var fe = Roo.factory(o, Roo.form);
44513 this.form.allItems.push(fe);
44514 this.stack.push(fe);
44516 if (fe.isFormField) {
44517 this.form.items.add(fe);
44525 * @class Roo.form.Column
44526 * @extends Roo.form.Layout
44527 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44529 * @param {Object} config Configuration options
44531 Roo.form.Column = function(config){
44532 Roo.form.Column.superclass.constructor.call(this, config);
44535 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44537 * @cfg {Number/String} width
44538 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44541 * @cfg {String/Object} autoCreate
44542 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44546 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44549 onRender : function(ct, position){
44550 Roo.form.Column.superclass.onRender.call(this, ct, position);
44552 this.el.setWidth(this.width);
44559 * @class Roo.form.Row
44560 * @extends Roo.form.Layout
44561 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44563 * @param {Object} config Configuration options
44567 Roo.form.Row = function(config){
44568 Roo.form.Row.superclass.constructor.call(this, config);
44571 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44573 * @cfg {Number/String} width
44574 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44577 * @cfg {Number/String} height
44578 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44580 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44584 onRender : function(ct, position){
44585 //console.log('row render');
44587 var t = new Roo.Template(
44588 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44589 '<label for="{0}" style="{2}">{1}{4}</label>',
44590 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44594 t.disableFormats = true;
44596 Roo.form.Layout.prototype.rowTpl = t;
44598 this.fieldTpl = this.rowTpl;
44600 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44601 var labelWidth = 100;
44603 if ((this.labelAlign != 'top')) {
44604 if (typeof this.labelWidth == 'number') {
44605 labelWidth = this.labelWidth
44607 this.padWidth = 20 + labelWidth;
44611 Roo.form.Column.superclass.onRender.call(this, ct, position);
44613 this.el.setWidth(this.width);
44616 this.el.setHeight(this.height);
44621 renderField : function(f){
44622 f.fieldEl = this.fieldTpl.append(this.el, [
44623 f.id, f.fieldLabel,
44624 f.labelStyle||this.labelStyle||'',
44625 this.elementStyle||'',
44626 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44627 f.itemCls||this.itemCls||'',
44628 f.width ? f.width + this.padWidth : 160 + this.padWidth
44635 * @class Roo.form.FieldSet
44636 * @extends Roo.form.Layout
44637 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44639 * @param {Object} config Configuration options
44641 Roo.form.FieldSet = function(config){
44642 Roo.form.FieldSet.superclass.constructor.call(this, config);
44645 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44647 * @cfg {String} legend
44648 * The text to display as the legend for the FieldSet (defaults to '')
44651 * @cfg {String/Object} autoCreate
44652 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44656 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44659 onRender : function(ct, position){
44660 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44662 this.setLegend(this.legend);
44667 setLegend : function(text){
44669 this.el.child('legend').update(text);
44674 * Ext JS Library 1.1.1
44675 * Copyright(c) 2006-2007, Ext JS, LLC.
44677 * Originally Released Under LGPL - original licence link has changed is not relivant.
44680 * <script type="text/javascript">
44683 * @class Roo.form.VTypes
44684 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44687 Roo.form.VTypes = function(){
44688 // closure these in so they are only created once.
44689 var alpha = /^[a-zA-Z_]+$/;
44690 var alphanum = /^[a-zA-Z0-9_]+$/;
44691 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44692 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44694 // All these messages and functions are configurable
44697 * The function used to validate email addresses
44698 * @param {String} value The email address
44700 'email' : function(v){
44701 return email.test(v);
44704 * The error text to display when the email validation function returns false
44707 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44709 * The keystroke filter mask to be applied on email input
44712 'emailMask' : /[a-z0-9_\.\-@]/i,
44715 * The function used to validate URLs
44716 * @param {String} value The URL
44718 'url' : function(v){
44719 return url.test(v);
44722 * The error text to display when the url validation function returns false
44725 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44728 * The function used to validate alpha values
44729 * @param {String} value The value
44731 'alpha' : function(v){
44732 return alpha.test(v);
44735 * The error text to display when the alpha validation function returns false
44738 'alphaText' : 'This field should only contain letters and _',
44740 * The keystroke filter mask to be applied on alpha input
44743 'alphaMask' : /[a-z_]/i,
44746 * The function used to validate alphanumeric values
44747 * @param {String} value The value
44749 'alphanum' : function(v){
44750 return alphanum.test(v);
44753 * The error text to display when the alphanumeric validation function returns false
44756 'alphanumText' : 'This field should only contain letters, numbers and _',
44758 * The keystroke filter mask to be applied on alphanumeric input
44761 'alphanumMask' : /[a-z0-9_]/i
44763 }();//<script type="text/javascript">
44766 * @class Roo.form.FCKeditor
44767 * @extends Roo.form.TextArea
44768 * Wrapper around the FCKEditor http://www.fckeditor.net
44770 * Creates a new FCKeditor
44771 * @param {Object} config Configuration options
44773 Roo.form.FCKeditor = function(config){
44774 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44777 * @event editorinit
44778 * Fired when the editor is initialized - you can add extra handlers here..
44779 * @param {FCKeditor} this
44780 * @param {Object} the FCK object.
44787 Roo.form.FCKeditor.editors = { };
44788 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44790 //defaultAutoCreate : {
44791 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44795 * @cfg {Object} fck options - see fck manual for details.
44800 * @cfg {Object} fck toolbar set (Basic or Default)
44802 toolbarSet : 'Basic',
44804 * @cfg {Object} fck BasePath
44806 basePath : '/fckeditor/',
44814 onRender : function(ct, position)
44817 this.defaultAutoCreate = {
44819 style:"width:300px;height:60px;",
44820 autocomplete: "off"
44823 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44826 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44827 if(this.preventScrollbars){
44828 this.el.setStyle("overflow", "hidden");
44830 this.el.setHeight(this.growMin);
44833 //console.log('onrender' + this.getId() );
44834 Roo.form.FCKeditor.editors[this.getId()] = this;
44837 this.replaceTextarea() ;
44841 getEditor : function() {
44842 return this.fckEditor;
44845 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44846 * @param {Mixed} value The value to set
44850 setValue : function(value)
44852 //console.log('setValue: ' + value);
44854 if(typeof(value) == 'undefined') { // not sure why this is happending...
44857 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44859 //if(!this.el || !this.getEditor()) {
44860 // this.value = value;
44861 //this.setValue.defer(100,this,[value]);
44865 if(!this.getEditor()) {
44869 this.getEditor().SetData(value);
44876 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44877 * @return {Mixed} value The field value
44879 getValue : function()
44882 if (this.frame && this.frame.dom.style.display == 'none') {
44883 return Roo.form.FCKeditor.superclass.getValue.call(this);
44886 if(!this.el || !this.getEditor()) {
44888 // this.getValue.defer(100,this);
44893 var value=this.getEditor().GetData();
44894 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44895 return Roo.form.FCKeditor.superclass.getValue.call(this);
44901 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44902 * @return {Mixed} value The field value
44904 getRawValue : function()
44906 if (this.frame && this.frame.dom.style.display == 'none') {
44907 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44910 if(!this.el || !this.getEditor()) {
44911 //this.getRawValue.defer(100,this);
44918 var value=this.getEditor().GetData();
44919 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44920 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44924 setSize : function(w,h) {
44928 //if (this.frame && this.frame.dom.style.display == 'none') {
44929 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44932 //if(!this.el || !this.getEditor()) {
44933 // this.setSize.defer(100,this, [w,h]);
44939 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44941 this.frame.dom.setAttribute('width', w);
44942 this.frame.dom.setAttribute('height', h);
44943 this.frame.setSize(w,h);
44947 toggleSourceEdit : function(value) {
44951 this.el.dom.style.display = value ? '' : 'none';
44952 this.frame.dom.style.display = value ? 'none' : '';
44957 focus: function(tag)
44959 if (this.frame.dom.style.display == 'none') {
44960 return Roo.form.FCKeditor.superclass.focus.call(this);
44962 if(!this.el || !this.getEditor()) {
44963 this.focus.defer(100,this, [tag]);
44970 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
44971 this.getEditor().Focus();
44973 if (!this.getEditor().Selection.GetSelection()) {
44974 this.focus.defer(100,this, [tag]);
44979 var r = this.getEditor().EditorDocument.createRange();
44980 r.setStart(tgs[0],0);
44981 r.setEnd(tgs[0],0);
44982 this.getEditor().Selection.GetSelection().removeAllRanges();
44983 this.getEditor().Selection.GetSelection().addRange(r);
44984 this.getEditor().Focus();
44991 replaceTextarea : function()
44993 if ( document.getElementById( this.getId() + '___Frame' ) )
44995 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
44997 // We must check the elements firstly using the Id and then the name.
44998 var oTextarea = document.getElementById( this.getId() );
45000 var colElementsByName = document.getElementsByName( this.getId() ) ;
45002 oTextarea.style.display = 'none' ;
45004 if ( oTextarea.tabIndex ) {
45005 this.TabIndex = oTextarea.tabIndex ;
45008 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45009 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45010 this.frame = Roo.get(this.getId() + '___Frame')
45013 _getConfigHtml : function()
45017 for ( var o in this.fckconfig ) {
45018 sConfig += sConfig.length > 0 ? '&' : '';
45019 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45022 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45026 _getIFrameHtml : function()
45028 var sFile = 'fckeditor.html' ;
45029 /* no idea what this is about..
45032 if ( (/fcksource=true/i).test( window.top.location.search ) )
45033 sFile = 'fckeditor.original.html' ;
45038 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45039 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45042 var html = '<iframe id="' + this.getId() +
45043 '___Frame" src="' + sLink +
45044 '" width="' + this.width +
45045 '" height="' + this.height + '"' +
45046 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45047 ' frameborder="0" scrolling="no"></iframe>' ;
45052 _insertHtmlBefore : function( html, element )
45054 if ( element.insertAdjacentHTML ) {
45056 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45058 var oRange = document.createRange() ;
45059 oRange.setStartBefore( element ) ;
45060 var oFragment = oRange.createContextualFragment( html );
45061 element.parentNode.insertBefore( oFragment, element ) ;
45074 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45076 function FCKeditor_OnComplete(editorInstance){
45077 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45078 f.fckEditor = editorInstance;
45079 //console.log("loaded");
45080 f.fireEvent('editorinit', f, editorInstance);
45100 //<script type="text/javascript">
45102 * @class Roo.form.GridField
45103 * @extends Roo.form.Field
45104 * Embed a grid (or editable grid into a form)
45107 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45109 * xgrid.store = Roo.data.Store
45110 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45111 * xgrid.store.reader = Roo.data.JsonReader
45115 * Creates a new GridField
45116 * @param {Object} config Configuration options
45118 Roo.form.GridField = function(config){
45119 Roo.form.GridField.superclass.constructor.call(this, config);
45123 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45125 * @cfg {Number} width - used to restrict width of grid..
45129 * @cfg {Number} height - used to restrict height of grid..
45133 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45139 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45140 * {tag: "input", type: "checkbox", autocomplete: "off"})
45142 // defaultAutoCreate : { tag: 'div' },
45143 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45145 * @cfg {String} addTitle Text to include for adding a title.
45149 onResize : function(){
45150 Roo.form.Field.superclass.onResize.apply(this, arguments);
45153 initEvents : function(){
45154 // Roo.form.Checkbox.superclass.initEvents.call(this);
45155 // has no events...
45160 getResizeEl : function(){
45164 getPositionEl : function(){
45169 onRender : function(ct, position){
45171 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45172 var style = this.style;
45175 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45176 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45177 this.viewEl = this.wrap.createChild({ tag: 'div' });
45179 this.viewEl.applyStyles(style);
45182 this.viewEl.setWidth(this.width);
45185 this.viewEl.setHeight(this.height);
45187 //if(this.inputValue !== undefined){
45188 //this.setValue(this.value);
45191 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45194 this.grid.render();
45195 this.grid.getDataSource().on('remove', this.refreshValue, this);
45196 this.grid.getDataSource().on('update', this.refreshValue, this);
45197 this.grid.on('afteredit', this.refreshValue, this);
45203 * Sets the value of the item.
45204 * @param {String} either an object or a string..
45206 setValue : function(v){
45208 v = v || []; // empty set..
45209 // this does not seem smart - it really only affects memoryproxy grids..
45210 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45211 var ds = this.grid.getDataSource();
45212 // assumes a json reader..
45214 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45215 ds.loadData( data);
45217 // clear selection so it does not get stale.
45218 if (this.grid.sm) {
45219 this.grid.sm.clearSelections();
45222 Roo.form.GridField.superclass.setValue.call(this, v);
45223 this.refreshValue();
45224 // should load data in the grid really....
45228 refreshValue: function() {
45230 this.grid.getDataSource().each(function(r) {
45233 this.el.dom.value = Roo.encode(val);
45241 * Ext JS Library 1.1.1
45242 * Copyright(c) 2006-2007, Ext JS, LLC.
45244 * Originally Released Under LGPL - original licence link has changed is not relivant.
45247 * <script type="text/javascript">
45250 * @class Roo.form.DisplayField
45251 * @extends Roo.form.Field
45252 * A generic Field to display non-editable data.
45254 * Creates a new Display Field item.
45255 * @param {Object} config Configuration options
45257 Roo.form.DisplayField = function(config){
45258 Roo.form.DisplayField.superclass.constructor.call(this, config);
45262 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45263 inputType: 'hidden',
45269 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45271 focusClass : undefined,
45273 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45275 fieldClass: 'x-form-field',
45278 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45280 valueRenderer: undefined,
45284 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45285 * {tag: "input", type: "checkbox", autocomplete: "off"})
45288 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45290 onResize : function(){
45291 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45295 initEvents : function(){
45296 // Roo.form.Checkbox.superclass.initEvents.call(this);
45297 // has no events...
45302 getResizeEl : function(){
45306 getPositionEl : function(){
45311 onRender : function(ct, position){
45313 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45314 //if(this.inputValue !== undefined){
45315 this.wrap = this.el.wrap();
45317 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45319 if (this.bodyStyle) {
45320 this.viewEl.applyStyles(this.bodyStyle);
45322 //this.viewEl.setStyle('padding', '2px');
45324 this.setValue(this.value);
45329 initValue : Roo.emptyFn,
45334 onClick : function(){
45339 * Sets the checked state of the checkbox.
45340 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45342 setValue : function(v){
45344 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45345 // this might be called before we have a dom element..
45346 if (!this.viewEl) {
45349 this.viewEl.dom.innerHTML = html;
45350 Roo.form.DisplayField.superclass.setValue.call(this, v);
45360 * @class Roo.form.DayPicker
45361 * @extends Roo.form.Field
45362 * A Day picker show [M] [T] [W] ....
45364 * Creates a new Day Picker
45365 * @param {Object} config Configuration options
45367 Roo.form.DayPicker= function(config){
45368 Roo.form.DayPicker.superclass.constructor.call(this, config);
45372 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45374 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45376 focusClass : undefined,
45378 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45380 fieldClass: "x-form-field",
45383 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45384 * {tag: "input", type: "checkbox", autocomplete: "off"})
45386 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45389 actionMode : 'viewEl',
45393 inputType : 'hidden',
45396 inputElement: false, // real input element?
45397 basedOn: false, // ????
45399 isFormField: true, // not sure where this is needed!!!!
45401 onResize : function(){
45402 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45403 if(!this.boxLabel){
45404 this.el.alignTo(this.wrap, 'c-c');
45408 initEvents : function(){
45409 Roo.form.Checkbox.superclass.initEvents.call(this);
45410 this.el.on("click", this.onClick, this);
45411 this.el.on("change", this.onClick, this);
45415 getResizeEl : function(){
45419 getPositionEl : function(){
45425 onRender : function(ct, position){
45426 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45428 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45430 var r1 = '<table><tr>';
45431 var r2 = '<tr class="x-form-daypick-icons">';
45432 for (var i=0; i < 7; i++) {
45433 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45434 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45437 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45438 viewEl.select('img').on('click', this.onClick, this);
45439 this.viewEl = viewEl;
45442 // this will not work on Chrome!!!
45443 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45444 this.el.on('propertychange', this.setFromHidden, this); //ie
45452 initValue : Roo.emptyFn,
45455 * Returns the checked state of the checkbox.
45456 * @return {Boolean} True if checked, else false
45458 getValue : function(){
45459 return this.el.dom.value;
45464 onClick : function(e){
45465 //this.setChecked(!this.checked);
45466 Roo.get(e.target).toggleClass('x-menu-item-checked');
45467 this.refreshValue();
45468 //if(this.el.dom.checked != this.checked){
45469 // this.setValue(this.el.dom.checked);
45474 refreshValue : function()
45477 this.viewEl.select('img',true).each(function(e,i,n) {
45478 val += e.is(".x-menu-item-checked") ? String(n) : '';
45480 this.setValue(val, true);
45484 * Sets the checked state of the checkbox.
45485 * On is always based on a string comparison between inputValue and the param.
45486 * @param {Boolean/String} value - the value to set
45487 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45489 setValue : function(v,suppressEvent){
45490 if (!this.el.dom) {
45493 var old = this.el.dom.value ;
45494 this.el.dom.value = v;
45495 if (suppressEvent) {
45499 // update display..
45500 this.viewEl.select('img',true).each(function(e,i,n) {
45502 var on = e.is(".x-menu-item-checked");
45503 var newv = v.indexOf(String(n)) > -1;
45505 e.toggleClass('x-menu-item-checked');
45511 this.fireEvent('change', this, v, old);
45516 // handle setting of hidden value by some other method!!?!?
45517 setFromHidden: function()
45522 //console.log("SET FROM HIDDEN");
45523 //alert('setFrom hidden');
45524 this.setValue(this.el.dom.value);
45527 onDestroy : function()
45530 Roo.get(this.viewEl).remove();
45533 Roo.form.DayPicker.superclass.onDestroy.call(this);
45537 * RooJS Library 1.1.1
45538 * Copyright(c) 2008-2011 Alan Knowles
45545 * @class Roo.form.ComboCheck
45546 * @extends Roo.form.ComboBox
45547 * A combobox for multiple select items.
45549 * FIXME - could do with a reset button..
45552 * Create a new ComboCheck
45553 * @param {Object} config Configuration options
45555 Roo.form.ComboCheck = function(config){
45556 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45557 // should verify some data...
45559 // hiddenName = required..
45560 // displayField = required
45561 // valudField == required
45562 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45564 Roo.each(req, function(e) {
45565 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45566 throw "Roo.form.ComboCheck : missing value for: " + e;
45573 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45578 selectedClass: 'x-menu-item-checked',
45581 onRender : function(ct, position){
45587 var cls = 'x-combo-list';
45590 this.tpl = new Roo.Template({
45591 html : '<div class="'+cls+'-item x-menu-check-item">' +
45592 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45593 '<span>{' + this.displayField + '}</span>' +
45600 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45601 this.view.singleSelect = false;
45602 this.view.multiSelect = true;
45603 this.view.toggleSelect = true;
45604 this.pageTb.add(new Roo.Toolbar.Fill(), {
45607 handler: function()
45614 onViewOver : function(e, t){
45620 onViewClick : function(doFocus,index){
45624 select: function () {
45625 //Roo.log("SELECT CALLED");
45628 selectByValue : function(xv, scrollIntoView){
45629 var ar = this.getValueArray();
45632 Roo.each(ar, function(v) {
45633 if(v === undefined || v === null){
45636 var r = this.findRecord(this.valueField, v);
45638 sels.push(this.store.indexOf(r))
45642 this.view.select(sels);
45648 onSelect : function(record, index){
45649 // Roo.log("onselect Called");
45650 // this is only called by the clear button now..
45651 this.view.clearSelections();
45652 this.setValue('[]');
45653 if (this.value != this.valueBefore) {
45654 this.fireEvent('change', this, this.value, this.valueBefore);
45655 this.valueBefore = this.value;
45658 getValueArray : function()
45663 //Roo.log(this.value);
45664 if (typeof(this.value) == 'undefined') {
45667 var ar = Roo.decode(this.value);
45668 return ar instanceof Array ? ar : []; //?? valid?
45671 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45676 expand : function ()
45679 Roo.form.ComboCheck.superclass.expand.call(this);
45680 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
45681 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
45686 collapse : function(){
45687 Roo.form.ComboCheck.superclass.collapse.call(this);
45688 var sl = this.view.getSelectedIndexes();
45689 var st = this.store;
45693 Roo.each(sl, function(i) {
45695 nv.push(r.get(this.valueField));
45697 this.setValue(Roo.encode(nv));
45698 if (this.value != this.valueBefore) {
45700 this.fireEvent('change', this, this.value, this.valueBefore);
45701 this.valueBefore = this.value;
45706 setValue : function(v){
45710 var vals = this.getValueArray();
45712 Roo.each(vals, function(k) {
45713 var r = this.findRecord(this.valueField, k);
45715 tv.push(r.data[this.displayField]);
45716 }else if(this.valueNotFoundText !== undefined){
45717 tv.push( this.valueNotFoundText );
45722 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45723 this.hiddenField.value = v;
45729 * Ext JS Library 1.1.1
45730 * Copyright(c) 2006-2007, Ext JS, LLC.
45732 * Originally Released Under LGPL - original licence link has changed is not relivant.
45735 * <script type="text/javascript">
45739 * @class Roo.form.Signature
45740 * @extends Roo.form.Field
45744 * @param {Object} config Configuration options
45747 Roo.form.Signature = function(config){
45748 Roo.form.Signature.superclass.constructor.call(this, config);
45750 this.addEvents({// not in used??
45753 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
45754 * @param {Roo.form.Signature} combo This combo box
45759 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
45760 * @param {Roo.form.ComboBox} combo This combo box
45761 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
45767 Roo.extend(Roo.form.Signature, Roo.form.Field, {
45769 * @cfg {Object} labels Label to use when rendering a form.
45773 * confirm : "Confirm"
45778 confirm : "Confirm"
45781 * @cfg {Number} width The signature panel width (defaults to 300)
45785 * @cfg {Number} height The signature panel height (defaults to 100)
45789 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
45791 allowBlank : false,
45794 // {Object} signPanel The signature SVG panel element (defaults to {})
45796 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
45797 isMouseDown : false,
45798 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
45799 isConfirmed : false,
45800 // {String} signatureTmp SVG mapping string (defaults to empty string)
45804 defaultAutoCreate : { // modified by initCompnoent..
45810 onRender : function(ct, position){
45812 Roo.form.Signature.superclass.onRender.call(this, ct, position);
45814 this.wrap = this.el.wrap({
45815 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
45818 this.createToolbar(this);
45819 this.signPanel = this.wrap.createChild({
45821 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
45825 this.svgID = Roo.id();
45826 this.svgEl = this.signPanel.createChild({
45827 xmlns : 'http://www.w3.org/2000/svg',
45829 id : this.svgID + "-svg",
45831 height: this.height,
45832 viewBox: '0 0 '+this.width+' '+this.height,
45836 id: this.svgID + "-svg-r",
45838 height: this.height,
45843 id: this.svgID + "-svg-l",
45845 y1: (this.height*0.8), // start set the line in 80% of height
45846 x2: this.width, // end
45847 y2: (this.height*0.8), // end set the line in 80% of height
45849 'stroke-width': "1",
45850 'stroke-dasharray': "3",
45851 'shape-rendering': "crispEdges",
45852 'pointer-events': "none"
45856 id: this.svgID + "-svg-p",
45858 'stroke-width': "3",
45860 'pointer-events': 'none'
45865 this.svgBox = this.svgEl.dom.getScreenCTM();
45867 createSVG : function(){
45868 var svg = this.signPanel;
45869 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
45872 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
45873 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
45874 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
45875 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
45876 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
45877 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
45878 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
45881 isTouchEvent : function(e){
45882 return e.type.match(/^touch/);
45884 getCoords : function (e) {
45885 var pt = this.svgEl.dom.createSVGPoint();
45888 if (this.isTouchEvent(e)) {
45889 pt.x = e.targetTouches[0].clientX
45890 pt.y = e.targetTouches[0].clientY;
45892 var a = this.svgEl.dom.getScreenCTM();
45893 var b = a.inverse();
45894 var mx = pt.matrixTransform(b);
45895 return mx.x + ',' + mx.y;
45897 //mouse event headler
45898 down : function (e) {
45899 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
45900 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
45902 this.isMouseDown = true;
45904 e.preventDefault();
45906 move : function (e) {
45907 if (this.isMouseDown) {
45908 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
45909 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
45912 e.preventDefault();
45914 up : function (e) {
45915 this.isMouseDown = false;
45916 var sp = this.signatureTmp.split(' ');
45919 if(!sp[sp.length-2].match(/^L/)){
45923 this.signatureTmp = sp.join(" ");
45926 if(this.getValue() != this.signatureTmp){
45927 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
45928 this.isConfirmed = false;
45930 e.preventDefault();
45934 * Protected method that will not generally be called directly. It
45935 * is called when the editor creates its toolbar. Override this method if you need to
45936 * add custom toolbar buttons.
45937 * @param {HtmlEditor} editor
45939 createToolbar : function(editor){
45940 function btn(id, toggle, handler){
45941 var xid = fid + '-'+ id ;
45945 cls : 'x-btn-icon x-edit-'+id,
45946 enableToggle:toggle !== false,
45947 scope: editor, // was editor...
45948 handler:handler||editor.relayBtnCmd,
45949 clickEvent:'mousedown',
45950 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45956 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45960 cls : ' x-signature-btn x-signature-'+id,
45961 scope: editor, // was editor...
45962 handler: this.reset,
45963 clickEvent:'mousedown',
45964 text: this.labels.clear
45971 cls : ' x-signature-btn x-signature-'+id,
45972 scope: editor, // was editor...
45973 handler: this.confirmHandler,
45974 clickEvent:'mousedown',
45975 text: this.labels.confirm
45982 * when user is clicked confirm then show this image.....
45984 * @return {String} Image Data URI
45986 getImageDataURI : function(){
45987 var svg = this.svgEl.dom.parentNode.innerHTML;
45988 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
45993 * @return {Boolean} this.isConfirmed
45995 getConfirmed : function(){
45996 return this.isConfirmed;
46000 * @return {Number} this.width
46002 getWidth : function(){
46007 * @return {Number} this.height
46009 getHeight : function(){
46010 return this.height;
46013 getSignature : function(){
46014 return this.signatureTmp;
46017 reset : function(){
46018 this.signatureTmp = '';
46019 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46020 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46021 this.isConfirmed = false;
46022 Roo.form.Signature.superclass.reset.call(this);
46024 setSignature : function(s){
46025 this.signatureTmp = s;
46026 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46027 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46029 this.isConfirmed = false;
46030 Roo.form.Signature.superclass.reset.call(this);
46033 // Roo.log(this.signPanel.dom.contentWindow.up())
46036 setConfirmed : function(){
46040 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46043 confirmHandler : function(){
46044 if(!this.getSignature()){
46048 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46049 this.setValue(this.getSignature());
46050 this.isConfirmed = true;
46052 this.fireEvent('confirm', this);
46055 // Subclasses should provide the validation implementation by overriding this
46056 validateValue : function(value){
46057 if(this.allowBlank){
46061 if(this.isConfirmed){
46066 });//<script type="text/javasscript">
46070 * @class Roo.DDView
46071 * A DnD enabled version of Roo.View.
46072 * @param {Element/String} container The Element in which to create the View.
46073 * @param {String} tpl The template string used to create the markup for each element of the View
46074 * @param {Object} config The configuration properties. These include all the config options of
46075 * {@link Roo.View} plus some specific to this class.<br>
46077 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
46078 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
46080 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
46081 .x-view-drag-insert-above {
46082 border-top:1px dotted #3366cc;
46084 .x-view-drag-insert-below {
46085 border-bottom:1px dotted #3366cc;
46091 Roo.DDView = function(container, tpl, config) {
46092 Roo.DDView.superclass.constructor.apply(this, arguments);
46093 this.getEl().setStyle("outline", "0px none");
46094 this.getEl().unselectable();
46095 if (this.dragGroup) {
46096 this.setDraggable(this.dragGroup.split(","));
46098 if (this.dropGroup) {
46099 this.setDroppable(this.dropGroup.split(","));
46101 if (this.deletable) {
46102 this.setDeletable();
46104 this.isDirtyFlag = false;
46110 Roo.extend(Roo.DDView, Roo.View, {
46111 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
46112 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
46113 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
46114 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
46118 reset: Roo.emptyFn,
46120 clearInvalid: Roo.form.Field.prototype.clearInvalid,
46122 validate: function() {
46126 destroy: function() {
46127 this.purgeListeners();
46128 this.getEl.removeAllListeners();
46129 this.getEl().remove();
46130 if (this.dragZone) {
46131 if (this.dragZone.destroy) {
46132 this.dragZone.destroy();
46135 if (this.dropZone) {
46136 if (this.dropZone.destroy) {
46137 this.dropZone.destroy();
46142 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
46143 getName: function() {
46147 /** Loads the View from a JSON string representing the Records to put into the Store. */
46148 setValue: function(v) {
46150 throw "DDView.setValue(). DDView must be constructed with a valid Store";
46153 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
46154 this.store.proxy = new Roo.data.MemoryProxy(data);
46158 /** @return {String} a parenthesised list of the ids of the Records in the View. */
46159 getValue: function() {
46161 this.store.each(function(rec) {
46162 result += rec.id + ',';
46164 return result.substr(0, result.length - 1) + ')';
46167 getIds: function() {
46168 var i = 0, result = new Array(this.store.getCount());
46169 this.store.each(function(rec) {
46170 result[i++] = rec.id;
46175 isDirty: function() {
46176 return this.isDirtyFlag;
46180 * Part of the Roo.dd.DropZone interface. If no target node is found, the
46181 * whole Element becomes the target, and this causes the drop gesture to append.
46183 getTargetFromEvent : function(e) {
46184 var target = e.getTarget();
46185 while ((target !== null) && (target.parentNode != this.el.dom)) {
46186 target = target.parentNode;
46189 target = this.el.dom.lastChild || this.el.dom;
46195 * Create the drag data which consists of an object which has the property "ddel" as
46196 * the drag proxy element.
46198 getDragData : function(e) {
46199 var target = this.findItemFromChild(e.getTarget());
46201 this.handleSelection(e);
46202 var selNodes = this.getSelectedNodes();
46205 copy: this.copy || (this.allowCopy && e.ctrlKey),
46209 var selectedIndices = this.getSelectedIndexes();
46210 for (var i = 0; i < selectedIndices.length; i++) {
46211 dragData.records.push(this.store.getAt(selectedIndices[i]));
46213 if (selNodes.length == 1) {
46214 dragData.ddel = target.cloneNode(true); // the div element
46216 var div = document.createElement('div'); // create the multi element drag "ghost"
46217 div.className = 'multi-proxy';
46218 for (var i = 0, len = selNodes.length; i < len; i++) {
46219 div.appendChild(selNodes[i].cloneNode(true));
46221 dragData.ddel = div;
46223 //console.log(dragData)
46224 //console.log(dragData.ddel.innerHTML)
46227 //console.log('nodragData')
46231 /** Specify to which ddGroup items in this DDView may be dragged. */
46232 setDraggable: function(ddGroup) {
46233 if (ddGroup instanceof Array) {
46234 Roo.each(ddGroup, this.setDraggable, this);
46237 if (this.dragZone) {
46238 this.dragZone.addToGroup(ddGroup);
46240 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
46241 containerScroll: true,
46245 // Draggability implies selection. DragZone's mousedown selects the element.
46246 if (!this.multiSelect) { this.singleSelect = true; }
46248 // Wire the DragZone's handlers up to methods in *this*
46249 this.dragZone.getDragData = this.getDragData.createDelegate(this);
46253 /** Specify from which ddGroup this DDView accepts drops. */
46254 setDroppable: function(ddGroup) {
46255 if (ddGroup instanceof Array) {
46256 Roo.each(ddGroup, this.setDroppable, this);
46259 if (this.dropZone) {
46260 this.dropZone.addToGroup(ddGroup);
46262 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
46263 containerScroll: true,
46267 // Wire the DropZone's handlers up to methods in *this*
46268 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
46269 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
46270 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
46271 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
46272 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
46276 /** Decide whether to drop above or below a View node. */
46277 getDropPoint : function(e, n, dd){
46278 if (n == this.el.dom) { return "above"; }
46279 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
46280 var c = t + (b - t) / 2;
46281 var y = Roo.lib.Event.getPageY(e);
46289 onNodeEnter : function(n, dd, e, data){
46293 onNodeOver : function(n, dd, e, data){
46294 var pt = this.getDropPoint(e, n, dd);
46295 // set the insert point style on the target node
46296 var dragElClass = this.dropNotAllowed;
46299 if (pt == "above"){
46300 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
46301 targetElClass = "x-view-drag-insert-above";
46303 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
46304 targetElClass = "x-view-drag-insert-below";
46306 if (this.lastInsertClass != targetElClass){
46307 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
46308 this.lastInsertClass = targetElClass;
46311 return dragElClass;
46314 onNodeOut : function(n, dd, e, data){
46315 this.removeDropIndicators(n);
46318 onNodeDrop : function(n, dd, e, data){
46319 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
46322 var pt = this.getDropPoint(e, n, dd);
46323 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
46324 if (pt == "below") { insertAt++; }
46325 for (var i = 0; i < data.records.length; i++) {
46326 var r = data.records[i];
46327 var dup = this.store.getById(r.id);
46328 if (dup && (dd != this.dragZone)) {
46329 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
46332 this.store.insert(insertAt++, r.copy());
46334 data.source.isDirtyFlag = true;
46336 this.store.insert(insertAt++, r);
46338 this.isDirtyFlag = true;
46341 this.dragZone.cachedTarget = null;
46345 removeDropIndicators : function(n){
46347 Roo.fly(n).removeClass([
46348 "x-view-drag-insert-above",
46349 "x-view-drag-insert-below"]);
46350 this.lastInsertClass = "_noclass";
46355 * Utility method. Add a delete option to the DDView's context menu.
46356 * @param {String} imageUrl The URL of the "delete" icon image.
46358 setDeletable: function(imageUrl) {
46359 if (!this.singleSelect && !this.multiSelect) {
46360 this.singleSelect = true;
46362 var c = this.getContextMenu();
46363 this.contextMenu.on("itemclick", function(item) {
46366 this.remove(this.getSelectedIndexes());
46370 this.contextMenu.add({
46377 /** Return the context menu for this DDView. */
46378 getContextMenu: function() {
46379 if (!this.contextMenu) {
46380 // Create the View's context menu
46381 this.contextMenu = new Roo.menu.Menu({
46382 id: this.id + "-contextmenu"
46384 this.el.on("contextmenu", this.showContextMenu, this);
46386 return this.contextMenu;
46389 disableContextMenu: function() {
46390 if (this.contextMenu) {
46391 this.el.un("contextmenu", this.showContextMenu, this);
46395 showContextMenu: function(e, item) {
46396 item = this.findItemFromChild(e.getTarget());
46399 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
46400 this.contextMenu.showAt(e.getXY());
46405 * Remove {@link Roo.data.Record}s at the specified indices.
46406 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
46408 remove: function(selectedIndices) {
46409 selectedIndices = [].concat(selectedIndices);
46410 for (var i = 0; i < selectedIndices.length; i++) {
46411 var rec = this.store.getAt(selectedIndices[i]);
46412 this.store.remove(rec);
46417 * Double click fires the event, but also, if this is draggable, and there is only one other
46418 * related DropZone, it transfers the selected node.
46420 onDblClick : function(e){
46421 var item = this.findItemFromChild(e.getTarget());
46423 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
46426 if (this.dragGroup) {
46427 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
46428 while (targets.indexOf(this.dropZone) > -1) {
46429 targets.remove(this.dropZone);
46431 if (targets.length == 1) {
46432 this.dragZone.cachedTarget = null;
46433 var el = Roo.get(targets[0].getEl());
46434 var box = el.getBox(true);
46435 targets[0].onNodeDrop(el.dom, {
46437 xy: [box.x, box.y + box.height - 1]
46438 }, null, this.getDragData(e));
46444 handleSelection: function(e) {
46445 this.dragZone.cachedTarget = null;
46446 var item = this.findItemFromChild(e.getTarget());
46448 this.clearSelections(true);
46451 if (item && (this.multiSelect || this.singleSelect)){
46452 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
46453 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
46454 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
46455 this.unselect(item);
46457 this.select(item, this.multiSelect && e.ctrlKey);
46458 this.lastSelection = item;
46463 onItemClick : function(item, index, e){
46464 if(this.fireEvent("beforeclick", this, index, item, e) === false){
46470 unselect : function(nodeInfo, suppressEvent){
46471 var node = this.getNode(nodeInfo);
46472 if(node && this.isSelected(node)){
46473 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
46474 Roo.fly(node).removeClass(this.selectedClass);
46475 this.selections.remove(node);
46476 if(!suppressEvent){
46477 this.fireEvent("selectionchange", this, this.selections);
46485 * Ext JS Library 1.1.1
46486 * Copyright(c) 2006-2007, Ext JS, LLC.
46488 * Originally Released Under LGPL - original licence link has changed is not relivant.
46491 * <script type="text/javascript">
46495 * @class Roo.LayoutManager
46496 * @extends Roo.util.Observable
46497 * Base class for layout managers.
46499 Roo.LayoutManager = function(container, config){
46500 Roo.LayoutManager.superclass.constructor.call(this);
46501 this.el = Roo.get(container);
46502 // ie scrollbar fix
46503 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
46504 document.body.scroll = "no";
46505 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
46506 this.el.position('relative');
46508 this.id = this.el.id;
46509 this.el.addClass("x-layout-container");
46510 /** false to disable window resize monitoring @type Boolean */
46511 this.monitorWindowResize = true;
46516 * Fires when a layout is performed.
46517 * @param {Roo.LayoutManager} this
46521 * @event regionresized
46522 * Fires when the user resizes a region.
46523 * @param {Roo.LayoutRegion} region The resized region
46524 * @param {Number} newSize The new size (width for east/west, height for north/south)
46526 "regionresized" : true,
46528 * @event regioncollapsed
46529 * Fires when a region is collapsed.
46530 * @param {Roo.LayoutRegion} region The collapsed region
46532 "regioncollapsed" : true,
46534 * @event regionexpanded
46535 * Fires when a region is expanded.
46536 * @param {Roo.LayoutRegion} region The expanded region
46538 "regionexpanded" : true
46540 this.updating = false;
46541 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
46544 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
46546 * Returns true if this layout is currently being updated
46547 * @return {Boolean}
46549 isUpdating : function(){
46550 return this.updating;
46554 * Suspend the LayoutManager from doing auto-layouts while
46555 * making multiple add or remove calls
46557 beginUpdate : function(){
46558 this.updating = true;
46562 * Restore auto-layouts and optionally disable the manager from performing a layout
46563 * @param {Boolean} noLayout true to disable a layout update
46565 endUpdate : function(noLayout){
46566 this.updating = false;
46572 layout: function(){
46576 onRegionResized : function(region, newSize){
46577 this.fireEvent("regionresized", region, newSize);
46581 onRegionCollapsed : function(region){
46582 this.fireEvent("regioncollapsed", region);
46585 onRegionExpanded : function(region){
46586 this.fireEvent("regionexpanded", region);
46590 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
46591 * performs box-model adjustments.
46592 * @return {Object} The size as an object {width: (the width), height: (the height)}
46594 getViewSize : function(){
46596 if(this.el.dom != document.body){
46597 size = this.el.getSize();
46599 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
46601 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
46602 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
46607 * Returns the Element this layout is bound to.
46608 * @return {Roo.Element}
46610 getEl : function(){
46615 * Returns the specified region.
46616 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
46617 * @return {Roo.LayoutRegion}
46619 getRegion : function(target){
46620 return this.regions[target.toLowerCase()];
46623 onWindowResize : function(){
46624 if(this.monitorWindowResize){
46630 * Ext JS Library 1.1.1
46631 * Copyright(c) 2006-2007, Ext JS, LLC.
46633 * Originally Released Under LGPL - original licence link has changed is not relivant.
46636 * <script type="text/javascript">
46639 * @class Roo.BorderLayout
46640 * @extends Roo.LayoutManager
46641 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
46642 * please see: <br><br>
46643 * <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>
46644 * <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>
46647 var layout = new Roo.BorderLayout(document.body, {
46681 preferredTabWidth: 150
46686 var CP = Roo.ContentPanel;
46688 layout.beginUpdate();
46689 layout.add("north", new CP("north", "North"));
46690 layout.add("south", new CP("south", {title: "South", closable: true}));
46691 layout.add("west", new CP("west", {title: "West"}));
46692 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
46693 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
46694 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
46695 layout.getRegion("center").showPanel("center1");
46696 layout.endUpdate();
46699 <b>The container the layout is rendered into can be either the body element or any other element.
46700 If it is not the body element, the container needs to either be an absolute positioned element,
46701 or you will need to add "position:relative" to the css of the container. You will also need to specify
46702 the container size if it is not the body element.</b>
46705 * Create a new BorderLayout
46706 * @param {String/HTMLElement/Element} container The container this layout is bound to
46707 * @param {Object} config Configuration options
46709 Roo.BorderLayout = function(container, config){
46710 config = config || {};
46711 Roo.BorderLayout.superclass.constructor.call(this, container, config);
46712 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
46713 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
46714 var target = this.factory.validRegions[i];
46715 if(config[target]){
46716 this.addRegion(target, config[target]);
46721 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
46723 * Creates and adds a new region if it doesn't already exist.
46724 * @param {String} target The target region key (north, south, east, west or center).
46725 * @param {Object} config The regions config object
46726 * @return {BorderLayoutRegion} The new region
46728 addRegion : function(target, config){
46729 if(!this.regions[target]){
46730 var r = this.factory.create(target, this, config);
46731 this.bindRegion(target, r);
46733 return this.regions[target];
46737 bindRegion : function(name, r){
46738 this.regions[name] = r;
46739 r.on("visibilitychange", this.layout, this);
46740 r.on("paneladded", this.layout, this);
46741 r.on("panelremoved", this.layout, this);
46742 r.on("invalidated", this.layout, this);
46743 r.on("resized", this.onRegionResized, this);
46744 r.on("collapsed", this.onRegionCollapsed, this);
46745 r.on("expanded", this.onRegionExpanded, this);
46749 * Performs a layout update.
46751 layout : function(){
46752 if(this.updating) return;
46753 var size = this.getViewSize();
46754 var w = size.width;
46755 var h = size.height;
46760 //var x = 0, y = 0;
46762 var rs = this.regions;
46763 var north = rs["north"];
46764 var south = rs["south"];
46765 var west = rs["west"];
46766 var east = rs["east"];
46767 var center = rs["center"];
46768 //if(this.hideOnLayout){ // not supported anymore
46769 //c.el.setStyle("display", "none");
46771 if(north && north.isVisible()){
46772 var b = north.getBox();
46773 var m = north.getMargins();
46774 b.width = w - (m.left+m.right);
46777 centerY = b.height + b.y + m.bottom;
46778 centerH -= centerY;
46779 north.updateBox(this.safeBox(b));
46781 if(south && south.isVisible()){
46782 var b = south.getBox();
46783 var m = south.getMargins();
46784 b.width = w - (m.left+m.right);
46786 var totalHeight = (b.height + m.top + m.bottom);
46787 b.y = h - totalHeight + m.top;
46788 centerH -= totalHeight;
46789 south.updateBox(this.safeBox(b));
46791 if(west && west.isVisible()){
46792 var b = west.getBox();
46793 var m = west.getMargins();
46794 b.height = centerH - (m.top+m.bottom);
46796 b.y = centerY + m.top;
46797 var totalWidth = (b.width + m.left + m.right);
46798 centerX += totalWidth;
46799 centerW -= totalWidth;
46800 west.updateBox(this.safeBox(b));
46802 if(east && east.isVisible()){
46803 var b = east.getBox();
46804 var m = east.getMargins();
46805 b.height = centerH - (m.top+m.bottom);
46806 var totalWidth = (b.width + m.left + m.right);
46807 b.x = w - totalWidth + m.left;
46808 b.y = centerY + m.top;
46809 centerW -= totalWidth;
46810 east.updateBox(this.safeBox(b));
46813 var m = center.getMargins();
46815 x: centerX + m.left,
46816 y: centerY + m.top,
46817 width: centerW - (m.left+m.right),
46818 height: centerH - (m.top+m.bottom)
46820 //if(this.hideOnLayout){
46821 //center.el.setStyle("display", "block");
46823 center.updateBox(this.safeBox(centerBox));
46826 this.fireEvent("layout", this);
46830 safeBox : function(box){
46831 box.width = Math.max(0, box.width);
46832 box.height = Math.max(0, box.height);
46837 * Adds a ContentPanel (or subclass) to this layout.
46838 * @param {String} target The target region key (north, south, east, west or center).
46839 * @param {Roo.ContentPanel} panel The panel to add
46840 * @return {Roo.ContentPanel} The added panel
46842 add : function(target, panel){
46844 target = target.toLowerCase();
46845 return this.regions[target].add(panel);
46849 * Remove a ContentPanel (or subclass) to this layout.
46850 * @param {String} target The target region key (north, south, east, west or center).
46851 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
46852 * @return {Roo.ContentPanel} The removed panel
46854 remove : function(target, panel){
46855 target = target.toLowerCase();
46856 return this.regions[target].remove(panel);
46860 * Searches all regions for a panel with the specified id
46861 * @param {String} panelId
46862 * @return {Roo.ContentPanel} The panel or null if it wasn't found
46864 findPanel : function(panelId){
46865 var rs = this.regions;
46866 for(var target in rs){
46867 if(typeof rs[target] != "function"){
46868 var p = rs[target].getPanel(panelId);
46878 * Searches all regions for a panel with the specified id and activates (shows) it.
46879 * @param {String/ContentPanel} panelId The panels id or the panel itself
46880 * @return {Roo.ContentPanel} The shown panel or null
46882 showPanel : function(panelId) {
46883 var rs = this.regions;
46884 for(var target in rs){
46885 var r = rs[target];
46886 if(typeof r != "function"){
46887 if(r.hasPanel(panelId)){
46888 return r.showPanel(panelId);
46896 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
46897 * @param {Roo.state.Provider} provider (optional) An alternate state provider
46899 restoreState : function(provider){
46901 provider = Roo.state.Manager;
46903 var sm = new Roo.LayoutStateManager();
46904 sm.init(this, provider);
46908 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
46909 * object should contain properties for each region to add ContentPanels to, and each property's value should be
46910 * a valid ContentPanel config object. Example:
46912 // Create the main layout
46913 var layout = new Roo.BorderLayout('main-ct', {
46924 // Create and add multiple ContentPanels at once via configs
46927 id: 'source-files',
46929 title:'Ext Source Files',
46942 * @param {Object} regions An object containing ContentPanel configs by region name
46944 batchAdd : function(regions){
46945 this.beginUpdate();
46946 for(var rname in regions){
46947 var lr = this.regions[rname];
46949 this.addTypedPanels(lr, regions[rname]);
46956 addTypedPanels : function(lr, ps){
46957 if(typeof ps == 'string'){
46958 lr.add(new Roo.ContentPanel(ps));
46960 else if(ps instanceof Array){
46961 for(var i =0, len = ps.length; i < len; i++){
46962 this.addTypedPanels(lr, ps[i]);
46965 else if(!ps.events){ // raw config?
46967 delete ps.el; // prevent conflict
46968 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
46970 else { // panel object assumed!
46975 * Adds a xtype elements to the layout.
46979 xtype : 'ContentPanel',
46986 xtype : 'NestedLayoutPanel',
46992 items : [ ... list of content panels or nested layout panels.. ]
46996 * @param {Object} cfg Xtype definition of item to add.
46998 addxtype : function(cfg)
47000 // basically accepts a pannel...
47001 // can accept a layout region..!?!?
47002 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
47004 if (!cfg.xtype.match(/Panel$/)) {
47009 if (typeof(cfg.region) == 'undefined') {
47010 Roo.log("Failed to add Panel, region was not set");
47014 var region = cfg.region;
47020 xitems = cfg.items;
47027 case 'ContentPanel': // ContentPanel (el, cfg)
47028 case 'ScrollPanel': // ContentPanel (el, cfg)
47030 if(cfg.autoCreate) {
47031 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47033 var el = this.el.createChild();
47034 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
47037 this.add(region, ret);
47041 case 'TreePanel': // our new panel!
47042 cfg.el = this.el.createChild();
47043 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47044 this.add(region, ret);
47047 case 'NestedLayoutPanel':
47048 // create a new Layout (which is a Border Layout...
47049 var el = this.el.createChild();
47050 var clayout = cfg.layout;
47052 clayout.items = clayout.items || [];
47053 // replace this exitems with the clayout ones..
47054 xitems = clayout.items;
47057 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
47058 cfg.background = false;
47060 var layout = new Roo.BorderLayout(el, clayout);
47062 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
47063 //console.log('adding nested layout panel ' + cfg.toSource());
47064 this.add(region, ret);
47065 nb = {}; /// find first...
47070 // needs grid and region
47072 //var el = this.getRegion(region).el.createChild();
47073 var el = this.el.createChild();
47074 // create the grid first...
47076 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
47078 if (region == 'center' && this.active ) {
47079 cfg.background = false;
47081 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
47083 this.add(region, ret);
47084 if (cfg.background) {
47085 ret.on('activate', function(gp) {
47086 if (!gp.grid.rendered) {
47101 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
47103 // GridPanel (grid, cfg)
47106 this.beginUpdate();
47110 Roo.each(xitems, function(i) {
47111 region = nb && i.region ? i.region : false;
47113 var add = ret.addxtype(i);
47116 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
47117 if (!i.background) {
47118 abn[region] = nb[region] ;
47125 // make the last non-background panel active..
47126 //if (nb) { Roo.log(abn); }
47129 for(var r in abn) {
47130 region = this.getRegion(r);
47132 // tried using nb[r], but it does not work..
47134 region.showPanel(abn[r]);
47145 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
47146 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
47147 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
47148 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
47151 var CP = Roo.ContentPanel;
47153 var layout = Roo.BorderLayout.create({
47157 panels: [new CP("north", "North")]
47166 panels: [new CP("west", {title: "West"})]
47175 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
47184 panels: [new CP("south", {title: "South", closable: true})]
47191 preferredTabWidth: 150,
47193 new CP("center1", {title: "Close Me", closable: true}),
47194 new CP("center2", {title: "Center Panel", closable: false})
47199 layout.getRegion("center").showPanel("center1");
47204 Roo.BorderLayout.create = function(config, targetEl){
47205 var layout = new Roo.BorderLayout(targetEl || document.body, config);
47206 layout.beginUpdate();
47207 var regions = Roo.BorderLayout.RegionFactory.validRegions;
47208 for(var j = 0, jlen = regions.length; j < jlen; j++){
47209 var lr = regions[j];
47210 if(layout.regions[lr] && config[lr].panels){
47211 var r = layout.regions[lr];
47212 var ps = config[lr].panels;
47213 layout.addTypedPanels(r, ps);
47216 layout.endUpdate();
47221 Roo.BorderLayout.RegionFactory = {
47223 validRegions : ["north","south","east","west","center"],
47226 create : function(target, mgr, config){
47227 target = target.toLowerCase();
47228 if(config.lightweight || config.basic){
47229 return new Roo.BasicLayoutRegion(mgr, config, target);
47233 return new Roo.NorthLayoutRegion(mgr, config);
47235 return new Roo.SouthLayoutRegion(mgr, config);
47237 return new Roo.EastLayoutRegion(mgr, config);
47239 return new Roo.WestLayoutRegion(mgr, config);
47241 return new Roo.CenterLayoutRegion(mgr, config);
47243 throw 'Layout region "'+target+'" not supported.';
47247 * Ext JS Library 1.1.1
47248 * Copyright(c) 2006-2007, Ext JS, LLC.
47250 * Originally Released Under LGPL - original licence link has changed is not relivant.
47253 * <script type="text/javascript">
47257 * @class Roo.BasicLayoutRegion
47258 * @extends Roo.util.Observable
47259 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
47260 * and does not have a titlebar, tabs or any other features. All it does is size and position
47261 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
47263 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
47265 this.position = pos;
47268 * @scope Roo.BasicLayoutRegion
47272 * @event beforeremove
47273 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
47274 * @param {Roo.LayoutRegion} this
47275 * @param {Roo.ContentPanel} panel The panel
47276 * @param {Object} e The cancel event object
47278 "beforeremove" : true,
47280 * @event invalidated
47281 * Fires when the layout for this region is changed.
47282 * @param {Roo.LayoutRegion} this
47284 "invalidated" : true,
47286 * @event visibilitychange
47287 * Fires when this region is shown or hidden
47288 * @param {Roo.LayoutRegion} this
47289 * @param {Boolean} visibility true or false
47291 "visibilitychange" : true,
47293 * @event paneladded
47294 * Fires when a panel is added.
47295 * @param {Roo.LayoutRegion} this
47296 * @param {Roo.ContentPanel} panel The panel
47298 "paneladded" : true,
47300 * @event panelremoved
47301 * Fires when a panel is removed.
47302 * @param {Roo.LayoutRegion} this
47303 * @param {Roo.ContentPanel} panel The panel
47305 "panelremoved" : true,
47308 * Fires when this region is collapsed.
47309 * @param {Roo.LayoutRegion} this
47311 "collapsed" : true,
47314 * Fires when this region is expanded.
47315 * @param {Roo.LayoutRegion} this
47320 * Fires when this region is slid into view.
47321 * @param {Roo.LayoutRegion} this
47323 "slideshow" : true,
47326 * Fires when this region slides out of view.
47327 * @param {Roo.LayoutRegion} this
47329 "slidehide" : true,
47331 * @event panelactivated
47332 * Fires when a panel is activated.
47333 * @param {Roo.LayoutRegion} this
47334 * @param {Roo.ContentPanel} panel The activated panel
47336 "panelactivated" : true,
47339 * Fires when the user resizes this region.
47340 * @param {Roo.LayoutRegion} this
47341 * @param {Number} newSize The new size (width for east/west, height for north/south)
47345 /** A collection of panels in this region. @type Roo.util.MixedCollection */
47346 this.panels = new Roo.util.MixedCollection();
47347 this.panels.getKey = this.getPanelId.createDelegate(this);
47349 this.activePanel = null;
47350 // ensure listeners are added...
47352 if (config.listeners || config.events) {
47353 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
47354 listeners : config.listeners || {},
47355 events : config.events || {}
47359 if(skipConfig !== true){
47360 this.applyConfig(config);
47364 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
47365 getPanelId : function(p){
47369 applyConfig : function(config){
47370 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
47371 this.config = config;
47376 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
47377 * the width, for horizontal (north, south) the height.
47378 * @param {Number} newSize The new width or height
47380 resizeTo : function(newSize){
47381 var el = this.el ? this.el :
47382 (this.activePanel ? this.activePanel.getEl() : null);
47384 switch(this.position){
47387 el.setWidth(newSize);
47388 this.fireEvent("resized", this, newSize);
47392 el.setHeight(newSize);
47393 this.fireEvent("resized", this, newSize);
47399 getBox : function(){
47400 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
47403 getMargins : function(){
47404 return this.margins;
47407 updateBox : function(box){
47409 var el = this.activePanel.getEl();
47410 el.dom.style.left = box.x + "px";
47411 el.dom.style.top = box.y + "px";
47412 this.activePanel.setSize(box.width, box.height);
47416 * Returns the container element for this region.
47417 * @return {Roo.Element}
47419 getEl : function(){
47420 return this.activePanel;
47424 * Returns true if this region is currently visible.
47425 * @return {Boolean}
47427 isVisible : function(){
47428 return this.activePanel ? true : false;
47431 setActivePanel : function(panel){
47432 panel = this.getPanel(panel);
47433 if(this.activePanel && this.activePanel != panel){
47434 this.activePanel.setActiveState(false);
47435 this.activePanel.getEl().setLeftTop(-10000,-10000);
47437 this.activePanel = panel;
47438 panel.setActiveState(true);
47440 panel.setSize(this.box.width, this.box.height);
47442 this.fireEvent("panelactivated", this, panel);
47443 this.fireEvent("invalidated");
47447 * Show the specified panel.
47448 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
47449 * @return {Roo.ContentPanel} The shown panel or null
47451 showPanel : function(panel){
47452 if(panel = this.getPanel(panel)){
47453 this.setActivePanel(panel);
47459 * Get the active panel for this region.
47460 * @return {Roo.ContentPanel} The active panel or null
47462 getActivePanel : function(){
47463 return this.activePanel;
47467 * Add the passed ContentPanel(s)
47468 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
47469 * @return {Roo.ContentPanel} The panel added (if only one was added)
47471 add : function(panel){
47472 if(arguments.length > 1){
47473 for(var i = 0, len = arguments.length; i < len; i++) {
47474 this.add(arguments[i]);
47478 if(this.hasPanel(panel)){
47479 this.showPanel(panel);
47482 var el = panel.getEl();
47483 if(el.dom.parentNode != this.mgr.el.dom){
47484 this.mgr.el.dom.appendChild(el.dom);
47486 if(panel.setRegion){
47487 panel.setRegion(this);
47489 this.panels.add(panel);
47490 el.setStyle("position", "absolute");
47491 if(!panel.background){
47492 this.setActivePanel(panel);
47493 if(this.config.initialSize && this.panels.getCount()==1){
47494 this.resizeTo(this.config.initialSize);
47497 this.fireEvent("paneladded", this, panel);
47502 * Returns true if the panel is in this region.
47503 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47504 * @return {Boolean}
47506 hasPanel : function(panel){
47507 if(typeof panel == "object"){ // must be panel obj
47508 panel = panel.getId();
47510 return this.getPanel(panel) ? true : false;
47514 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
47515 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47516 * @param {Boolean} preservePanel Overrides the config preservePanel option
47517 * @return {Roo.ContentPanel} The panel that was removed
47519 remove : function(panel, preservePanel){
47520 panel = this.getPanel(panel);
47525 this.fireEvent("beforeremove", this, panel, e);
47526 if(e.cancel === true){
47529 var panelId = panel.getId();
47530 this.panels.removeKey(panelId);
47535 * Returns the panel specified or null if it's not in this region.
47536 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47537 * @return {Roo.ContentPanel}
47539 getPanel : function(id){
47540 if(typeof id == "object"){ // must be panel obj
47543 return this.panels.get(id);
47547 * Returns this regions position (north/south/east/west/center).
47550 getPosition: function(){
47551 return this.position;
47555 * Ext JS Library 1.1.1
47556 * Copyright(c) 2006-2007, Ext JS, LLC.
47558 * Originally Released Under LGPL - original licence link has changed is not relivant.
47561 * <script type="text/javascript">
47565 * @class Roo.LayoutRegion
47566 * @extends Roo.BasicLayoutRegion
47567 * This class represents a region in a layout manager.
47568 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
47569 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
47570 * @cfg {Boolean} floatable False to disable floating (defaults to true)
47571 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
47572 * @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})
47573 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
47574 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
47575 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
47576 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
47577 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
47578 * @cfg {String} title The title for the region (overrides panel titles)
47579 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
47580 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
47581 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
47582 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
47583 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
47584 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
47585 * the space available, similar to FireFox 1.5 tabs (defaults to false)
47586 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
47587 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
47588 * @cfg {Boolean} showPin True to show a pin button
47589 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
47590 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
47591 * @cfg {Boolean} disableTabTips True to disable tab tooltips
47592 * @cfg {Number} width For East/West panels
47593 * @cfg {Number} height For North/South panels
47594 * @cfg {Boolean} split To show the splitter
47595 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
47597 Roo.LayoutRegion = function(mgr, config, pos){
47598 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
47599 var dh = Roo.DomHelper;
47600 /** This region's container element
47601 * @type Roo.Element */
47602 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
47603 /** This region's title element
47604 * @type Roo.Element */
47606 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
47607 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
47608 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
47610 this.titleEl.enableDisplayMode();
47611 /** This region's title text element
47612 * @type HTMLElement */
47613 this.titleTextEl = this.titleEl.dom.firstChild;
47614 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
47615 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
47616 this.closeBtn.enableDisplayMode();
47617 this.closeBtn.on("click", this.closeClicked, this);
47618 this.closeBtn.hide();
47620 this.createBody(config);
47621 this.visible = true;
47622 this.collapsed = false;
47624 if(config.hideWhenEmpty){
47626 this.on("paneladded", this.validateVisibility, this);
47627 this.on("panelremoved", this.validateVisibility, this);
47629 this.applyConfig(config);
47632 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
47634 createBody : function(){
47635 /** This region's body element
47636 * @type Roo.Element */
47637 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
47640 applyConfig : function(c){
47641 if(c.collapsible && this.position != "center" && !this.collapsedEl){
47642 var dh = Roo.DomHelper;
47643 if(c.titlebar !== false){
47644 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
47645 this.collapseBtn.on("click", this.collapse, this);
47646 this.collapseBtn.enableDisplayMode();
47648 if(c.showPin === true || this.showPin){
47649 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
47650 this.stickBtn.enableDisplayMode();
47651 this.stickBtn.on("click", this.expand, this);
47652 this.stickBtn.hide();
47655 /** This region's collapsed element
47656 * @type Roo.Element */
47657 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
47658 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
47660 if(c.floatable !== false){
47661 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
47662 this.collapsedEl.on("click", this.collapseClick, this);
47665 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
47666 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
47667 id: "message", unselectable: "on", style:{"float":"left"}});
47668 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
47670 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
47671 this.expandBtn.on("click", this.expand, this);
47673 if(this.collapseBtn){
47674 this.collapseBtn.setVisible(c.collapsible == true);
47676 this.cmargins = c.cmargins || this.cmargins ||
47677 (this.position == "west" || this.position == "east" ?
47678 {top: 0, left: 2, right:2, bottom: 0} :
47679 {top: 2, left: 0, right:0, bottom: 2});
47680 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
47681 this.bottomTabs = c.tabPosition != "top";
47682 this.autoScroll = c.autoScroll || false;
47683 if(this.autoScroll){
47684 this.bodyEl.setStyle("overflow", "auto");
47686 this.bodyEl.setStyle("overflow", "hidden");
47688 //if(c.titlebar !== false){
47689 if((!c.titlebar && !c.title) || c.titlebar === false){
47690 this.titleEl.hide();
47692 this.titleEl.show();
47694 this.titleTextEl.innerHTML = c.title;
47698 this.duration = c.duration || .30;
47699 this.slideDuration = c.slideDuration || .45;
47702 this.collapse(true);
47709 * Returns true if this region is currently visible.
47710 * @return {Boolean}
47712 isVisible : function(){
47713 return this.visible;
47717 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
47718 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
47720 setCollapsedTitle : function(title){
47721 title = title || " ";
47722 if(this.collapsedTitleTextEl){
47723 this.collapsedTitleTextEl.innerHTML = title;
47727 getBox : function(){
47729 if(!this.collapsed){
47730 b = this.el.getBox(false, true);
47732 b = this.collapsedEl.getBox(false, true);
47737 getMargins : function(){
47738 return this.collapsed ? this.cmargins : this.margins;
47741 highlight : function(){
47742 this.el.addClass("x-layout-panel-dragover");
47745 unhighlight : function(){
47746 this.el.removeClass("x-layout-panel-dragover");
47749 updateBox : function(box){
47751 if(!this.collapsed){
47752 this.el.dom.style.left = box.x + "px";
47753 this.el.dom.style.top = box.y + "px";
47754 this.updateBody(box.width, box.height);
47756 this.collapsedEl.dom.style.left = box.x + "px";
47757 this.collapsedEl.dom.style.top = box.y + "px";
47758 this.collapsedEl.setSize(box.width, box.height);
47761 this.tabs.autoSizeTabs();
47765 updateBody : function(w, h){
47767 this.el.setWidth(w);
47768 w -= this.el.getBorderWidth("rl");
47769 if(this.config.adjustments){
47770 w += this.config.adjustments[0];
47774 this.el.setHeight(h);
47775 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
47776 h -= this.el.getBorderWidth("tb");
47777 if(this.config.adjustments){
47778 h += this.config.adjustments[1];
47780 this.bodyEl.setHeight(h);
47782 h = this.tabs.syncHeight(h);
47785 if(this.panelSize){
47786 w = w !== null ? w : this.panelSize.width;
47787 h = h !== null ? h : this.panelSize.height;
47789 if(this.activePanel){
47790 var el = this.activePanel.getEl();
47791 w = w !== null ? w : el.getWidth();
47792 h = h !== null ? h : el.getHeight();
47793 this.panelSize = {width: w, height: h};
47794 this.activePanel.setSize(w, h);
47796 if(Roo.isIE && this.tabs){
47797 this.tabs.el.repaint();
47802 * Returns the container element for this region.
47803 * @return {Roo.Element}
47805 getEl : function(){
47810 * Hides this region.
47813 if(!this.collapsed){
47814 this.el.dom.style.left = "-2000px";
47817 this.collapsedEl.dom.style.left = "-2000px";
47818 this.collapsedEl.hide();
47820 this.visible = false;
47821 this.fireEvent("visibilitychange", this, false);
47825 * Shows this region if it was previously hidden.
47828 if(!this.collapsed){
47831 this.collapsedEl.show();
47833 this.visible = true;
47834 this.fireEvent("visibilitychange", this, true);
47837 closeClicked : function(){
47838 if(this.activePanel){
47839 this.remove(this.activePanel);
47843 collapseClick : function(e){
47845 e.stopPropagation();
47848 e.stopPropagation();
47854 * Collapses this region.
47855 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
47857 collapse : function(skipAnim){
47858 if(this.collapsed) return;
47859 this.collapsed = true;
47861 this.split.el.hide();
47863 if(this.config.animate && skipAnim !== true){
47864 this.fireEvent("invalidated", this);
47865 this.animateCollapse();
47867 this.el.setLocation(-20000,-20000);
47869 this.collapsedEl.show();
47870 this.fireEvent("collapsed", this);
47871 this.fireEvent("invalidated", this);
47875 animateCollapse : function(){
47880 * Expands this region if it was previously collapsed.
47881 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
47882 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
47884 expand : function(e, skipAnim){
47885 if(e) e.stopPropagation();
47886 if(!this.collapsed || this.el.hasActiveFx()) return;
47888 this.afterSlideIn();
47891 this.collapsed = false;
47892 if(this.config.animate && skipAnim !== true){
47893 this.animateExpand();
47897 this.split.el.show();
47899 this.collapsedEl.setLocation(-2000,-2000);
47900 this.collapsedEl.hide();
47901 this.fireEvent("invalidated", this);
47902 this.fireEvent("expanded", this);
47906 animateExpand : function(){
47910 initTabs : function()
47912 this.bodyEl.setStyle("overflow", "hidden");
47913 var ts = new Roo.TabPanel(
47916 tabPosition: this.bottomTabs ? 'bottom' : 'top',
47917 disableTooltips: this.config.disableTabTips,
47918 toolbar : this.config.toolbar
47921 if(this.config.hideTabs){
47922 ts.stripWrap.setDisplayed(false);
47925 ts.resizeTabs = this.config.resizeTabs === true;
47926 ts.minTabWidth = this.config.minTabWidth || 40;
47927 ts.maxTabWidth = this.config.maxTabWidth || 250;
47928 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
47929 ts.monitorResize = false;
47930 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47931 ts.bodyEl.addClass('x-layout-tabs-body');
47932 this.panels.each(this.initPanelAsTab, this);
47935 initPanelAsTab : function(panel){
47936 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
47937 this.config.closeOnTab && panel.isClosable());
47938 if(panel.tabTip !== undefined){
47939 ti.setTooltip(panel.tabTip);
47941 ti.on("activate", function(){
47942 this.setActivePanel(panel);
47944 if(this.config.closeOnTab){
47945 ti.on("beforeclose", function(t, e){
47947 this.remove(panel);
47953 updatePanelTitle : function(panel, title){
47954 if(this.activePanel == panel){
47955 this.updateTitle(title);
47958 var ti = this.tabs.getTab(panel.getEl().id);
47960 if(panel.tabTip !== undefined){
47961 ti.setTooltip(panel.tabTip);
47966 updateTitle : function(title){
47967 if(this.titleTextEl && !this.config.title){
47968 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
47972 setActivePanel : function(panel){
47973 panel = this.getPanel(panel);
47974 if(this.activePanel && this.activePanel != panel){
47975 this.activePanel.setActiveState(false);
47977 this.activePanel = panel;
47978 panel.setActiveState(true);
47979 if(this.panelSize){
47980 panel.setSize(this.panelSize.width, this.panelSize.height);
47983 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
47985 this.updateTitle(panel.getTitle());
47987 this.fireEvent("invalidated", this);
47989 this.fireEvent("panelactivated", this, panel);
47993 * Shows the specified panel.
47994 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
47995 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
47997 showPanel : function(panel){
47998 if(panel = this.getPanel(panel)){
48000 var tab = this.tabs.getTab(panel.getEl().id);
48001 if(tab.isHidden()){
48002 this.tabs.unhideTab(tab.id);
48006 this.setActivePanel(panel);
48013 * Get the active panel for this region.
48014 * @return {Roo.ContentPanel} The active panel or null
48016 getActivePanel : function(){
48017 return this.activePanel;
48020 validateVisibility : function(){
48021 if(this.panels.getCount() < 1){
48022 this.updateTitle(" ");
48023 this.closeBtn.hide();
48026 if(!this.isVisible()){
48033 * Adds the passed ContentPanel(s) to this region.
48034 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48035 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
48037 add : function(panel){
48038 if(arguments.length > 1){
48039 for(var i = 0, len = arguments.length; i < len; i++) {
48040 this.add(arguments[i]);
48044 if(this.hasPanel(panel)){
48045 this.showPanel(panel);
48048 panel.setRegion(this);
48049 this.panels.add(panel);
48050 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
48051 this.bodyEl.dom.appendChild(panel.getEl().dom);
48052 if(panel.background !== true){
48053 this.setActivePanel(panel);
48055 this.fireEvent("paneladded", this, panel);
48061 this.initPanelAsTab(panel);
48063 if(panel.background !== true){
48064 this.tabs.activate(panel.getEl().id);
48066 this.fireEvent("paneladded", this, panel);
48071 * Hides the tab for the specified panel.
48072 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48074 hidePanel : function(panel){
48075 if(this.tabs && (panel = this.getPanel(panel))){
48076 this.tabs.hideTab(panel.getEl().id);
48081 * Unhides the tab for a previously hidden panel.
48082 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48084 unhidePanel : function(panel){
48085 if(this.tabs && (panel = this.getPanel(panel))){
48086 this.tabs.unhideTab(panel.getEl().id);
48090 clearPanels : function(){
48091 while(this.panels.getCount() > 0){
48092 this.remove(this.panels.first());
48097 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48098 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48099 * @param {Boolean} preservePanel Overrides the config preservePanel option
48100 * @return {Roo.ContentPanel} The panel that was removed
48102 remove : function(panel, preservePanel){
48103 panel = this.getPanel(panel);
48108 this.fireEvent("beforeremove", this, panel, e);
48109 if(e.cancel === true){
48112 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
48113 var panelId = panel.getId();
48114 this.panels.removeKey(panelId);
48116 document.body.appendChild(panel.getEl().dom);
48119 this.tabs.removeTab(panel.getEl().id);
48120 }else if (!preservePanel){
48121 this.bodyEl.dom.removeChild(panel.getEl().dom);
48123 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
48124 var p = this.panels.first();
48125 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
48126 tempEl.appendChild(p.getEl().dom);
48127 this.bodyEl.update("");
48128 this.bodyEl.dom.appendChild(p.getEl().dom);
48130 this.updateTitle(p.getTitle());
48132 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48133 this.setActivePanel(p);
48135 panel.setRegion(null);
48136 if(this.activePanel == panel){
48137 this.activePanel = null;
48139 if(this.config.autoDestroy !== false && preservePanel !== true){
48140 try{panel.destroy();}catch(e){}
48142 this.fireEvent("panelremoved", this, panel);
48147 * Returns the TabPanel component used by this region
48148 * @return {Roo.TabPanel}
48150 getTabs : function(){
48154 createTool : function(parentEl, className){
48155 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
48156 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
48157 btn.addClassOnOver("x-layout-tools-button-over");
48162 * Ext JS Library 1.1.1
48163 * Copyright(c) 2006-2007, Ext JS, LLC.
48165 * Originally Released Under LGPL - original licence link has changed is not relivant.
48168 * <script type="text/javascript">
48174 * @class Roo.SplitLayoutRegion
48175 * @extends Roo.LayoutRegion
48176 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
48178 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
48179 this.cursor = cursor;
48180 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
48183 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
48184 splitTip : "Drag to resize.",
48185 collapsibleSplitTip : "Drag to resize. Double click to hide.",
48186 useSplitTips : false,
48188 applyConfig : function(config){
48189 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
48192 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
48193 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
48194 /** The SplitBar for this region
48195 * @type Roo.SplitBar */
48196 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
48197 this.split.on("moved", this.onSplitMove, this);
48198 this.split.useShim = config.useShim === true;
48199 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
48200 if(this.useSplitTips){
48201 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
48203 if(config.collapsible){
48204 this.split.el.on("dblclick", this.collapse, this);
48207 if(typeof config.minSize != "undefined"){
48208 this.split.minSize = config.minSize;
48210 if(typeof config.maxSize != "undefined"){
48211 this.split.maxSize = config.maxSize;
48213 if(config.hideWhenEmpty || config.hidden || config.collapsed){
48214 this.hideSplitter();
48219 getHMaxSize : function(){
48220 var cmax = this.config.maxSize || 10000;
48221 var center = this.mgr.getRegion("center");
48222 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
48225 getVMaxSize : function(){
48226 var cmax = this.config.maxSize || 10000;
48227 var center = this.mgr.getRegion("center");
48228 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
48231 onSplitMove : function(split, newSize){
48232 this.fireEvent("resized", this, newSize);
48236 * Returns the {@link Roo.SplitBar} for this region.
48237 * @return {Roo.SplitBar}
48239 getSplitBar : function(){
48244 this.hideSplitter();
48245 Roo.SplitLayoutRegion.superclass.hide.call(this);
48248 hideSplitter : function(){
48250 this.split.el.setLocation(-2000,-2000);
48251 this.split.el.hide();
48257 this.split.el.show();
48259 Roo.SplitLayoutRegion.superclass.show.call(this);
48262 beforeSlide: function(){
48263 if(Roo.isGecko){// firefox overflow auto bug workaround
48264 this.bodyEl.clip();
48265 if(this.tabs) this.tabs.bodyEl.clip();
48266 if(this.activePanel){
48267 this.activePanel.getEl().clip();
48269 if(this.activePanel.beforeSlide){
48270 this.activePanel.beforeSlide();
48276 afterSlide : function(){
48277 if(Roo.isGecko){// firefox overflow auto bug workaround
48278 this.bodyEl.unclip();
48279 if(this.tabs) this.tabs.bodyEl.unclip();
48280 if(this.activePanel){
48281 this.activePanel.getEl().unclip();
48282 if(this.activePanel.afterSlide){
48283 this.activePanel.afterSlide();
48289 initAutoHide : function(){
48290 if(this.autoHide !== false){
48291 if(!this.autoHideHd){
48292 var st = new Roo.util.DelayedTask(this.slideIn, this);
48293 this.autoHideHd = {
48294 "mouseout": function(e){
48295 if(!e.within(this.el, true)){
48299 "mouseover" : function(e){
48305 this.el.on(this.autoHideHd);
48309 clearAutoHide : function(){
48310 if(this.autoHide !== false){
48311 this.el.un("mouseout", this.autoHideHd.mouseout);
48312 this.el.un("mouseover", this.autoHideHd.mouseover);
48316 clearMonitor : function(){
48317 Roo.get(document).un("click", this.slideInIf, this);
48320 // these names are backwards but not changed for compat
48321 slideOut : function(){
48322 if(this.isSlid || this.el.hasActiveFx()){
48325 this.isSlid = true;
48326 if(this.collapseBtn){
48327 this.collapseBtn.hide();
48329 this.closeBtnState = this.closeBtn.getStyle('display');
48330 this.closeBtn.hide();
48332 this.stickBtn.show();
48335 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
48336 this.beforeSlide();
48337 this.el.setStyle("z-index", 10001);
48338 this.el.slideIn(this.getSlideAnchor(), {
48339 callback: function(){
48341 this.initAutoHide();
48342 Roo.get(document).on("click", this.slideInIf, this);
48343 this.fireEvent("slideshow", this);
48350 afterSlideIn : function(){
48351 this.clearAutoHide();
48352 this.isSlid = false;
48353 this.clearMonitor();
48354 this.el.setStyle("z-index", "");
48355 if(this.collapseBtn){
48356 this.collapseBtn.show();
48358 this.closeBtn.setStyle('display', this.closeBtnState);
48360 this.stickBtn.hide();
48362 this.fireEvent("slidehide", this);
48365 slideIn : function(cb){
48366 if(!this.isSlid || this.el.hasActiveFx()){
48370 this.isSlid = false;
48371 this.beforeSlide();
48372 this.el.slideOut(this.getSlideAnchor(), {
48373 callback: function(){
48374 this.el.setLeftTop(-10000, -10000);
48376 this.afterSlideIn();
48384 slideInIf : function(e){
48385 if(!e.within(this.el)){
48390 animateCollapse : function(){
48391 this.beforeSlide();
48392 this.el.setStyle("z-index", 20000);
48393 var anchor = this.getSlideAnchor();
48394 this.el.slideOut(anchor, {
48395 callback : function(){
48396 this.el.setStyle("z-index", "");
48397 this.collapsedEl.slideIn(anchor, {duration:.3});
48399 this.el.setLocation(-10000,-10000);
48401 this.fireEvent("collapsed", this);
48408 animateExpand : function(){
48409 this.beforeSlide();
48410 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
48411 this.el.setStyle("z-index", 20000);
48412 this.collapsedEl.hide({
48415 this.el.slideIn(this.getSlideAnchor(), {
48416 callback : function(){
48417 this.el.setStyle("z-index", "");
48420 this.split.el.show();
48422 this.fireEvent("invalidated", this);
48423 this.fireEvent("expanded", this);
48451 getAnchor : function(){
48452 return this.anchors[this.position];
48455 getCollapseAnchor : function(){
48456 return this.canchors[this.position];
48459 getSlideAnchor : function(){
48460 return this.sanchors[this.position];
48463 getAlignAdj : function(){
48464 var cm = this.cmargins;
48465 switch(this.position){
48481 getExpandAdj : function(){
48482 var c = this.collapsedEl, cm = this.cmargins;
48483 switch(this.position){
48485 return [-(cm.right+c.getWidth()+cm.left), 0];
48488 return [cm.right+c.getWidth()+cm.left, 0];
48491 return [0, -(cm.top+cm.bottom+c.getHeight())];
48494 return [0, cm.top+cm.bottom+c.getHeight()];
48500 * Ext JS Library 1.1.1
48501 * Copyright(c) 2006-2007, Ext JS, LLC.
48503 * Originally Released Under LGPL - original licence link has changed is not relivant.
48506 * <script type="text/javascript">
48509 * These classes are private internal classes
48511 Roo.CenterLayoutRegion = function(mgr, config){
48512 Roo.LayoutRegion.call(this, mgr, config, "center");
48513 this.visible = true;
48514 this.minWidth = config.minWidth || 20;
48515 this.minHeight = config.minHeight || 20;
48518 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
48520 // center panel can't be hidden
48524 // center panel can't be hidden
48527 getMinWidth: function(){
48528 return this.minWidth;
48531 getMinHeight: function(){
48532 return this.minHeight;
48537 Roo.NorthLayoutRegion = function(mgr, config){
48538 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
48540 this.split.placement = Roo.SplitBar.TOP;
48541 this.split.orientation = Roo.SplitBar.VERTICAL;
48542 this.split.el.addClass("x-layout-split-v");
48544 var size = config.initialSize || config.height;
48545 if(typeof size != "undefined"){
48546 this.el.setHeight(size);
48549 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
48550 orientation: Roo.SplitBar.VERTICAL,
48551 getBox : function(){
48552 if(this.collapsed){
48553 return this.collapsedEl.getBox();
48555 var box = this.el.getBox();
48557 box.height += this.split.el.getHeight();
48562 updateBox : function(box){
48563 if(this.split && !this.collapsed){
48564 box.height -= this.split.el.getHeight();
48565 this.split.el.setLeft(box.x);
48566 this.split.el.setTop(box.y+box.height);
48567 this.split.el.setWidth(box.width);
48569 if(this.collapsed){
48570 this.updateBody(box.width, null);
48572 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48576 Roo.SouthLayoutRegion = function(mgr, config){
48577 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
48579 this.split.placement = Roo.SplitBar.BOTTOM;
48580 this.split.orientation = Roo.SplitBar.VERTICAL;
48581 this.split.el.addClass("x-layout-split-v");
48583 var size = config.initialSize || config.height;
48584 if(typeof size != "undefined"){
48585 this.el.setHeight(size);
48588 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
48589 orientation: Roo.SplitBar.VERTICAL,
48590 getBox : function(){
48591 if(this.collapsed){
48592 return this.collapsedEl.getBox();
48594 var box = this.el.getBox();
48596 var sh = this.split.el.getHeight();
48603 updateBox : function(box){
48604 if(this.split && !this.collapsed){
48605 var sh = this.split.el.getHeight();
48608 this.split.el.setLeft(box.x);
48609 this.split.el.setTop(box.y-sh);
48610 this.split.el.setWidth(box.width);
48612 if(this.collapsed){
48613 this.updateBody(box.width, null);
48615 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48619 Roo.EastLayoutRegion = function(mgr, config){
48620 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
48622 this.split.placement = Roo.SplitBar.RIGHT;
48623 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48624 this.split.el.addClass("x-layout-split-h");
48626 var size = config.initialSize || config.width;
48627 if(typeof size != "undefined"){
48628 this.el.setWidth(size);
48631 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
48632 orientation: Roo.SplitBar.HORIZONTAL,
48633 getBox : function(){
48634 if(this.collapsed){
48635 return this.collapsedEl.getBox();
48637 var box = this.el.getBox();
48639 var sw = this.split.el.getWidth();
48646 updateBox : function(box){
48647 if(this.split && !this.collapsed){
48648 var sw = this.split.el.getWidth();
48650 this.split.el.setLeft(box.x);
48651 this.split.el.setTop(box.y);
48652 this.split.el.setHeight(box.height);
48655 if(this.collapsed){
48656 this.updateBody(null, box.height);
48658 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48662 Roo.WestLayoutRegion = function(mgr, config){
48663 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
48665 this.split.placement = Roo.SplitBar.LEFT;
48666 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48667 this.split.el.addClass("x-layout-split-h");
48669 var size = config.initialSize || config.width;
48670 if(typeof size != "undefined"){
48671 this.el.setWidth(size);
48674 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
48675 orientation: Roo.SplitBar.HORIZONTAL,
48676 getBox : function(){
48677 if(this.collapsed){
48678 return this.collapsedEl.getBox();
48680 var box = this.el.getBox();
48682 box.width += this.split.el.getWidth();
48687 updateBox : function(box){
48688 if(this.split && !this.collapsed){
48689 var sw = this.split.el.getWidth();
48691 this.split.el.setLeft(box.x+box.width);
48692 this.split.el.setTop(box.y);
48693 this.split.el.setHeight(box.height);
48695 if(this.collapsed){
48696 this.updateBody(null, box.height);
48698 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48703 * Ext JS Library 1.1.1
48704 * Copyright(c) 2006-2007, Ext JS, LLC.
48706 * Originally Released Under LGPL - original licence link has changed is not relivant.
48709 * <script type="text/javascript">
48714 * Private internal class for reading and applying state
48716 Roo.LayoutStateManager = function(layout){
48717 // default empty state
48726 Roo.LayoutStateManager.prototype = {
48727 init : function(layout, provider){
48728 this.provider = provider;
48729 var state = provider.get(layout.id+"-layout-state");
48731 var wasUpdating = layout.isUpdating();
48733 layout.beginUpdate();
48735 for(var key in state){
48736 if(typeof state[key] != "function"){
48737 var rstate = state[key];
48738 var r = layout.getRegion(key);
48741 r.resizeTo(rstate.size);
48743 if(rstate.collapsed == true){
48746 r.expand(null, true);
48752 layout.endUpdate();
48754 this.state = state;
48756 this.layout = layout;
48757 layout.on("regionresized", this.onRegionResized, this);
48758 layout.on("regioncollapsed", this.onRegionCollapsed, this);
48759 layout.on("regionexpanded", this.onRegionExpanded, this);
48762 storeState : function(){
48763 this.provider.set(this.layout.id+"-layout-state", this.state);
48766 onRegionResized : function(region, newSize){
48767 this.state[region.getPosition()].size = newSize;
48771 onRegionCollapsed : function(region){
48772 this.state[region.getPosition()].collapsed = true;
48776 onRegionExpanded : function(region){
48777 this.state[region.getPosition()].collapsed = false;
48782 * Ext JS Library 1.1.1
48783 * Copyright(c) 2006-2007, Ext JS, LLC.
48785 * Originally Released Under LGPL - original licence link has changed is not relivant.
48788 * <script type="text/javascript">
48791 * @class Roo.ContentPanel
48792 * @extends Roo.util.Observable
48793 * A basic ContentPanel element.
48794 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
48795 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
48796 * @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
48797 * @cfg {Boolean} closable True if the panel can be closed/removed
48798 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
48799 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
48800 * @cfg {Toolbar} toolbar A toolbar for this panel
48801 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
48802 * @cfg {String} title The title for this panel
48803 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
48804 * @cfg {String} url Calls {@link #setUrl} with this value
48805 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
48806 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
48807 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
48808 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
48811 * Create a new ContentPanel.
48812 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
48813 * @param {String/Object} config A string to set only the title or a config object
48814 * @param {String} content (optional) Set the HTML content for this panel
48815 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
48817 Roo.ContentPanel = function(el, config, content){
48821 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
48825 if (config && config.parentLayout) {
48826 el = config.parentLayout.el.createChild();
48829 if(el.autoCreate){ // xtype is available if this is called from factory
48833 this.el = Roo.get(el);
48834 if(!this.el && config && config.autoCreate){
48835 if(typeof config.autoCreate == "object"){
48836 if(!config.autoCreate.id){
48837 config.autoCreate.id = config.id||el;
48839 this.el = Roo.DomHelper.append(document.body,
48840 config.autoCreate, true);
48842 this.el = Roo.DomHelper.append(document.body,
48843 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
48846 this.closable = false;
48847 this.loaded = false;
48848 this.active = false;
48849 if(typeof config == "string"){
48850 this.title = config;
48852 Roo.apply(this, config);
48855 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
48856 this.wrapEl = this.el.wrap();
48857 this.toolbar.container = this.el.insertSibling(false, 'before');
48858 this.toolbar = new Roo.Toolbar(this.toolbar);
48861 // xtype created footer. - not sure if will work as we normally have to render first..
48862 if (this.footer && !this.footer.el && this.footer.xtype) {
48863 if (!this.wrapEl) {
48864 this.wrapEl = this.el.wrap();
48867 this.footer.container = this.wrapEl.createChild();
48869 this.footer = Roo.factory(this.footer, Roo);
48874 this.resizeEl = Roo.get(this.resizeEl, true);
48876 this.resizeEl = this.el;
48878 // handle view.xtype
48886 * Fires when this panel is activated.
48887 * @param {Roo.ContentPanel} this
48891 * @event deactivate
48892 * Fires when this panel is activated.
48893 * @param {Roo.ContentPanel} this
48895 "deactivate" : true,
48899 * Fires when this panel is resized if fitToFrame is true.
48900 * @param {Roo.ContentPanel} this
48901 * @param {Number} width The width after any component adjustments
48902 * @param {Number} height The height after any component adjustments
48908 * Fires when this tab is created
48909 * @param {Roo.ContentPanel} this
48920 if(this.autoScroll){
48921 this.resizeEl.setStyle("overflow", "auto");
48923 // fix randome scrolling
48924 this.el.on('scroll', function() {
48925 Roo.log('fix random scolling');
48926 this.scrollTo('top',0);
48929 content = content || this.content;
48931 this.setContent(content);
48933 if(config && config.url){
48934 this.setUrl(this.url, this.params, this.loadOnce);
48939 Roo.ContentPanel.superclass.constructor.call(this);
48941 if (this.view && typeof(this.view.xtype) != 'undefined') {
48942 this.view.el = this.el.appendChild(document.createElement("div"));
48943 this.view = Roo.factory(this.view);
48944 this.view.render && this.view.render(false, '');
48948 this.fireEvent('render', this);
48951 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
48953 setRegion : function(region){
48954 this.region = region;
48956 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
48958 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
48963 * Returns the toolbar for this Panel if one was configured.
48964 * @return {Roo.Toolbar}
48966 getToolbar : function(){
48967 return this.toolbar;
48970 setActiveState : function(active){
48971 this.active = active;
48973 this.fireEvent("deactivate", this);
48975 this.fireEvent("activate", this);
48979 * Updates this panel's element
48980 * @param {String} content The new content
48981 * @param {Boolean} loadScripts (optional) true to look for and process scripts
48983 setContent : function(content, loadScripts){
48984 this.el.update(content, loadScripts);
48987 ignoreResize : function(w, h){
48988 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
48991 this.lastSize = {width: w, height: h};
48996 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
48997 * @return {Roo.UpdateManager} The UpdateManager
48999 getUpdateManager : function(){
49000 return this.el.getUpdateManager();
49003 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
49004 * @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:
49007 url: "your-url.php",
49008 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
49009 callback: yourFunction,
49010 scope: yourObject, //(optional scope)
49013 text: "Loading...",
49018 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
49019 * 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.
49020 * @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}
49021 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
49022 * @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.
49023 * @return {Roo.ContentPanel} this
49026 var um = this.el.getUpdateManager();
49027 um.update.apply(um, arguments);
49033 * 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.
49034 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
49035 * @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)
49036 * @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)
49037 * @return {Roo.UpdateManager} The UpdateManager
49039 setUrl : function(url, params, loadOnce){
49040 if(this.refreshDelegate){
49041 this.removeListener("activate", this.refreshDelegate);
49043 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
49044 this.on("activate", this.refreshDelegate);
49045 return this.el.getUpdateManager();
49048 _handleRefresh : function(url, params, loadOnce){
49049 if(!loadOnce || !this.loaded){
49050 var updater = this.el.getUpdateManager();
49051 updater.update(url, params, this._setLoaded.createDelegate(this));
49055 _setLoaded : function(){
49056 this.loaded = true;
49060 * Returns this panel's id
49063 getId : function(){
49068 * Returns this panel's element - used by regiosn to add.
49069 * @return {Roo.Element}
49071 getEl : function(){
49072 return this.wrapEl || this.el;
49075 adjustForComponents : function(width, height)
49077 //Roo.log('adjustForComponents ');
49078 if(this.resizeEl != this.el){
49079 width -= this.el.getFrameWidth('lr');
49080 height -= this.el.getFrameWidth('tb');
49083 var te = this.toolbar.getEl();
49084 height -= te.getHeight();
49085 te.setWidth(width);
49088 var te = this.footer.getEl();
49089 Roo.log("footer:" + te.getHeight());
49091 height -= te.getHeight();
49092 te.setWidth(width);
49096 if(this.adjustments){
49097 width += this.adjustments[0];
49098 height += this.adjustments[1];
49100 return {"width": width, "height": height};
49103 setSize : function(width, height){
49104 if(this.fitToFrame && !this.ignoreResize(width, height)){
49105 if(this.fitContainer && this.resizeEl != this.el){
49106 this.el.setSize(width, height);
49108 var size = this.adjustForComponents(width, height);
49109 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
49110 this.fireEvent('resize', this, size.width, size.height);
49115 * Returns this panel's title
49118 getTitle : function(){
49123 * Set this panel's title
49124 * @param {String} title
49126 setTitle : function(title){
49127 this.title = title;
49129 this.region.updatePanelTitle(this, title);
49134 * Returns true is this panel was configured to be closable
49135 * @return {Boolean}
49137 isClosable : function(){
49138 return this.closable;
49141 beforeSlide : function(){
49143 this.resizeEl.clip();
49146 afterSlide : function(){
49148 this.resizeEl.unclip();
49152 * Force a content refresh from the URL specified in the {@link #setUrl} method.
49153 * Will fail silently if the {@link #setUrl} method has not been called.
49154 * This does not activate the panel, just updates its content.
49156 refresh : function(){
49157 if(this.refreshDelegate){
49158 this.loaded = false;
49159 this.refreshDelegate();
49164 * Destroys this panel
49166 destroy : function(){
49167 this.el.removeAllListeners();
49168 var tempEl = document.createElement("span");
49169 tempEl.appendChild(this.el.dom);
49170 tempEl.innerHTML = "";
49176 * form - if the content panel contains a form - this is a reference to it.
49177 * @type {Roo.form.Form}
49181 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
49182 * This contains a reference to it.
49188 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
49198 * @param {Object} cfg Xtype definition of item to add.
49201 addxtype : function(cfg) {
49203 if (cfg.xtype.match(/^Form$/)) {
49206 //if (this.footer) {
49207 // el = this.footer.container.insertSibling(false, 'before');
49209 el = this.el.createChild();
49212 this.form = new Roo.form.Form(cfg);
49215 if ( this.form.allItems.length) this.form.render(el.dom);
49218 // should only have one of theses..
49219 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
49220 // views.. should not be just added - used named prop 'view''
49222 cfg.el = this.el.appendChild(document.createElement("div"));
49225 var ret = new Roo.factory(cfg);
49227 ret.render && ret.render(false, ''); // render blank..
49236 * @class Roo.GridPanel
49237 * @extends Roo.ContentPanel
49239 * Create a new GridPanel.
49240 * @param {Roo.grid.Grid} grid The grid for this panel
49241 * @param {String/Object} config A string to set only the panel's title, or a config object
49243 Roo.GridPanel = function(grid, config){
49246 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
49247 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
49249 this.wrapper.dom.appendChild(grid.getGridEl().dom);
49251 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
49254 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
49256 // xtype created footer. - not sure if will work as we normally have to render first..
49257 if (this.footer && !this.footer.el && this.footer.xtype) {
49259 this.footer.container = this.grid.getView().getFooterPanel(true);
49260 this.footer.dataSource = this.grid.dataSource;
49261 this.footer = Roo.factory(this.footer, Roo);
49265 grid.monitorWindowResize = false; // turn off autosizing
49266 grid.autoHeight = false;
49267 grid.autoWidth = false;
49269 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
49272 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
49273 getId : function(){
49274 return this.grid.id;
49278 * Returns the grid for this panel
49279 * @return {Roo.grid.Grid}
49281 getGrid : function(){
49285 setSize : function(width, height){
49286 if(!this.ignoreResize(width, height)){
49287 var grid = this.grid;
49288 var size = this.adjustForComponents(width, height);
49289 grid.getGridEl().setSize(size.width, size.height);
49294 beforeSlide : function(){
49295 this.grid.getView().scroller.clip();
49298 afterSlide : function(){
49299 this.grid.getView().scroller.unclip();
49302 destroy : function(){
49303 this.grid.destroy();
49305 Roo.GridPanel.superclass.destroy.call(this);
49311 * @class Roo.NestedLayoutPanel
49312 * @extends Roo.ContentPanel
49314 * Create a new NestedLayoutPanel.
49317 * @param {Roo.BorderLayout} layout The layout for this panel
49318 * @param {String/Object} config A string to set only the title or a config object
49320 Roo.NestedLayoutPanel = function(layout, config)
49322 // construct with only one argument..
49323 /* FIXME - implement nicer consturctors
49324 if (layout.layout) {
49326 layout = config.layout;
49327 delete config.layout;
49329 if (layout.xtype && !layout.getEl) {
49330 // then layout needs constructing..
49331 layout = Roo.factory(layout, Roo);
49336 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
49338 layout.monitorWindowResize = false; // turn off autosizing
49339 this.layout = layout;
49340 this.layout.getEl().addClass("x-layout-nested-layout");
49347 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
49349 setSize : function(width, height){
49350 if(!this.ignoreResize(width, height)){
49351 var size = this.adjustForComponents(width, height);
49352 var el = this.layout.getEl();
49353 el.setSize(size.width, size.height);
49354 var touch = el.dom.offsetWidth;
49355 this.layout.layout();
49356 // ie requires a double layout on the first pass
49357 if(Roo.isIE && !this.initialized){
49358 this.initialized = true;
49359 this.layout.layout();
49364 // activate all subpanels if not currently active..
49366 setActiveState : function(active){
49367 this.active = active;
49369 this.fireEvent("deactivate", this);
49373 this.fireEvent("activate", this);
49374 // not sure if this should happen before or after..
49375 if (!this.layout) {
49376 return; // should not happen..
49379 for (var r in this.layout.regions) {
49380 reg = this.layout.getRegion(r);
49381 if (reg.getActivePanel()) {
49382 //reg.showPanel(reg.getActivePanel()); // force it to activate..
49383 reg.setActivePanel(reg.getActivePanel());
49386 if (!reg.panels.length) {
49389 reg.showPanel(reg.getPanel(0));
49398 * Returns the nested BorderLayout for this panel
49399 * @return {Roo.BorderLayout}
49401 getLayout : function(){
49402 return this.layout;
49406 * Adds a xtype elements to the layout of the nested panel
49410 xtype : 'ContentPanel',
49417 xtype : 'NestedLayoutPanel',
49423 items : [ ... list of content panels or nested layout panels.. ]
49427 * @param {Object} cfg Xtype definition of item to add.
49429 addxtype : function(cfg) {
49430 return this.layout.addxtype(cfg);
49435 Roo.ScrollPanel = function(el, config, content){
49436 config = config || {};
49437 config.fitToFrame = true;
49438 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
49440 this.el.dom.style.overflow = "hidden";
49441 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
49442 this.el.removeClass("x-layout-inactive-content");
49443 this.el.on("mousewheel", this.onWheel, this);
49445 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
49446 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
49447 up.unselectable(); down.unselectable();
49448 up.on("click", this.scrollUp, this);
49449 down.on("click", this.scrollDown, this);
49450 up.addClassOnOver("x-scroller-btn-over");
49451 down.addClassOnOver("x-scroller-btn-over");
49452 up.addClassOnClick("x-scroller-btn-click");
49453 down.addClassOnClick("x-scroller-btn-click");
49454 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
49456 this.resizeEl = this.el;
49457 this.el = wrap; this.up = up; this.down = down;
49460 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
49462 wheelIncrement : 5,
49463 scrollUp : function(){
49464 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
49467 scrollDown : function(){
49468 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
49471 afterScroll : function(){
49472 var el = this.resizeEl;
49473 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
49474 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
49475 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
49478 setSize : function(){
49479 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
49480 this.afterScroll();
49483 onWheel : function(e){
49484 var d = e.getWheelDelta();
49485 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
49486 this.afterScroll();
49490 setContent : function(content, loadScripts){
49491 this.resizeEl.update(content, loadScripts);
49505 * @class Roo.TreePanel
49506 * @extends Roo.ContentPanel
49508 * Create a new TreePanel. - defaults to fit/scoll contents.
49509 * @param {String/Object} config A string to set only the panel's title, or a config object
49510 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
49512 Roo.TreePanel = function(config){
49513 var el = config.el;
49514 var tree = config.tree;
49515 delete config.tree;
49516 delete config.el; // hopefull!
49518 // wrapper for IE7 strict & safari scroll issue
49520 var treeEl = el.createChild();
49521 config.resizeEl = treeEl;
49525 Roo.TreePanel.superclass.constructor.call(this, el, config);
49528 this.tree = new Roo.tree.TreePanel(treeEl , tree);
49529 //console.log(tree);
49530 this.on('activate', function()
49532 if (this.tree.rendered) {
49535 //console.log('render tree');
49536 this.tree.render();
49538 // this should not be needed.. - it's actually the 'el' that resizes?
49539 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
49541 //this.on('resize', function (cp, w, h) {
49542 // this.tree.innerCt.setWidth(w);
49543 // this.tree.innerCt.setHeight(h);
49544 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
49551 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
49568 * Ext JS Library 1.1.1
49569 * Copyright(c) 2006-2007, Ext JS, LLC.
49571 * Originally Released Under LGPL - original licence link has changed is not relivant.
49574 * <script type="text/javascript">
49579 * @class Roo.ReaderLayout
49580 * @extends Roo.BorderLayout
49581 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
49582 * center region containing two nested regions (a top one for a list view and one for item preview below),
49583 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
49584 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
49585 * expedites the setup of the overall layout and regions for this common application style.
49588 var reader = new Roo.ReaderLayout();
49589 var CP = Roo.ContentPanel; // shortcut for adding
49591 reader.beginUpdate();
49592 reader.add("north", new CP("north", "North"));
49593 reader.add("west", new CP("west", {title: "West"}));
49594 reader.add("east", new CP("east", {title: "East"}));
49596 reader.regions.listView.add(new CP("listView", "List"));
49597 reader.regions.preview.add(new CP("preview", "Preview"));
49598 reader.endUpdate();
49601 * Create a new ReaderLayout
49602 * @param {Object} config Configuration options
49603 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
49604 * document.body if omitted)
49606 Roo.ReaderLayout = function(config, renderTo){
49607 var c = config || {size:{}};
49608 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
49609 north: c.north !== false ? Roo.apply({
49613 }, c.north) : false,
49614 west: c.west !== false ? Roo.apply({
49622 margins:{left:5,right:0,bottom:5,top:5},
49623 cmargins:{left:5,right:5,bottom:5,top:5}
49624 }, c.west) : false,
49625 east: c.east !== false ? Roo.apply({
49633 margins:{left:0,right:5,bottom:5,top:5},
49634 cmargins:{left:5,right:5,bottom:5,top:5}
49635 }, c.east) : false,
49636 center: Roo.apply({
49637 tabPosition: 'top',
49641 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
49645 this.el.addClass('x-reader');
49647 this.beginUpdate();
49649 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
49650 south: c.preview !== false ? Roo.apply({
49657 cmargins:{top:5,left:0, right:0, bottom:0}
49658 }, c.preview) : false,
49659 center: Roo.apply({
49665 this.add('center', new Roo.NestedLayoutPanel(inner,
49666 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
49670 this.regions.preview = inner.getRegion('south');
49671 this.regions.listView = inner.getRegion('center');
49674 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
49676 * Ext JS Library 1.1.1
49677 * Copyright(c) 2006-2007, Ext JS, LLC.
49679 * Originally Released Under LGPL - original licence link has changed is not relivant.
49682 * <script type="text/javascript">
49686 * @class Roo.grid.Grid
49687 * @extends Roo.util.Observable
49688 * This class represents the primary interface of a component based grid control.
49689 * <br><br>Usage:<pre><code>
49690 var grid = new Roo.grid.Grid("my-container-id", {
49693 selModel: mySelectionModel,
49694 autoSizeColumns: true,
49695 monitorWindowResize: false,
49696 trackMouseOver: true
49701 * <b>Common Problems:</b><br/>
49702 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
49703 * element will correct this<br/>
49704 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
49705 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
49706 * are unpredictable.<br/>
49707 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
49708 * grid to calculate dimensions/offsets.<br/>
49710 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49711 * The container MUST have some type of size defined for the grid to fill. The container will be
49712 * automatically set to position relative if it isn't already.
49713 * @param {Object} config A config object that sets properties on this grid.
49715 Roo.grid.Grid = function(container, config){
49716 // initialize the container
49717 this.container = Roo.get(container);
49718 this.container.update("");
49719 this.container.setStyle("overflow", "hidden");
49720 this.container.addClass('x-grid-container');
49722 this.id = this.container.id;
49724 Roo.apply(this, config);
49725 // check and correct shorthanded configs
49727 this.dataSource = this.ds;
49731 this.colModel = this.cm;
49735 this.selModel = this.sm;
49739 if (this.selModel) {
49740 this.selModel = Roo.factory(this.selModel, Roo.grid);
49741 this.sm = this.selModel;
49742 this.sm.xmodule = this.xmodule || false;
49744 if (typeof(this.colModel.config) == 'undefined') {
49745 this.colModel = new Roo.grid.ColumnModel(this.colModel);
49746 this.cm = this.colModel;
49747 this.cm.xmodule = this.xmodule || false;
49749 if (this.dataSource) {
49750 this.dataSource= Roo.factory(this.dataSource, Roo.data);
49751 this.ds = this.dataSource;
49752 this.ds.xmodule = this.xmodule || false;
49759 this.container.setWidth(this.width);
49763 this.container.setHeight(this.height);
49770 * The raw click event for the entire grid.
49771 * @param {Roo.EventObject} e
49776 * The raw dblclick event for the entire grid.
49777 * @param {Roo.EventObject} e
49781 * @event contextmenu
49782 * The raw contextmenu event for the entire grid.
49783 * @param {Roo.EventObject} e
49785 "contextmenu" : true,
49788 * The raw mousedown event for the entire grid.
49789 * @param {Roo.EventObject} e
49791 "mousedown" : true,
49794 * The raw mouseup event for the entire grid.
49795 * @param {Roo.EventObject} e
49800 * The raw mouseover event for the entire grid.
49801 * @param {Roo.EventObject} e
49803 "mouseover" : true,
49806 * The raw mouseout event for the entire grid.
49807 * @param {Roo.EventObject} e
49812 * The raw keypress event for the entire grid.
49813 * @param {Roo.EventObject} e
49818 * The raw keydown event for the entire grid.
49819 * @param {Roo.EventObject} e
49827 * Fires when a cell is clicked
49828 * @param {Grid} this
49829 * @param {Number} rowIndex
49830 * @param {Number} columnIndex
49831 * @param {Roo.EventObject} e
49833 "cellclick" : true,
49835 * @event celldblclick
49836 * Fires when a cell is double clicked
49837 * @param {Grid} this
49838 * @param {Number} rowIndex
49839 * @param {Number} columnIndex
49840 * @param {Roo.EventObject} e
49842 "celldblclick" : true,
49845 * Fires when a row is clicked
49846 * @param {Grid} this
49847 * @param {Number} rowIndex
49848 * @param {Roo.EventObject} e
49852 * @event rowdblclick
49853 * Fires when a row is double clicked
49854 * @param {Grid} this
49855 * @param {Number} rowIndex
49856 * @param {Roo.EventObject} e
49858 "rowdblclick" : true,
49860 * @event headerclick
49861 * Fires when a header is clicked
49862 * @param {Grid} this
49863 * @param {Number} columnIndex
49864 * @param {Roo.EventObject} e
49866 "headerclick" : true,
49868 * @event headerdblclick
49869 * Fires when a header cell is double clicked
49870 * @param {Grid} this
49871 * @param {Number} columnIndex
49872 * @param {Roo.EventObject} e
49874 "headerdblclick" : true,
49876 * @event rowcontextmenu
49877 * Fires when a row is right clicked
49878 * @param {Grid} this
49879 * @param {Number} rowIndex
49880 * @param {Roo.EventObject} e
49882 "rowcontextmenu" : true,
49884 * @event cellcontextmenu
49885 * Fires when a cell is right clicked
49886 * @param {Grid} this
49887 * @param {Number} rowIndex
49888 * @param {Number} cellIndex
49889 * @param {Roo.EventObject} e
49891 "cellcontextmenu" : true,
49893 * @event headercontextmenu
49894 * Fires when a header is right clicked
49895 * @param {Grid} this
49896 * @param {Number} columnIndex
49897 * @param {Roo.EventObject} e
49899 "headercontextmenu" : true,
49901 * @event bodyscroll
49902 * Fires when the body element is scrolled
49903 * @param {Number} scrollLeft
49904 * @param {Number} scrollTop
49906 "bodyscroll" : true,
49908 * @event columnresize
49909 * Fires when the user resizes a column
49910 * @param {Number} columnIndex
49911 * @param {Number} newSize
49913 "columnresize" : true,
49915 * @event columnmove
49916 * Fires when the user moves a column
49917 * @param {Number} oldIndex
49918 * @param {Number} newIndex
49920 "columnmove" : true,
49923 * Fires when row(s) start being dragged
49924 * @param {Grid} this
49925 * @param {Roo.GridDD} dd The drag drop object
49926 * @param {event} e The raw browser event
49928 "startdrag" : true,
49931 * Fires when a drag operation is complete
49932 * @param {Grid} this
49933 * @param {Roo.GridDD} dd The drag drop object
49934 * @param {event} e The raw browser event
49939 * Fires when dragged row(s) are dropped on a valid DD target
49940 * @param {Grid} this
49941 * @param {Roo.GridDD} dd The drag drop object
49942 * @param {String} targetId The target drag drop object
49943 * @param {event} e The raw browser event
49948 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
49949 * @param {Grid} this
49950 * @param {Roo.GridDD} dd The drag drop object
49951 * @param {String} targetId The target drag drop object
49952 * @param {event} e The raw browser event
49957 * Fires when the dragged row(s) first cross another DD target while being dragged
49958 * @param {Grid} this
49959 * @param {Roo.GridDD} dd The drag drop object
49960 * @param {String} targetId The target drag drop object
49961 * @param {event} e The raw browser event
49963 "dragenter" : true,
49966 * Fires when the dragged row(s) leave another DD target while being dragged
49967 * @param {Grid} this
49968 * @param {Roo.GridDD} dd The drag drop object
49969 * @param {String} targetId The target drag drop object
49970 * @param {event} e The raw browser event
49975 * Fires when a row is rendered, so you can change add a style to it.
49976 * @param {GridView} gridview The grid view
49977 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
49983 * Fires when the grid is rendered
49984 * @param {Grid} grid
49989 Roo.grid.Grid.superclass.constructor.call(this);
49991 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
49994 * @cfg {String} ddGroup - drag drop group.
49998 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
50000 minColumnWidth : 25,
50003 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
50004 * <b>on initial render.</b> It is more efficient to explicitly size the columns
50005 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
50007 autoSizeColumns : false,
50010 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
50012 autoSizeHeaders : true,
50015 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
50017 monitorWindowResize : true,
50020 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
50021 * rows measured to get a columns size. Default is 0 (all rows).
50023 maxRowsToMeasure : 0,
50026 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
50028 trackMouseOver : true,
50031 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
50035 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
50037 enableDragDrop : false,
50040 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
50042 enableColumnMove : true,
50045 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
50047 enableColumnHide : true,
50050 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
50052 enableRowHeightSync : false,
50055 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
50060 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
50062 autoHeight : false,
50065 * @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.
50067 autoExpandColumn : false,
50070 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
50073 autoExpandMin : 50,
50076 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
50078 autoExpandMax : 1000,
50081 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
50086 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
50090 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
50100 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
50101 * of a fixed width. Default is false.
50104 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
50107 * Called once after all setup has been completed and the grid is ready to be rendered.
50108 * @return {Roo.grid.Grid} this
50110 render : function()
50112 var c = this.container;
50113 // try to detect autoHeight/width mode
50114 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
50115 this.autoHeight = true;
50117 var view = this.getView();
50120 c.on("click", this.onClick, this);
50121 c.on("dblclick", this.onDblClick, this);
50122 c.on("contextmenu", this.onContextMenu, this);
50123 c.on("keydown", this.onKeyDown, this);
50125 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
50127 this.getSelectionModel().init(this);
50132 this.loadMask = new Roo.LoadMask(this.container,
50133 Roo.apply({store:this.dataSource}, this.loadMask));
50137 if (this.toolbar && this.toolbar.xtype) {
50138 this.toolbar.container = this.getView().getHeaderPanel(true);
50139 this.toolbar = new Roo.Toolbar(this.toolbar);
50141 if (this.footer && this.footer.xtype) {
50142 this.footer.dataSource = this.getDataSource();
50143 this.footer.container = this.getView().getFooterPanel(true);
50144 this.footer = Roo.factory(this.footer, Roo);
50146 if (this.dropTarget && this.dropTarget.xtype) {
50147 delete this.dropTarget.xtype;
50148 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
50152 this.rendered = true;
50153 this.fireEvent('render', this);
50158 * Reconfigures the grid to use a different Store and Column Model.
50159 * The View will be bound to the new objects and refreshed.
50160 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
50161 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
50163 reconfigure : function(dataSource, colModel){
50165 this.loadMask.destroy();
50166 this.loadMask = new Roo.LoadMask(this.container,
50167 Roo.apply({store:dataSource}, this.loadMask));
50169 this.view.bind(dataSource, colModel);
50170 this.dataSource = dataSource;
50171 this.colModel = colModel;
50172 this.view.refresh(true);
50176 onKeyDown : function(e){
50177 this.fireEvent("keydown", e);
50181 * Destroy this grid.
50182 * @param {Boolean} removeEl True to remove the element
50184 destroy : function(removeEl, keepListeners){
50186 this.loadMask.destroy();
50188 var c = this.container;
50189 c.removeAllListeners();
50190 this.view.destroy();
50191 this.colModel.purgeListeners();
50192 if(!keepListeners){
50193 this.purgeListeners();
50196 if(removeEl === true){
50202 processEvent : function(name, e){
50203 this.fireEvent(name, e);
50204 var t = e.getTarget();
50206 var header = v.findHeaderIndex(t);
50207 if(header !== false){
50208 this.fireEvent("header" + name, this, header, e);
50210 var row = v.findRowIndex(t);
50211 var cell = v.findCellIndex(t);
50213 this.fireEvent("row" + name, this, row, e);
50214 if(cell !== false){
50215 this.fireEvent("cell" + name, this, row, cell, e);
50222 onClick : function(e){
50223 this.processEvent("click", e);
50227 onContextMenu : function(e, t){
50228 this.processEvent("contextmenu", e);
50232 onDblClick : function(e){
50233 this.processEvent("dblclick", e);
50237 walkCells : function(row, col, step, fn, scope){
50238 var cm = this.colModel, clen = cm.getColumnCount();
50239 var ds = this.dataSource, rlen = ds.getCount(), first = true;
50251 if(fn.call(scope || this, row, col, cm) === true){
50269 if(fn.call(scope || this, row, col, cm) === true){
50281 getSelections : function(){
50282 return this.selModel.getSelections();
50286 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
50287 * but if manual update is required this method will initiate it.
50289 autoSize : function(){
50291 this.view.layout();
50292 if(this.view.adjustForScroll){
50293 this.view.adjustForScroll();
50299 * Returns the grid's underlying element.
50300 * @return {Element} The element
50302 getGridEl : function(){
50303 return this.container;
50306 // private for compatibility, overridden by editor grid
50307 stopEditing : function(){},
50310 * Returns the grid's SelectionModel.
50311 * @return {SelectionModel}
50313 getSelectionModel : function(){
50314 if(!this.selModel){
50315 this.selModel = new Roo.grid.RowSelectionModel();
50317 return this.selModel;
50321 * Returns the grid's DataSource.
50322 * @return {DataSource}
50324 getDataSource : function(){
50325 return this.dataSource;
50329 * Returns the grid's ColumnModel.
50330 * @return {ColumnModel}
50332 getColumnModel : function(){
50333 return this.colModel;
50337 * Returns the grid's GridView object.
50338 * @return {GridView}
50340 getView : function(){
50342 this.view = new Roo.grid.GridView(this.viewConfig);
50347 * Called to get grid's drag proxy text, by default returns this.ddText.
50350 getDragDropText : function(){
50351 var count = this.selModel.getCount();
50352 return String.format(this.ddText, count, count == 1 ? '' : 's');
50356 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
50357 * %0 is replaced with the number of selected rows.
50360 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
50362 * Ext JS Library 1.1.1
50363 * Copyright(c) 2006-2007, Ext JS, LLC.
50365 * Originally Released Under LGPL - original licence link has changed is not relivant.
50368 * <script type="text/javascript">
50371 Roo.grid.AbstractGridView = function(){
50375 "beforerowremoved" : true,
50376 "beforerowsinserted" : true,
50377 "beforerefresh" : true,
50378 "rowremoved" : true,
50379 "rowsinserted" : true,
50380 "rowupdated" : true,
50383 Roo.grid.AbstractGridView.superclass.constructor.call(this);
50386 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
50387 rowClass : "x-grid-row",
50388 cellClass : "x-grid-cell",
50389 tdClass : "x-grid-td",
50390 hdClass : "x-grid-hd",
50391 splitClass : "x-grid-hd-split",
50393 init: function(grid){
50395 var cid = this.grid.getGridEl().id;
50396 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
50397 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
50398 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
50399 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
50402 getColumnRenderers : function(){
50403 var renderers = [];
50404 var cm = this.grid.colModel;
50405 var colCount = cm.getColumnCount();
50406 for(var i = 0; i < colCount; i++){
50407 renderers[i] = cm.getRenderer(i);
50412 getColumnIds : function(){
50414 var cm = this.grid.colModel;
50415 var colCount = cm.getColumnCount();
50416 for(var i = 0; i < colCount; i++){
50417 ids[i] = cm.getColumnId(i);
50422 getDataIndexes : function(){
50423 if(!this.indexMap){
50424 this.indexMap = this.buildIndexMap();
50426 return this.indexMap.colToData;
50429 getColumnIndexByDataIndex : function(dataIndex){
50430 if(!this.indexMap){
50431 this.indexMap = this.buildIndexMap();
50433 return this.indexMap.dataToCol[dataIndex];
50437 * Set a css style for a column dynamically.
50438 * @param {Number} colIndex The index of the column
50439 * @param {String} name The css property name
50440 * @param {String} value The css value
50442 setCSSStyle : function(colIndex, name, value){
50443 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
50444 Roo.util.CSS.updateRule(selector, name, value);
50447 generateRules : function(cm){
50448 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
50449 Roo.util.CSS.removeStyleSheet(rulesId);
50450 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50451 var cid = cm.getColumnId(i);
50452 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
50453 this.tdSelector, cid, " {\n}\n",
50454 this.hdSelector, cid, " {\n}\n",
50455 this.splitSelector, cid, " {\n}\n");
50457 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
50461 * Ext JS Library 1.1.1
50462 * Copyright(c) 2006-2007, Ext JS, LLC.
50464 * Originally Released Under LGPL - original licence link has changed is not relivant.
50467 * <script type="text/javascript">
50471 // This is a support class used internally by the Grid components
50472 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
50474 this.view = grid.getView();
50475 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
50476 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
50478 this.setHandleElId(Roo.id(hd));
50479 this.setOuterHandleElId(Roo.id(hd2));
50481 this.scroll = false;
50483 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
50485 getDragData : function(e){
50486 var t = Roo.lib.Event.getTarget(e);
50487 var h = this.view.findHeaderCell(t);
50489 return {ddel: h.firstChild, header:h};
50494 onInitDrag : function(e){
50495 this.view.headersDisabled = true;
50496 var clone = this.dragData.ddel.cloneNode(true);
50497 clone.id = Roo.id();
50498 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
50499 this.proxy.update(clone);
50503 afterValidDrop : function(){
50505 setTimeout(function(){
50506 v.headersDisabled = false;
50510 afterInvalidDrop : function(){
50512 setTimeout(function(){
50513 v.headersDisabled = false;
50519 * Ext JS Library 1.1.1
50520 * Copyright(c) 2006-2007, Ext JS, LLC.
50522 * Originally Released Under LGPL - original licence link has changed is not relivant.
50525 * <script type="text/javascript">
50528 // This is a support class used internally by the Grid components
50529 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
50531 this.view = grid.getView();
50532 // split the proxies so they don't interfere with mouse events
50533 this.proxyTop = Roo.DomHelper.append(document.body, {
50534 cls:"col-move-top", html:" "
50536 this.proxyBottom = Roo.DomHelper.append(document.body, {
50537 cls:"col-move-bottom", html:" "
50539 this.proxyTop.hide = this.proxyBottom.hide = function(){
50540 this.setLeftTop(-100,-100);
50541 this.setStyle("visibility", "hidden");
50543 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
50544 // temporarily disabled
50545 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
50546 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
50548 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
50549 proxyOffsets : [-4, -9],
50550 fly: Roo.Element.fly,
50552 getTargetFromEvent : function(e){
50553 var t = Roo.lib.Event.getTarget(e);
50554 var cindex = this.view.findCellIndex(t);
50555 if(cindex !== false){
50556 return this.view.getHeaderCell(cindex);
50561 nextVisible : function(h){
50562 var v = this.view, cm = this.grid.colModel;
50565 if(!cm.isHidden(v.getCellIndex(h))){
50573 prevVisible : function(h){
50574 var v = this.view, cm = this.grid.colModel;
50577 if(!cm.isHidden(v.getCellIndex(h))){
50585 positionIndicator : function(h, n, e){
50586 var x = Roo.lib.Event.getPageX(e);
50587 var r = Roo.lib.Dom.getRegion(n.firstChild);
50588 var px, pt, py = r.top + this.proxyOffsets[1];
50589 if((r.right - x) <= (r.right-r.left)/2){
50590 px = r.right+this.view.borderWidth;
50596 var oldIndex = this.view.getCellIndex(h);
50597 var newIndex = this.view.getCellIndex(n);
50599 if(this.grid.colModel.isFixed(newIndex)){
50603 var locked = this.grid.colModel.isLocked(newIndex);
50608 if(oldIndex < newIndex){
50611 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
50614 px += this.proxyOffsets[0];
50615 this.proxyTop.setLeftTop(px, py);
50616 this.proxyTop.show();
50617 if(!this.bottomOffset){
50618 this.bottomOffset = this.view.mainHd.getHeight();
50620 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
50621 this.proxyBottom.show();
50625 onNodeEnter : function(n, dd, e, data){
50626 if(data.header != n){
50627 this.positionIndicator(data.header, n, e);
50631 onNodeOver : function(n, dd, e, data){
50632 var result = false;
50633 if(data.header != n){
50634 result = this.positionIndicator(data.header, n, e);
50637 this.proxyTop.hide();
50638 this.proxyBottom.hide();
50640 return result ? this.dropAllowed : this.dropNotAllowed;
50643 onNodeOut : function(n, dd, e, data){
50644 this.proxyTop.hide();
50645 this.proxyBottom.hide();
50648 onNodeDrop : function(n, dd, e, data){
50649 var h = data.header;
50651 var cm = this.grid.colModel;
50652 var x = Roo.lib.Event.getPageX(e);
50653 var r = Roo.lib.Dom.getRegion(n.firstChild);
50654 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
50655 var oldIndex = this.view.getCellIndex(h);
50656 var newIndex = this.view.getCellIndex(n);
50657 var locked = cm.isLocked(newIndex);
50661 if(oldIndex < newIndex){
50664 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
50667 cm.setLocked(oldIndex, locked, true);
50668 cm.moveColumn(oldIndex, newIndex);
50669 this.grid.fireEvent("columnmove", oldIndex, newIndex);
50677 * Ext JS Library 1.1.1
50678 * Copyright(c) 2006-2007, Ext JS, LLC.
50680 * Originally Released Under LGPL - original licence link has changed is not relivant.
50683 * <script type="text/javascript">
50687 * @class Roo.grid.GridView
50688 * @extends Roo.util.Observable
50691 * @param {Object} config
50693 Roo.grid.GridView = function(config){
50694 Roo.grid.GridView.superclass.constructor.call(this);
50697 Roo.apply(this, config);
50700 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
50702 unselectable : 'unselectable="on"',
50703 unselectableCls : 'x-unselectable',
50706 rowClass : "x-grid-row",
50708 cellClass : "x-grid-col",
50710 tdClass : "x-grid-td",
50712 hdClass : "x-grid-hd",
50714 splitClass : "x-grid-split",
50716 sortClasses : ["sort-asc", "sort-desc"],
50718 enableMoveAnim : false,
50722 dh : Roo.DomHelper,
50724 fly : Roo.Element.fly,
50726 css : Roo.util.CSS,
50732 scrollIncrement : 22,
50734 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
50736 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
50738 bind : function(ds, cm){
50740 this.ds.un("load", this.onLoad, this);
50741 this.ds.un("datachanged", this.onDataChange, this);
50742 this.ds.un("add", this.onAdd, this);
50743 this.ds.un("remove", this.onRemove, this);
50744 this.ds.un("update", this.onUpdate, this);
50745 this.ds.un("clear", this.onClear, this);
50748 ds.on("load", this.onLoad, this);
50749 ds.on("datachanged", this.onDataChange, this);
50750 ds.on("add", this.onAdd, this);
50751 ds.on("remove", this.onRemove, this);
50752 ds.on("update", this.onUpdate, this);
50753 ds.on("clear", this.onClear, this);
50758 this.cm.un("widthchange", this.onColWidthChange, this);
50759 this.cm.un("headerchange", this.onHeaderChange, this);
50760 this.cm.un("hiddenchange", this.onHiddenChange, this);
50761 this.cm.un("columnmoved", this.onColumnMove, this);
50762 this.cm.un("columnlockchange", this.onColumnLock, this);
50765 this.generateRules(cm);
50766 cm.on("widthchange", this.onColWidthChange, this);
50767 cm.on("headerchange", this.onHeaderChange, this);
50768 cm.on("hiddenchange", this.onHiddenChange, this);
50769 cm.on("columnmoved", this.onColumnMove, this);
50770 cm.on("columnlockchange", this.onColumnLock, this);
50775 init: function(grid){
50776 Roo.grid.GridView.superclass.init.call(this, grid);
50778 this.bind(grid.dataSource, grid.colModel);
50780 grid.on("headerclick", this.handleHeaderClick, this);
50782 if(grid.trackMouseOver){
50783 grid.on("mouseover", this.onRowOver, this);
50784 grid.on("mouseout", this.onRowOut, this);
50786 grid.cancelTextSelection = function(){};
50787 this.gridId = grid.id;
50789 var tpls = this.templates || {};
50792 tpls.master = new Roo.Template(
50793 '<div class="x-grid" hidefocus="true">',
50794 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
50795 '<div class="x-grid-topbar"></div>',
50796 '<div class="x-grid-scroller"><div></div></div>',
50797 '<div class="x-grid-locked">',
50798 '<div class="x-grid-header">{lockedHeader}</div>',
50799 '<div class="x-grid-body">{lockedBody}</div>',
50801 '<div class="x-grid-viewport">',
50802 '<div class="x-grid-header">{header}</div>',
50803 '<div class="x-grid-body">{body}</div>',
50805 '<div class="x-grid-bottombar"></div>',
50807 '<div class="x-grid-resize-proxy"> </div>',
50810 tpls.master.disableformats = true;
50814 tpls.header = new Roo.Template(
50815 '<table border="0" cellspacing="0" cellpadding="0">',
50816 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
50819 tpls.header.disableformats = true;
50821 tpls.header.compile();
50824 tpls.hcell = new Roo.Template(
50825 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
50826 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
50829 tpls.hcell.disableFormats = true;
50831 tpls.hcell.compile();
50834 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
50835 this.unselectableCls + '" ' + this.unselectable +'> </div>');
50836 tpls.hsplit.disableFormats = true;
50838 tpls.hsplit.compile();
50841 tpls.body = new Roo.Template(
50842 '<table border="0" cellspacing="0" cellpadding="0">',
50843 "<tbody>{rows}</tbody>",
50846 tpls.body.disableFormats = true;
50848 tpls.body.compile();
50851 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
50852 tpls.row.disableFormats = true;
50854 tpls.row.compile();
50857 tpls.cell = new Roo.Template(
50858 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
50859 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
50860 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
50863 tpls.cell.disableFormats = true;
50865 tpls.cell.compile();
50867 this.templates = tpls;
50870 // remap these for backwards compat
50871 onColWidthChange : function(){
50872 this.updateColumns.apply(this, arguments);
50874 onHeaderChange : function(){
50875 this.updateHeaders.apply(this, arguments);
50877 onHiddenChange : function(){
50878 this.handleHiddenChange.apply(this, arguments);
50880 onColumnMove : function(){
50881 this.handleColumnMove.apply(this, arguments);
50883 onColumnLock : function(){
50884 this.handleLockChange.apply(this, arguments);
50887 onDataChange : function(){
50889 this.updateHeaderSortState();
50892 onClear : function(){
50896 onUpdate : function(ds, record){
50897 this.refreshRow(record);
50900 refreshRow : function(record){
50901 var ds = this.ds, index;
50902 if(typeof record == 'number'){
50904 record = ds.getAt(index);
50906 index = ds.indexOf(record);
50908 this.insertRows(ds, index, index, true);
50909 this.onRemove(ds, record, index+1, true);
50910 this.syncRowHeights(index, index);
50912 this.fireEvent("rowupdated", this, index, record);
50915 onAdd : function(ds, records, index){
50916 this.insertRows(ds, index, index + (records.length-1));
50919 onRemove : function(ds, record, index, isUpdate){
50920 if(isUpdate !== true){
50921 this.fireEvent("beforerowremoved", this, index, record);
50923 var bt = this.getBodyTable(), lt = this.getLockedTable();
50924 if(bt.rows[index]){
50925 bt.firstChild.removeChild(bt.rows[index]);
50927 if(lt.rows[index]){
50928 lt.firstChild.removeChild(lt.rows[index]);
50930 if(isUpdate !== true){
50931 this.stripeRows(index);
50932 this.syncRowHeights(index, index);
50934 this.fireEvent("rowremoved", this, index, record);
50938 onLoad : function(){
50939 this.scrollToTop();
50943 * Scrolls the grid to the top
50945 scrollToTop : function(){
50947 this.scroller.dom.scrollTop = 0;
50953 * Gets a panel in the header of the grid that can be used for toolbars etc.
50954 * After modifying the contents of this panel a call to grid.autoSize() may be
50955 * required to register any changes in size.
50956 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
50957 * @return Roo.Element
50959 getHeaderPanel : function(doShow){
50961 this.headerPanel.show();
50963 return this.headerPanel;
50967 * Gets a panel in the footer of the grid that can be used for toolbars etc.
50968 * After modifying the contents of this panel a call to grid.autoSize() may be
50969 * required to register any changes in size.
50970 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
50971 * @return Roo.Element
50973 getFooterPanel : function(doShow){
50975 this.footerPanel.show();
50977 return this.footerPanel;
50980 initElements : function(){
50981 var E = Roo.Element;
50982 var el = this.grid.getGridEl().dom.firstChild;
50983 var cs = el.childNodes;
50985 this.el = new E(el);
50987 this.focusEl = new E(el.firstChild);
50988 this.focusEl.swallowEvent("click", true);
50990 this.headerPanel = new E(cs[1]);
50991 this.headerPanel.enableDisplayMode("block");
50993 this.scroller = new E(cs[2]);
50994 this.scrollSizer = new E(this.scroller.dom.firstChild);
50996 this.lockedWrap = new E(cs[3]);
50997 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
50998 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
51000 this.mainWrap = new E(cs[4]);
51001 this.mainHd = new E(this.mainWrap.dom.firstChild);
51002 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
51004 this.footerPanel = new E(cs[5]);
51005 this.footerPanel.enableDisplayMode("block");
51007 this.resizeProxy = new E(cs[6]);
51009 this.headerSelector = String.format(
51010 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
51011 this.lockedHd.id, this.mainHd.id
51014 this.splitterSelector = String.format(
51015 '#{0} div.x-grid-split, #{1} div.x-grid-split',
51016 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
51019 idToCssName : function(s)
51021 return s.replace(/[^a-z0-9]+/ig, '-');
51024 getHeaderCell : function(index){
51025 return Roo.DomQuery.select(this.headerSelector)[index];
51028 getHeaderCellMeasure : function(index){
51029 return this.getHeaderCell(index).firstChild;
51032 getHeaderCellText : function(index){
51033 return this.getHeaderCell(index).firstChild.firstChild;
51036 getLockedTable : function(){
51037 return this.lockedBody.dom.firstChild;
51040 getBodyTable : function(){
51041 return this.mainBody.dom.firstChild;
51044 getLockedRow : function(index){
51045 return this.getLockedTable().rows[index];
51048 getRow : function(index){
51049 return this.getBodyTable().rows[index];
51052 getRowComposite : function(index){
51054 this.rowEl = new Roo.CompositeElementLite();
51056 var els = [], lrow, mrow;
51057 if(lrow = this.getLockedRow(index)){
51060 if(mrow = this.getRow(index)){
51063 this.rowEl.elements = els;
51067 * Gets the 'td' of the cell
51069 * @param {Integer} rowIndex row to select
51070 * @param {Integer} colIndex column to select
51074 getCell : function(rowIndex, colIndex){
51075 var locked = this.cm.getLockedCount();
51077 if(colIndex < locked){
51078 source = this.lockedBody.dom.firstChild;
51080 source = this.mainBody.dom.firstChild;
51081 colIndex -= locked;
51083 return source.rows[rowIndex].childNodes[colIndex];
51086 getCellText : function(rowIndex, colIndex){
51087 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
51090 getCellBox : function(cell){
51091 var b = this.fly(cell).getBox();
51092 if(Roo.isOpera){ // opera fails to report the Y
51093 b.y = cell.offsetTop + this.mainBody.getY();
51098 getCellIndex : function(cell){
51099 var id = String(cell.className).match(this.cellRE);
51101 return parseInt(id[1], 10);
51106 findHeaderIndex : function(n){
51107 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51108 return r ? this.getCellIndex(r) : false;
51111 findHeaderCell : function(n){
51112 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51113 return r ? r : false;
51116 findRowIndex : function(n){
51120 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
51121 return r ? r.rowIndex : false;
51124 findCellIndex : function(node){
51125 var stop = this.el.dom;
51126 while(node && node != stop){
51127 if(this.findRE.test(node.className)){
51128 return this.getCellIndex(node);
51130 node = node.parentNode;
51135 getColumnId : function(index){
51136 return this.cm.getColumnId(index);
51139 getSplitters : function()
51141 if(this.splitterSelector){
51142 return Roo.DomQuery.select(this.splitterSelector);
51148 getSplitter : function(index){
51149 return this.getSplitters()[index];
51152 onRowOver : function(e, t){
51154 if((row = this.findRowIndex(t)) !== false){
51155 this.getRowComposite(row).addClass("x-grid-row-over");
51159 onRowOut : function(e, t){
51161 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
51162 this.getRowComposite(row).removeClass("x-grid-row-over");
51166 renderHeaders : function(){
51168 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
51169 var cb = [], lb = [], sb = [], lsb = [], p = {};
51170 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51171 p.cellId = "x-grid-hd-0-" + i;
51172 p.splitId = "x-grid-csplit-0-" + i;
51173 p.id = cm.getColumnId(i);
51174 p.title = cm.getColumnTooltip(i) || "";
51175 p.value = cm.getColumnHeader(i) || "";
51176 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
51177 if(!cm.isLocked(i)){
51178 cb[cb.length] = ct.apply(p);
51179 sb[sb.length] = st.apply(p);
51181 lb[lb.length] = ct.apply(p);
51182 lsb[lsb.length] = st.apply(p);
51185 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
51186 ht.apply({cells: cb.join(""), splits:sb.join("")})];
51189 updateHeaders : function(){
51190 var html = this.renderHeaders();
51191 this.lockedHd.update(html[0]);
51192 this.mainHd.update(html[1]);
51196 * Focuses the specified row.
51197 * @param {Number} row The row index
51199 focusRow : function(row)
51201 //Roo.log('GridView.focusRow');
51202 var x = this.scroller.dom.scrollLeft;
51203 this.focusCell(row, 0, false);
51204 this.scroller.dom.scrollLeft = x;
51208 * Focuses the specified cell.
51209 * @param {Number} row The row index
51210 * @param {Number} col The column index
51211 * @param {Boolean} hscroll false to disable horizontal scrolling
51213 focusCell : function(row, col, hscroll)
51215 //Roo.log('GridView.focusCell');
51216 var el = this.ensureVisible(row, col, hscroll);
51217 this.focusEl.alignTo(el, "tl-tl");
51219 this.focusEl.focus();
51221 this.focusEl.focus.defer(1, this.focusEl);
51226 * Scrolls the specified cell into view
51227 * @param {Number} row The row index
51228 * @param {Number} col The column index
51229 * @param {Boolean} hscroll false to disable horizontal scrolling
51231 ensureVisible : function(row, col, hscroll)
51233 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
51234 //return null; //disable for testing.
51235 if(typeof row != "number"){
51236 row = row.rowIndex;
51238 if(row < 0 && row >= this.ds.getCount()){
51241 col = (col !== undefined ? col : 0);
51242 var cm = this.grid.colModel;
51243 while(cm.isHidden(col)){
51247 var el = this.getCell(row, col);
51251 var c = this.scroller.dom;
51253 var ctop = parseInt(el.offsetTop, 10);
51254 var cleft = parseInt(el.offsetLeft, 10);
51255 var cbot = ctop + el.offsetHeight;
51256 var cright = cleft + el.offsetWidth;
51258 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
51259 var stop = parseInt(c.scrollTop, 10);
51260 var sleft = parseInt(c.scrollLeft, 10);
51261 var sbot = stop + ch;
51262 var sright = sleft + c.clientWidth;
51264 Roo.log('GridView.ensureVisible:' +
51266 ' c.clientHeight:' + c.clientHeight +
51267 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
51275 c.scrollTop = ctop;
51276 //Roo.log("set scrolltop to ctop DISABLE?");
51277 }else if(cbot > sbot){
51278 //Roo.log("set scrolltop to cbot-ch");
51279 c.scrollTop = cbot-ch;
51282 if(hscroll !== false){
51284 c.scrollLeft = cleft;
51285 }else if(cright > sright){
51286 c.scrollLeft = cright-c.clientWidth;
51293 updateColumns : function(){
51294 this.grid.stopEditing();
51295 var cm = this.grid.colModel, colIds = this.getColumnIds();
51296 //var totalWidth = cm.getTotalWidth();
51298 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51299 //if(cm.isHidden(i)) continue;
51300 var w = cm.getColumnWidth(i);
51301 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
51302 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
51304 this.updateSplitters();
51307 generateRules : function(cm){
51308 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
51309 Roo.util.CSS.removeStyleSheet(rulesId);
51310 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51311 var cid = cm.getColumnId(i);
51313 if(cm.config[i].align){
51314 align = 'text-align:'+cm.config[i].align+';';
51317 if(cm.isHidden(i)){
51318 hidden = 'display:none;';
51320 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
51322 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
51323 this.hdSelector, cid, " {\n", align, width, "}\n",
51324 this.tdSelector, cid, " {\n",hidden,"\n}\n",
51325 this.splitSelector, cid, " {\n", hidden , "\n}\n");
51327 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51330 updateSplitters : function(){
51331 var cm = this.cm, s = this.getSplitters();
51332 if(s){ // splitters not created yet
51333 var pos = 0, locked = true;
51334 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51335 if(cm.isHidden(i)) continue;
51336 var w = cm.getColumnWidth(i); // make sure it's a number
51337 if(!cm.isLocked(i) && locked){
51342 s[i].style.left = (pos-this.splitOffset) + "px";
51347 handleHiddenChange : function(colModel, colIndex, hidden){
51349 this.hideColumn(colIndex);
51351 this.unhideColumn(colIndex);
51355 hideColumn : function(colIndex){
51356 var cid = this.getColumnId(colIndex);
51357 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
51358 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
51360 this.updateHeaders();
51362 this.updateSplitters();
51366 unhideColumn : function(colIndex){
51367 var cid = this.getColumnId(colIndex);
51368 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
51369 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
51372 this.updateHeaders();
51374 this.updateSplitters();
51378 insertRows : function(dm, firstRow, lastRow, isUpdate){
51379 if(firstRow == 0 && lastRow == dm.getCount()-1){
51383 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
51385 var s = this.getScrollState();
51386 var markup = this.renderRows(firstRow, lastRow);
51387 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
51388 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
51389 this.restoreScroll(s);
51391 this.fireEvent("rowsinserted", this, firstRow, lastRow);
51392 this.syncRowHeights(firstRow, lastRow);
51393 this.stripeRows(firstRow);
51399 bufferRows : function(markup, target, index){
51400 var before = null, trows = target.rows, tbody = target.tBodies[0];
51401 if(index < trows.length){
51402 before = trows[index];
51404 var b = document.createElement("div");
51405 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
51406 var rows = b.firstChild.rows;
51407 for(var i = 0, len = rows.length; i < len; i++){
51409 tbody.insertBefore(rows[0], before);
51411 tbody.appendChild(rows[0]);
51418 deleteRows : function(dm, firstRow, lastRow){
51419 if(dm.getRowCount()<1){
51420 this.fireEvent("beforerefresh", this);
51421 this.mainBody.update("");
51422 this.lockedBody.update("");
51423 this.fireEvent("refresh", this);
51425 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
51426 var bt = this.getBodyTable();
51427 var tbody = bt.firstChild;
51428 var rows = bt.rows;
51429 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
51430 tbody.removeChild(rows[firstRow]);
51432 this.stripeRows(firstRow);
51433 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
51437 updateRows : function(dataSource, firstRow, lastRow){
51438 var s = this.getScrollState();
51440 this.restoreScroll(s);
51443 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
51447 this.updateHeaderSortState();
51450 getScrollState : function(){
51452 var sb = this.scroller.dom;
51453 return {left: sb.scrollLeft, top: sb.scrollTop};
51456 stripeRows : function(startRow){
51457 if(!this.grid.stripeRows || this.ds.getCount() < 1){
51460 startRow = startRow || 0;
51461 var rows = this.getBodyTable().rows;
51462 var lrows = this.getLockedTable().rows;
51463 var cls = ' x-grid-row-alt ';
51464 for(var i = startRow, len = rows.length; i < len; i++){
51465 var row = rows[i], lrow = lrows[i];
51466 var isAlt = ((i+1) % 2 == 0);
51467 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
51468 if(isAlt == hasAlt){
51472 row.className += " x-grid-row-alt";
51474 row.className = row.className.replace("x-grid-row-alt", "");
51477 lrow.className = row.className;
51482 restoreScroll : function(state){
51483 //Roo.log('GridView.restoreScroll');
51484 var sb = this.scroller.dom;
51485 sb.scrollLeft = state.left;
51486 sb.scrollTop = state.top;
51490 syncScroll : function(){
51491 //Roo.log('GridView.syncScroll');
51492 var sb = this.scroller.dom;
51493 var sh = this.mainHd.dom;
51494 var bs = this.mainBody.dom;
51495 var lv = this.lockedBody.dom;
51496 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
51497 lv.scrollTop = bs.scrollTop = sb.scrollTop;
51500 handleScroll : function(e){
51502 var sb = this.scroller.dom;
51503 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
51507 handleWheel : function(e){
51508 var d = e.getWheelDelta();
51509 this.scroller.dom.scrollTop -= d*22;
51510 // set this here to prevent jumpy scrolling on large tables
51511 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
51515 renderRows : function(startRow, endRow){
51516 // pull in all the crap needed to render rows
51517 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
51518 var colCount = cm.getColumnCount();
51520 if(ds.getCount() < 1){
51524 // build a map for all the columns
51526 for(var i = 0; i < colCount; i++){
51527 var name = cm.getDataIndex(i);
51529 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
51530 renderer : cm.getRenderer(i),
51531 id : cm.getColumnId(i),
51532 locked : cm.isLocked(i)
51536 startRow = startRow || 0;
51537 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
51539 // records to render
51540 var rs = ds.getRange(startRow, endRow);
51542 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
51545 // As much as I hate to duplicate code, this was branched because FireFox really hates
51546 // [].join("") on strings. The performance difference was substantial enough to
51547 // branch this function
51548 doRender : Roo.isGecko ?
51549 function(cs, rs, ds, startRow, colCount, stripe){
51550 var ts = this.templates, ct = ts.cell, rt = ts.row;
51552 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
51554 var hasListener = this.grid.hasListener('rowclass');
51556 for(var j = 0, len = rs.length; j < len; j++){
51557 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
51558 for(var i = 0; i < colCount; i++){
51560 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
51562 p.css = p.attr = "";
51563 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
51564 if(p.value == undefined || p.value === "") p.value = " ";
51565 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
51566 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
51568 var markup = ct.apply(p);
51576 if(stripe && ((rowIndex+1) % 2 == 0)){
51577 alt.push("x-grid-row-alt")
51580 alt.push( " x-grid-dirty-row");
51583 if(this.getRowClass){
51584 alt.push(this.getRowClass(r, rowIndex));
51590 rowIndex : rowIndex,
51593 this.grid.fireEvent('rowclass', this, rowcfg);
51594 alt.push(rowcfg.rowClass);
51596 rp.alt = alt.join(" ");
51597 lbuf+= rt.apply(rp);
51599 buf+= rt.apply(rp);
51601 return [lbuf, buf];
51603 function(cs, rs, ds, startRow, colCount, stripe){
51604 var ts = this.templates, ct = ts.cell, rt = ts.row;
51606 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
51607 var hasListener = this.grid.hasListener('rowclass');
51610 for(var j = 0, len = rs.length; j < len; j++){
51611 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
51612 for(var i = 0; i < colCount; i++){
51614 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
51616 p.css = p.attr = "";
51617 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
51618 if(p.value == undefined || p.value === "") p.value = " ";
51619 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
51620 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
51623 var markup = ct.apply(p);
51625 cb[cb.length] = markup;
51627 lcb[lcb.length] = markup;
51631 if(stripe && ((rowIndex+1) % 2 == 0)){
51632 alt.push( "x-grid-row-alt");
51635 alt.push(" x-grid-dirty-row");
51638 if(this.getRowClass){
51639 alt.push( this.getRowClass(r, rowIndex));
51645 rowIndex : rowIndex,
51648 this.grid.fireEvent('rowclass', this, rowcfg);
51649 alt.push(rowcfg.rowClass);
51651 rp.alt = alt.join(" ");
51652 rp.cells = lcb.join("");
51653 lbuf[lbuf.length] = rt.apply(rp);
51654 rp.cells = cb.join("");
51655 buf[buf.length] = rt.apply(rp);
51657 return [lbuf.join(""), buf.join("")];
51660 renderBody : function(){
51661 var markup = this.renderRows();
51662 var bt = this.templates.body;
51663 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
51667 * Refreshes the grid
51668 * @param {Boolean} headersToo
51670 refresh : function(headersToo){
51671 this.fireEvent("beforerefresh", this);
51672 this.grid.stopEditing();
51673 var result = this.renderBody();
51674 this.lockedBody.update(result[0]);
51675 this.mainBody.update(result[1]);
51676 if(headersToo === true){
51677 this.updateHeaders();
51678 this.updateColumns();
51679 this.updateSplitters();
51680 this.updateHeaderSortState();
51682 this.syncRowHeights();
51684 this.fireEvent("refresh", this);
51687 handleColumnMove : function(cm, oldIndex, newIndex){
51688 this.indexMap = null;
51689 var s = this.getScrollState();
51690 this.refresh(true);
51691 this.restoreScroll(s);
51692 this.afterMove(newIndex);
51695 afterMove : function(colIndex){
51696 if(this.enableMoveAnim && Roo.enableFx){
51697 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
51699 // if multisort - fix sortOrder, and reload..
51700 if (this.grid.dataSource.multiSort) {
51701 // the we can call sort again..
51702 var dm = this.grid.dataSource;
51703 var cm = this.grid.colModel;
51705 for(var i = 0; i < cm.config.length; i++ ) {
51707 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
51708 continue; // dont' bother, it's not in sort list or being set.
51711 so.push(cm.config[i].dataIndex);
51714 dm.load(dm.lastOptions);
51721 updateCell : function(dm, rowIndex, dataIndex){
51722 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
51723 if(typeof colIndex == "undefined"){ // not present in grid
51726 var cm = this.grid.colModel;
51727 var cell = this.getCell(rowIndex, colIndex);
51728 var cellText = this.getCellText(rowIndex, colIndex);
51731 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
51732 id : cm.getColumnId(colIndex),
51733 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
51735 var renderer = cm.getRenderer(colIndex);
51736 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
51737 if(typeof val == "undefined" || val === "") val = " ";
51738 cellText.innerHTML = val;
51739 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
51740 this.syncRowHeights(rowIndex, rowIndex);
51743 calcColumnWidth : function(colIndex, maxRowsToMeasure){
51745 if(this.grid.autoSizeHeaders){
51746 var h = this.getHeaderCellMeasure(colIndex);
51747 maxWidth = Math.max(maxWidth, h.scrollWidth);
51750 if(this.cm.isLocked(colIndex)){
51751 tb = this.getLockedTable();
51754 tb = this.getBodyTable();
51755 index = colIndex - this.cm.getLockedCount();
51758 var rows = tb.rows;
51759 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
51760 for(var i = 0; i < stopIndex; i++){
51761 var cell = rows[i].childNodes[index].firstChild;
51762 maxWidth = Math.max(maxWidth, cell.scrollWidth);
51765 return maxWidth + /*margin for error in IE*/ 5;
51768 * Autofit a column to its content.
51769 * @param {Number} colIndex
51770 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
51772 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
51773 if(this.cm.isHidden(colIndex)){
51774 return; // can't calc a hidden column
51777 var cid = this.cm.getColumnId(colIndex);
51778 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
51779 if(this.grid.autoSizeHeaders){
51780 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
51783 var newWidth = this.calcColumnWidth(colIndex);
51784 this.cm.setColumnWidth(colIndex,
51785 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
51786 if(!suppressEvent){
51787 this.grid.fireEvent("columnresize", colIndex, newWidth);
51792 * Autofits all columns to their content and then expands to fit any extra space in the grid
51794 autoSizeColumns : function(){
51795 var cm = this.grid.colModel;
51796 var colCount = cm.getColumnCount();
51797 for(var i = 0; i < colCount; i++){
51798 this.autoSizeColumn(i, true, true);
51800 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
51803 this.updateColumns();
51809 * Autofits all columns to the grid's width proportionate with their current size
51810 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
51812 fitColumns : function(reserveScrollSpace){
51813 var cm = this.grid.colModel;
51814 var colCount = cm.getColumnCount();
51818 for (i = 0; i < colCount; i++){
51819 if(!cm.isHidden(i) && !cm.isFixed(i)){
51820 w = cm.getColumnWidth(i);
51826 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
51827 if(reserveScrollSpace){
51830 var frac = (avail - cm.getTotalWidth())/width;
51831 while (cols.length){
51834 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
51836 this.updateColumns();
51840 onRowSelect : function(rowIndex){
51841 var row = this.getRowComposite(rowIndex);
51842 row.addClass("x-grid-row-selected");
51845 onRowDeselect : function(rowIndex){
51846 var row = this.getRowComposite(rowIndex);
51847 row.removeClass("x-grid-row-selected");
51850 onCellSelect : function(row, col){
51851 var cell = this.getCell(row, col);
51853 Roo.fly(cell).addClass("x-grid-cell-selected");
51857 onCellDeselect : function(row, col){
51858 var cell = this.getCell(row, col);
51860 Roo.fly(cell).removeClass("x-grid-cell-selected");
51864 updateHeaderSortState : function(){
51866 // sort state can be single { field: xxx, direction : yyy}
51867 // or { xxx=>ASC , yyy : DESC ..... }
51870 if (!this.ds.multiSort) {
51871 var state = this.ds.getSortState();
51875 mstate[state.field] = state.direction;
51876 // FIXME... - this is not used here.. but might be elsewhere..
51877 this.sortState = state;
51880 mstate = this.ds.sortToggle;
51882 //remove existing sort classes..
51884 var sc = this.sortClasses;
51885 var hds = this.el.select(this.headerSelector).removeClass(sc);
51887 for(var f in mstate) {
51889 var sortColumn = this.cm.findColumnIndex(f);
51891 if(sortColumn != -1){
51892 var sortDir = mstate[f];
51893 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
51902 handleHeaderClick : function(g, index){
51903 if(this.headersDisabled){
51906 var dm = g.dataSource, cm = g.colModel;
51907 if(!cm.isSortable(index)){
51912 if (dm.multiSort) {
51913 // update the sortOrder
51915 for(var i = 0; i < cm.config.length; i++ ) {
51917 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
51918 continue; // dont' bother, it's not in sort list or being set.
51921 so.push(cm.config[i].dataIndex);
51927 dm.sort(cm.getDataIndex(index));
51931 destroy : function(){
51933 this.colMenu.removeAll();
51934 Roo.menu.MenuMgr.unregister(this.colMenu);
51935 this.colMenu.getEl().remove();
51936 delete this.colMenu;
51939 this.hmenu.removeAll();
51940 Roo.menu.MenuMgr.unregister(this.hmenu);
51941 this.hmenu.getEl().remove();
51944 if(this.grid.enableColumnMove){
51945 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51947 for(var dd in dds){
51948 if(!dds[dd].config.isTarget && dds[dd].dragElId){
51949 var elid = dds[dd].dragElId;
51951 Roo.get(elid).remove();
51952 } else if(dds[dd].config.isTarget){
51953 dds[dd].proxyTop.remove();
51954 dds[dd].proxyBottom.remove();
51957 if(Roo.dd.DDM.locationCache[dd]){
51958 delete Roo.dd.DDM.locationCache[dd];
51961 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51964 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
51965 this.bind(null, null);
51966 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
51969 handleLockChange : function(){
51970 this.refresh(true);
51973 onDenyColumnLock : function(){
51977 onDenyColumnHide : function(){
51981 handleHdMenuClick : function(item){
51982 var index = this.hdCtxIndex;
51983 var cm = this.cm, ds = this.ds;
51986 ds.sort(cm.getDataIndex(index), "ASC");
51989 ds.sort(cm.getDataIndex(index), "DESC");
51992 var lc = cm.getLockedCount();
51993 if(cm.getColumnCount(true) <= lc+1){
51994 this.onDenyColumnLock();
51998 cm.setLocked(index, true, true);
51999 cm.moveColumn(index, lc);
52000 this.grid.fireEvent("columnmove", index, lc);
52002 cm.setLocked(index, true);
52006 var lc = cm.getLockedCount();
52007 if((lc-1) != index){
52008 cm.setLocked(index, false, true);
52009 cm.moveColumn(index, lc-1);
52010 this.grid.fireEvent("columnmove", index, lc-1);
52012 cm.setLocked(index, false);
52016 index = cm.getIndexById(item.id.substr(4));
52018 if(item.checked && cm.getColumnCount(true) <= 1){
52019 this.onDenyColumnHide();
52022 cm.setHidden(index, item.checked);
52028 beforeColMenuShow : function(){
52029 var cm = this.cm, colCount = cm.getColumnCount();
52030 this.colMenu.removeAll();
52031 for(var i = 0; i < colCount; i++){
52032 this.colMenu.add(new Roo.menu.CheckItem({
52033 id: "col-"+cm.getColumnId(i),
52034 text: cm.getColumnHeader(i),
52035 checked: !cm.isHidden(i),
52041 handleHdCtx : function(g, index, e){
52043 var hd = this.getHeaderCell(index);
52044 this.hdCtxIndex = index;
52045 var ms = this.hmenu.items, cm = this.cm;
52046 ms.get("asc").setDisabled(!cm.isSortable(index));
52047 ms.get("desc").setDisabled(!cm.isSortable(index));
52048 if(this.grid.enableColLock !== false){
52049 ms.get("lock").setDisabled(cm.isLocked(index));
52050 ms.get("unlock").setDisabled(!cm.isLocked(index));
52052 this.hmenu.show(hd, "tl-bl");
52055 handleHdOver : function(e){
52056 var hd = this.findHeaderCell(e.getTarget());
52057 if(hd && !this.headersDisabled){
52058 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
52059 this.fly(hd).addClass("x-grid-hd-over");
52064 handleHdOut : function(e){
52065 var hd = this.findHeaderCell(e.getTarget());
52067 this.fly(hd).removeClass("x-grid-hd-over");
52071 handleSplitDblClick : function(e, t){
52072 var i = this.getCellIndex(t);
52073 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
52074 this.autoSizeColumn(i, true);
52079 render : function(){
52082 var colCount = cm.getColumnCount();
52084 if(this.grid.monitorWindowResize === true){
52085 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52087 var header = this.renderHeaders();
52088 var body = this.templates.body.apply({rows:""});
52089 var html = this.templates.master.apply({
52092 lockedHeader: header[0],
52096 //this.updateColumns();
52098 this.grid.getGridEl().dom.innerHTML = html;
52100 this.initElements();
52102 // a kludge to fix the random scolling effect in webkit
52103 this.el.on("scroll", function() {
52104 this.el.dom.scrollTop=0; // hopefully not recursive..
52107 this.scroller.on("scroll", this.handleScroll, this);
52108 this.lockedBody.on("mousewheel", this.handleWheel, this);
52109 this.mainBody.on("mousewheel", this.handleWheel, this);
52111 this.mainHd.on("mouseover", this.handleHdOver, this);
52112 this.mainHd.on("mouseout", this.handleHdOut, this);
52113 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
52114 {delegate: "."+this.splitClass});
52116 this.lockedHd.on("mouseover", this.handleHdOver, this);
52117 this.lockedHd.on("mouseout", this.handleHdOut, this);
52118 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
52119 {delegate: "."+this.splitClass});
52121 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
52122 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52125 this.updateSplitters();
52127 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
52128 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52129 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52132 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
52133 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
52135 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
52136 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
52138 if(this.grid.enableColLock !== false){
52139 this.hmenu.add('-',
52140 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
52141 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
52144 if(this.grid.enableColumnHide !== false){
52146 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
52147 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
52148 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
52150 this.hmenu.add('-',
52151 {id:"columns", text: this.columnsText, menu: this.colMenu}
52154 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
52156 this.grid.on("headercontextmenu", this.handleHdCtx, this);
52159 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
52160 this.dd = new Roo.grid.GridDragZone(this.grid, {
52161 ddGroup : this.grid.ddGroup || 'GridDD'
52167 for(var i = 0; i < colCount; i++){
52168 if(cm.isHidden(i)){
52169 this.hideColumn(i);
52171 if(cm.config[i].align){
52172 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
52173 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
52177 this.updateHeaderSortState();
52179 this.beforeInitialResize();
52182 // two part rendering gives faster view to the user
52183 this.renderPhase2.defer(1, this);
52186 renderPhase2 : function(){
52187 // render the rows now
52189 if(this.grid.autoSizeColumns){
52190 this.autoSizeColumns();
52194 beforeInitialResize : function(){
52198 onColumnSplitterMoved : function(i, w){
52199 this.userResized = true;
52200 var cm = this.grid.colModel;
52201 cm.setColumnWidth(i, w, true);
52202 var cid = cm.getColumnId(i);
52203 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52204 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52205 this.updateSplitters();
52207 this.grid.fireEvent("columnresize", i, w);
52210 syncRowHeights : function(startIndex, endIndex){
52211 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
52212 startIndex = startIndex || 0;
52213 var mrows = this.getBodyTable().rows;
52214 var lrows = this.getLockedTable().rows;
52215 var len = mrows.length-1;
52216 endIndex = Math.min(endIndex || len, len);
52217 for(var i = startIndex; i <= endIndex; i++){
52218 var m = mrows[i], l = lrows[i];
52219 var h = Math.max(m.offsetHeight, l.offsetHeight);
52220 m.style.height = l.style.height = h + "px";
52225 layout : function(initialRender, is2ndPass){
52227 var auto = g.autoHeight;
52228 var scrollOffset = 16;
52229 var c = g.getGridEl(), cm = this.cm,
52230 expandCol = g.autoExpandColumn,
52232 //c.beginMeasure();
52234 if(!c.dom.offsetWidth){ // display:none?
52236 this.lockedWrap.show();
52237 this.mainWrap.show();
52242 var hasLock = this.cm.isLocked(0);
52244 var tbh = this.headerPanel.getHeight();
52245 var bbh = this.footerPanel.getHeight();
52248 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
52249 var newHeight = ch + c.getBorderWidth("tb");
52251 newHeight = Math.min(g.maxHeight, newHeight);
52253 c.setHeight(newHeight);
52257 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
52260 var s = this.scroller;
52262 var csize = c.getSize(true);
52264 this.el.setSize(csize.width, csize.height);
52266 this.headerPanel.setWidth(csize.width);
52267 this.footerPanel.setWidth(csize.width);
52269 var hdHeight = this.mainHd.getHeight();
52270 var vw = csize.width;
52271 var vh = csize.height - (tbh + bbh);
52275 var bt = this.getBodyTable();
52276 var ltWidth = hasLock ?
52277 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
52279 var scrollHeight = bt.offsetHeight;
52280 var scrollWidth = ltWidth + bt.offsetWidth;
52281 var vscroll = false, hscroll = false;
52283 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
52285 var lw = this.lockedWrap, mw = this.mainWrap;
52286 var lb = this.lockedBody, mb = this.mainBody;
52288 setTimeout(function(){
52289 var t = s.dom.offsetTop;
52290 var w = s.dom.clientWidth,
52291 h = s.dom.clientHeight;
52294 lw.setSize(ltWidth, h);
52296 mw.setLeftTop(ltWidth, t);
52297 mw.setSize(w-ltWidth, h);
52299 lb.setHeight(h-hdHeight);
52300 mb.setHeight(h-hdHeight);
52302 if(is2ndPass !== true && !gv.userResized && expandCol){
52303 // high speed resize without full column calculation
52305 var ci = cm.getIndexById(expandCol);
52307 ci = cm.findColumnIndex(expandCol);
52309 ci = Math.max(0, ci); // make sure it's got at least the first col.
52310 var expandId = cm.getColumnId(ci);
52311 var tw = cm.getTotalWidth(false);
52312 var currentWidth = cm.getColumnWidth(ci);
52313 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
52314 if(currentWidth != cw){
52315 cm.setColumnWidth(ci, cw, true);
52316 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
52317 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
52318 gv.updateSplitters();
52319 gv.layout(false, true);
52331 onWindowResize : function(){
52332 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
52338 appendFooter : function(parentEl){
52342 sortAscText : "Sort Ascending",
52343 sortDescText : "Sort Descending",
52344 lockText : "Lock Column",
52345 unlockText : "Unlock Column",
52346 columnsText : "Columns"
52350 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
52351 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
52352 this.proxy.el.addClass('x-grid3-col-dd');
52355 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
52356 handleMouseDown : function(e){
52360 callHandleMouseDown : function(e){
52361 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
52366 * Ext JS Library 1.1.1
52367 * Copyright(c) 2006-2007, Ext JS, LLC.
52369 * Originally Released Under LGPL - original licence link has changed is not relivant.
52372 * <script type="text/javascript">
52376 // This is a support class used internally by the Grid components
52377 Roo.grid.SplitDragZone = function(grid, hd, hd2){
52379 this.view = grid.getView();
52380 this.proxy = this.view.resizeProxy;
52381 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
52382 "gridSplitters" + this.grid.getGridEl().id, {
52383 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
52385 this.setHandleElId(Roo.id(hd));
52386 this.setOuterHandleElId(Roo.id(hd2));
52387 this.scroll = false;
52389 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
52390 fly: Roo.Element.fly,
52392 b4StartDrag : function(x, y){
52393 this.view.headersDisabled = true;
52394 this.proxy.setHeight(this.view.mainWrap.getHeight());
52395 var w = this.cm.getColumnWidth(this.cellIndex);
52396 var minw = Math.max(w-this.grid.minColumnWidth, 0);
52397 this.resetConstraints();
52398 this.setXConstraint(minw, 1000);
52399 this.setYConstraint(0, 0);
52400 this.minX = x - minw;
52401 this.maxX = x + 1000;
52403 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
52407 handleMouseDown : function(e){
52408 ev = Roo.EventObject.setEvent(e);
52409 var t = this.fly(ev.getTarget());
52410 if(t.hasClass("x-grid-split")){
52411 this.cellIndex = this.view.getCellIndex(t.dom);
52412 this.split = t.dom;
52413 this.cm = this.grid.colModel;
52414 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
52415 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
52420 endDrag : function(e){
52421 this.view.headersDisabled = false;
52422 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
52423 var diff = endX - this.startPos;
52424 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
52427 autoOffset : function(){
52428 this.setDelta(0,0);
52432 * Ext JS Library 1.1.1
52433 * Copyright(c) 2006-2007, Ext JS, LLC.
52435 * Originally Released Under LGPL - original licence link has changed is not relivant.
52438 * <script type="text/javascript">
52442 // This is a support class used internally by the Grid components
52443 Roo.grid.GridDragZone = function(grid, config){
52444 this.view = grid.getView();
52445 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
52446 if(this.view.lockedBody){
52447 this.setHandleElId(Roo.id(this.view.mainBody.dom));
52448 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
52450 this.scroll = false;
52452 this.ddel = document.createElement('div');
52453 this.ddel.className = 'x-grid-dd-wrap';
52456 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
52457 ddGroup : "GridDD",
52459 getDragData : function(e){
52460 var t = Roo.lib.Event.getTarget(e);
52461 var rowIndex = this.view.findRowIndex(t);
52462 var sm = this.grid.selModel;
52464 //Roo.log(rowIndex);
52466 if (sm.getSelectedCell) {
52467 // cell selection..
52468 if (!sm.getSelectedCell()) {
52471 if (rowIndex != sm.getSelectedCell()[0]) {
52477 if(rowIndex !== false){
52482 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
52484 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
52487 if (e.hasModifier()){
52488 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
52491 Roo.log("getDragData");
52496 rowIndex: rowIndex,
52497 selections:sm.getSelections ? sm.getSelections() : (
52498 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
52505 onInitDrag : function(e){
52506 var data = this.dragData;
52507 this.ddel.innerHTML = this.grid.getDragDropText();
52508 this.proxy.update(this.ddel);
52509 // fire start drag?
52512 afterRepair : function(){
52513 this.dragging = false;
52516 getRepairXY : function(e, data){
52520 onEndDrag : function(data, e){
52524 onValidDrop : function(dd, e, id){
52529 beforeInvalidDrop : function(e, id){
52534 * Ext JS Library 1.1.1
52535 * Copyright(c) 2006-2007, Ext JS, LLC.
52537 * Originally Released Under LGPL - original licence link has changed is not relivant.
52540 * <script type="text/javascript">
52545 * @class Roo.grid.ColumnModel
52546 * @extends Roo.util.Observable
52547 * This is the default implementation of a ColumnModel used by the Grid. It defines
52548 * the columns in the grid.
52551 var colModel = new Roo.grid.ColumnModel([
52552 {header: "Ticker", width: 60, sortable: true, locked: true},
52553 {header: "Company Name", width: 150, sortable: true},
52554 {header: "Market Cap.", width: 100, sortable: true},
52555 {header: "$ Sales", width: 100, sortable: true, renderer: money},
52556 {header: "Employees", width: 100, sortable: true, resizable: false}
52561 * The config options listed for this class are options which may appear in each
52562 * individual column definition.
52563 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
52565 * @param {Object} config An Array of column config objects. See this class's
52566 * config objects for details.
52568 Roo.grid.ColumnModel = function(config){
52570 * The config passed into the constructor
52572 this.config = config;
52575 // if no id, create one
52576 // if the column does not have a dataIndex mapping,
52577 // map it to the order it is in the config
52578 for(var i = 0, len = config.length; i < len; i++){
52580 if(typeof c.dataIndex == "undefined"){
52583 if(typeof c.renderer == "string"){
52584 c.renderer = Roo.util.Format[c.renderer];
52586 if(typeof c.id == "undefined"){
52589 if(c.editor && c.editor.xtype){
52590 c.editor = Roo.factory(c.editor, Roo.grid);
52592 if(c.editor && c.editor.isFormField){
52593 c.editor = new Roo.grid.GridEditor(c.editor);
52595 this.lookup[c.id] = c;
52599 * The width of columns which have no width specified (defaults to 100)
52602 this.defaultWidth = 100;
52605 * Default sortable of columns which have no sortable specified (defaults to false)
52608 this.defaultSortable = false;
52612 * @event widthchange
52613 * Fires when the width of a column changes.
52614 * @param {ColumnModel} this
52615 * @param {Number} columnIndex The column index
52616 * @param {Number} newWidth The new width
52618 "widthchange": true,
52620 * @event headerchange
52621 * Fires when the text of a header changes.
52622 * @param {ColumnModel} this
52623 * @param {Number} columnIndex The column index
52624 * @param {Number} newText The new header text
52626 "headerchange": true,
52628 * @event hiddenchange
52629 * Fires when a column is hidden or "unhidden".
52630 * @param {ColumnModel} this
52631 * @param {Number} columnIndex The column index
52632 * @param {Boolean} hidden true if hidden, false otherwise
52634 "hiddenchange": true,
52636 * @event columnmoved
52637 * Fires when a column is moved.
52638 * @param {ColumnModel} this
52639 * @param {Number} oldIndex
52640 * @param {Number} newIndex
52642 "columnmoved" : true,
52644 * @event columlockchange
52645 * Fires when a column's locked state is changed
52646 * @param {ColumnModel} this
52647 * @param {Number} colIndex
52648 * @param {Boolean} locked true if locked
52650 "columnlockchange" : true
52652 Roo.grid.ColumnModel.superclass.constructor.call(this);
52654 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
52656 * @cfg {String} header The header text to display in the Grid view.
52659 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
52660 * {@link Roo.data.Record} definition from which to draw the column's value. If not
52661 * specified, the column's index is used as an index into the Record's data Array.
52664 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
52665 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
52668 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
52669 * Defaults to the value of the {@link #defaultSortable} property.
52670 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
52673 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
52676 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
52679 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
52682 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
52685 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
52686 * given the cell's data value. See {@link #setRenderer}. If not specified, the
52687 * default renderer uses the raw data value.
52690 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
52693 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
52697 * Returns the id of the column at the specified index.
52698 * @param {Number} index The column index
52699 * @return {String} the id
52701 getColumnId : function(index){
52702 return this.config[index].id;
52706 * Returns the column for a specified id.
52707 * @param {String} id The column id
52708 * @return {Object} the column
52710 getColumnById : function(id){
52711 return this.lookup[id];
52716 * Returns the column for a specified dataIndex.
52717 * @param {String} dataIndex The column dataIndex
52718 * @return {Object|Boolean} the column or false if not found
52720 getColumnByDataIndex: function(dataIndex){
52721 var index = this.findColumnIndex(dataIndex);
52722 return index > -1 ? this.config[index] : false;
52726 * Returns the index for a specified column id.
52727 * @param {String} id The column id
52728 * @return {Number} the index, or -1 if not found
52730 getIndexById : function(id){
52731 for(var i = 0, len = this.config.length; i < len; i++){
52732 if(this.config[i].id == id){
52740 * Returns the index for a specified column dataIndex.
52741 * @param {String} dataIndex The column dataIndex
52742 * @return {Number} the index, or -1 if not found
52745 findColumnIndex : function(dataIndex){
52746 for(var i = 0, len = this.config.length; i < len; i++){
52747 if(this.config[i].dataIndex == dataIndex){
52755 moveColumn : function(oldIndex, newIndex){
52756 var c = this.config[oldIndex];
52757 this.config.splice(oldIndex, 1);
52758 this.config.splice(newIndex, 0, c);
52759 this.dataMap = null;
52760 this.fireEvent("columnmoved", this, oldIndex, newIndex);
52763 isLocked : function(colIndex){
52764 return this.config[colIndex].locked === true;
52767 setLocked : function(colIndex, value, suppressEvent){
52768 if(this.isLocked(colIndex) == value){
52771 this.config[colIndex].locked = value;
52772 if(!suppressEvent){
52773 this.fireEvent("columnlockchange", this, colIndex, value);
52777 getTotalLockedWidth : function(){
52778 var totalWidth = 0;
52779 for(var i = 0; i < this.config.length; i++){
52780 if(this.isLocked(i) && !this.isHidden(i)){
52781 this.totalWidth += this.getColumnWidth(i);
52787 getLockedCount : function(){
52788 for(var i = 0, len = this.config.length; i < len; i++){
52789 if(!this.isLocked(i)){
52796 * Returns the number of columns.
52799 getColumnCount : function(visibleOnly){
52800 if(visibleOnly === true){
52802 for(var i = 0, len = this.config.length; i < len; i++){
52803 if(!this.isHidden(i)){
52809 return this.config.length;
52813 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
52814 * @param {Function} fn
52815 * @param {Object} scope (optional)
52816 * @return {Array} result
52818 getColumnsBy : function(fn, scope){
52820 for(var i = 0, len = this.config.length; i < len; i++){
52821 var c = this.config[i];
52822 if(fn.call(scope||this, c, i) === true){
52830 * Returns true if the specified column is sortable.
52831 * @param {Number} col The column index
52832 * @return {Boolean}
52834 isSortable : function(col){
52835 if(typeof this.config[col].sortable == "undefined"){
52836 return this.defaultSortable;
52838 return this.config[col].sortable;
52842 * Returns the rendering (formatting) function defined for the column.
52843 * @param {Number} col The column index.
52844 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
52846 getRenderer : function(col){
52847 if(!this.config[col].renderer){
52848 return Roo.grid.ColumnModel.defaultRenderer;
52850 return this.config[col].renderer;
52854 * Sets the rendering (formatting) function for a column.
52855 * @param {Number} col The column index
52856 * @param {Function} fn The function to use to process the cell's raw data
52857 * to return HTML markup for the grid view. The render function is called with
52858 * the following parameters:<ul>
52859 * <li>Data value.</li>
52860 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
52861 * <li>css A CSS style string to apply to the table cell.</li>
52862 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
52863 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
52864 * <li>Row index</li>
52865 * <li>Column index</li>
52866 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
52868 setRenderer : function(col, fn){
52869 this.config[col].renderer = fn;
52873 * Returns the width for the specified column.
52874 * @param {Number} col The column index
52877 getColumnWidth : function(col){
52878 return this.config[col].width * 1 || this.defaultWidth;
52882 * Sets the width for a column.
52883 * @param {Number} col The column index
52884 * @param {Number} width The new width
52886 setColumnWidth : function(col, width, suppressEvent){
52887 this.config[col].width = width;
52888 this.totalWidth = null;
52889 if(!suppressEvent){
52890 this.fireEvent("widthchange", this, col, width);
52895 * Returns the total width of all columns.
52896 * @param {Boolean} includeHidden True to include hidden column widths
52899 getTotalWidth : function(includeHidden){
52900 if(!this.totalWidth){
52901 this.totalWidth = 0;
52902 for(var i = 0, len = this.config.length; i < len; i++){
52903 if(includeHidden || !this.isHidden(i)){
52904 this.totalWidth += this.getColumnWidth(i);
52908 return this.totalWidth;
52912 * Returns the header for the specified column.
52913 * @param {Number} col The column index
52916 getColumnHeader : function(col){
52917 return this.config[col].header;
52921 * Sets the header for a column.
52922 * @param {Number} col The column index
52923 * @param {String} header The new header
52925 setColumnHeader : function(col, header){
52926 this.config[col].header = header;
52927 this.fireEvent("headerchange", this, col, header);
52931 * Returns the tooltip for the specified column.
52932 * @param {Number} col The column index
52935 getColumnTooltip : function(col){
52936 return this.config[col].tooltip;
52939 * Sets the tooltip for a column.
52940 * @param {Number} col The column index
52941 * @param {String} tooltip The new tooltip
52943 setColumnTooltip : function(col, tooltip){
52944 this.config[col].tooltip = tooltip;
52948 * Returns the dataIndex for the specified column.
52949 * @param {Number} col The column index
52952 getDataIndex : function(col){
52953 return this.config[col].dataIndex;
52957 * Sets the dataIndex for a column.
52958 * @param {Number} col The column index
52959 * @param {Number} dataIndex The new dataIndex
52961 setDataIndex : function(col, dataIndex){
52962 this.config[col].dataIndex = dataIndex;
52968 * Returns true if the cell is editable.
52969 * @param {Number} colIndex The column index
52970 * @param {Number} rowIndex The row index
52971 * @return {Boolean}
52973 isCellEditable : function(colIndex, rowIndex){
52974 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
52978 * Returns the editor defined for the cell/column.
52979 * return false or null to disable editing.
52980 * @param {Number} colIndex The column index
52981 * @param {Number} rowIndex The row index
52984 getCellEditor : function(colIndex, rowIndex){
52985 return this.config[colIndex].editor;
52989 * Sets if a column is editable.
52990 * @param {Number} col The column index
52991 * @param {Boolean} editable True if the column is editable
52993 setEditable : function(col, editable){
52994 this.config[col].editable = editable;
52999 * Returns true if the column is hidden.
53000 * @param {Number} colIndex The column index
53001 * @return {Boolean}
53003 isHidden : function(colIndex){
53004 return this.config[colIndex].hidden;
53009 * Returns true if the column width cannot be changed
53011 isFixed : function(colIndex){
53012 return this.config[colIndex].fixed;
53016 * Returns true if the column can be resized
53017 * @return {Boolean}
53019 isResizable : function(colIndex){
53020 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
53023 * Sets if a column is hidden.
53024 * @param {Number} colIndex The column index
53025 * @param {Boolean} hidden True if the column is hidden
53027 setHidden : function(colIndex, hidden){
53028 this.config[colIndex].hidden = hidden;
53029 this.totalWidth = null;
53030 this.fireEvent("hiddenchange", this, colIndex, hidden);
53034 * Sets the editor for a column.
53035 * @param {Number} col The column index
53036 * @param {Object} editor The editor object
53038 setEditor : function(col, editor){
53039 this.config[col].editor = editor;
53043 Roo.grid.ColumnModel.defaultRenderer = function(value){
53044 if(typeof value == "string" && value.length < 1){
53050 // Alias for backwards compatibility
53051 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
53054 * Ext JS Library 1.1.1
53055 * Copyright(c) 2006-2007, Ext JS, LLC.
53057 * Originally Released Under LGPL - original licence link has changed is not relivant.
53060 * <script type="text/javascript">
53064 * @class Roo.grid.AbstractSelectionModel
53065 * @extends Roo.util.Observable
53066 * Abstract base class for grid SelectionModels. It provides the interface that should be
53067 * implemented by descendant classes. This class should not be directly instantiated.
53070 Roo.grid.AbstractSelectionModel = function(){
53071 this.locked = false;
53072 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
53075 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
53076 /** @ignore Called by the grid automatically. Do not call directly. */
53077 init : function(grid){
53083 * Locks the selections.
53086 this.locked = true;
53090 * Unlocks the selections.
53092 unlock : function(){
53093 this.locked = false;
53097 * Returns true if the selections are locked.
53098 * @return {Boolean}
53100 isLocked : function(){
53101 return this.locked;
53105 * Ext JS Library 1.1.1
53106 * Copyright(c) 2006-2007, Ext JS, LLC.
53108 * Originally Released Under LGPL - original licence link has changed is not relivant.
53111 * <script type="text/javascript">
53114 * @extends Roo.grid.AbstractSelectionModel
53115 * @class Roo.grid.RowSelectionModel
53116 * The default SelectionModel used by {@link Roo.grid.Grid}.
53117 * It supports multiple selections and keyboard selection/navigation.
53119 * @param {Object} config
53121 Roo.grid.RowSelectionModel = function(config){
53122 Roo.apply(this, config);
53123 this.selections = new Roo.util.MixedCollection(false, function(o){
53128 this.lastActive = false;
53132 * @event selectionchange
53133 * Fires when the selection changes
53134 * @param {SelectionModel} this
53136 "selectionchange" : true,
53138 * @event afterselectionchange
53139 * Fires after the selection changes (eg. by key press or clicking)
53140 * @param {SelectionModel} this
53142 "afterselectionchange" : true,
53144 * @event beforerowselect
53145 * Fires when a row is selected being selected, return false to cancel.
53146 * @param {SelectionModel} this
53147 * @param {Number} rowIndex The selected index
53148 * @param {Boolean} keepExisting False if other selections will be cleared
53150 "beforerowselect" : true,
53153 * Fires when a row is selected.
53154 * @param {SelectionModel} this
53155 * @param {Number} rowIndex The selected index
53156 * @param {Roo.data.Record} r The record
53158 "rowselect" : true,
53160 * @event rowdeselect
53161 * Fires when a row is deselected.
53162 * @param {SelectionModel} this
53163 * @param {Number} rowIndex The selected index
53165 "rowdeselect" : true
53167 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
53168 this.locked = false;
53171 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
53173 * @cfg {Boolean} singleSelect
53174 * True to allow selection of only one row at a time (defaults to false)
53176 singleSelect : false,
53179 initEvents : function(){
53181 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
53182 this.grid.on("mousedown", this.handleMouseDown, this);
53183 }else{ // allow click to work like normal
53184 this.grid.on("rowclick", this.handleDragableRowClick, this);
53187 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
53188 "up" : function(e){
53190 this.selectPrevious(e.shiftKey);
53191 }else if(this.last !== false && this.lastActive !== false){
53192 var last = this.last;
53193 this.selectRange(this.last, this.lastActive-1);
53194 this.grid.getView().focusRow(this.lastActive);
53195 if(last !== false){
53199 this.selectFirstRow();
53201 this.fireEvent("afterselectionchange", this);
53203 "down" : function(e){
53205 this.selectNext(e.shiftKey);
53206 }else if(this.last !== false && this.lastActive !== false){
53207 var last = this.last;
53208 this.selectRange(this.last, this.lastActive+1);
53209 this.grid.getView().focusRow(this.lastActive);
53210 if(last !== false){
53214 this.selectFirstRow();
53216 this.fireEvent("afterselectionchange", this);
53221 var view = this.grid.view;
53222 view.on("refresh", this.onRefresh, this);
53223 view.on("rowupdated", this.onRowUpdated, this);
53224 view.on("rowremoved", this.onRemove, this);
53228 onRefresh : function(){
53229 var ds = this.grid.dataSource, i, v = this.grid.view;
53230 var s = this.selections;
53231 s.each(function(r){
53232 if((i = ds.indexOfId(r.id)) != -1){
53241 onRemove : function(v, index, r){
53242 this.selections.remove(r);
53246 onRowUpdated : function(v, index, r){
53247 if(this.isSelected(r)){
53248 v.onRowSelect(index);
53254 * @param {Array} records The records to select
53255 * @param {Boolean} keepExisting (optional) True to keep existing selections
53257 selectRecords : function(records, keepExisting){
53259 this.clearSelections();
53261 var ds = this.grid.dataSource;
53262 for(var i = 0, len = records.length; i < len; i++){
53263 this.selectRow(ds.indexOf(records[i]), true);
53268 * Gets the number of selected rows.
53271 getCount : function(){
53272 return this.selections.length;
53276 * Selects the first row in the grid.
53278 selectFirstRow : function(){
53283 * Select the last row.
53284 * @param {Boolean} keepExisting (optional) True to keep existing selections
53286 selectLastRow : function(keepExisting){
53287 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
53291 * Selects the row immediately following the last selected row.
53292 * @param {Boolean} keepExisting (optional) True to keep existing selections
53294 selectNext : function(keepExisting){
53295 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
53296 this.selectRow(this.last+1, keepExisting);
53297 this.grid.getView().focusRow(this.last);
53302 * Selects the row that precedes the last selected row.
53303 * @param {Boolean} keepExisting (optional) True to keep existing selections
53305 selectPrevious : function(keepExisting){
53307 this.selectRow(this.last-1, keepExisting);
53308 this.grid.getView().focusRow(this.last);
53313 * Returns the selected records
53314 * @return {Array} Array of selected records
53316 getSelections : function(){
53317 return [].concat(this.selections.items);
53321 * Returns the first selected record.
53324 getSelected : function(){
53325 return this.selections.itemAt(0);
53330 * Clears all selections.
53332 clearSelections : function(fast){
53333 if(this.locked) return;
53335 var ds = this.grid.dataSource;
53336 var s = this.selections;
53337 s.each(function(r){
53338 this.deselectRow(ds.indexOfId(r.id));
53342 this.selections.clear();
53349 * Selects all rows.
53351 selectAll : function(){
53352 if(this.locked) return;
53353 this.selections.clear();
53354 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
53355 this.selectRow(i, true);
53360 * Returns True if there is a selection.
53361 * @return {Boolean}
53363 hasSelection : function(){
53364 return this.selections.length > 0;
53368 * Returns True if the specified row is selected.
53369 * @param {Number/Record} record The record or index of the record to check
53370 * @return {Boolean}
53372 isSelected : function(index){
53373 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
53374 return (r && this.selections.key(r.id) ? true : false);
53378 * Returns True if the specified record id is selected.
53379 * @param {String} id The id of record to check
53380 * @return {Boolean}
53382 isIdSelected : function(id){
53383 return (this.selections.key(id) ? true : false);
53387 handleMouseDown : function(e, t){
53388 var view = this.grid.getView(), rowIndex;
53389 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
53392 if(e.shiftKey && this.last !== false){
53393 var last = this.last;
53394 this.selectRange(last, rowIndex, e.ctrlKey);
53395 this.last = last; // reset the last
53396 view.focusRow(rowIndex);
53398 var isSelected = this.isSelected(rowIndex);
53399 if(e.button !== 0 && isSelected){
53400 view.focusRow(rowIndex);
53401 }else if(e.ctrlKey && isSelected){
53402 this.deselectRow(rowIndex);
53403 }else if(!isSelected){
53404 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
53405 view.focusRow(rowIndex);
53408 this.fireEvent("afterselectionchange", this);
53411 handleDragableRowClick : function(grid, rowIndex, e)
53413 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
53414 this.selectRow(rowIndex, false);
53415 grid.view.focusRow(rowIndex);
53416 this.fireEvent("afterselectionchange", this);
53421 * Selects multiple rows.
53422 * @param {Array} rows Array of the indexes of the row to select
53423 * @param {Boolean} keepExisting (optional) True to keep existing selections
53425 selectRows : function(rows, keepExisting){
53427 this.clearSelections();
53429 for(var i = 0, len = rows.length; i < len; i++){
53430 this.selectRow(rows[i], true);
53435 * Selects a range of rows. All rows in between startRow and endRow are also selected.
53436 * @param {Number} startRow The index of the first row in the range
53437 * @param {Number} endRow The index of the last row in the range
53438 * @param {Boolean} keepExisting (optional) True to retain existing selections
53440 selectRange : function(startRow, endRow, keepExisting){
53441 if(this.locked) return;
53443 this.clearSelections();
53445 if(startRow <= endRow){
53446 for(var i = startRow; i <= endRow; i++){
53447 this.selectRow(i, true);
53450 for(var i = startRow; i >= endRow; i--){
53451 this.selectRow(i, true);
53457 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
53458 * @param {Number} startRow The index of the first row in the range
53459 * @param {Number} endRow The index of the last row in the range
53461 deselectRange : function(startRow, endRow, preventViewNotify){
53462 if(this.locked) return;
53463 for(var i = startRow; i <= endRow; i++){
53464 this.deselectRow(i, preventViewNotify);
53470 * @param {Number} row The index of the row to select
53471 * @param {Boolean} keepExisting (optional) True to keep existing selections
53473 selectRow : function(index, keepExisting, preventViewNotify){
53474 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
53475 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
53476 if(!keepExisting || this.singleSelect){
53477 this.clearSelections();
53479 var r = this.grid.dataSource.getAt(index);
53480 this.selections.add(r);
53481 this.last = this.lastActive = index;
53482 if(!preventViewNotify){
53483 this.grid.getView().onRowSelect(index);
53485 this.fireEvent("rowselect", this, index, r);
53486 this.fireEvent("selectionchange", this);
53492 * @param {Number} row The index of the row to deselect
53494 deselectRow : function(index, preventViewNotify){
53495 if(this.locked) return;
53496 if(this.last == index){
53499 if(this.lastActive == index){
53500 this.lastActive = false;
53502 var r = this.grid.dataSource.getAt(index);
53503 this.selections.remove(r);
53504 if(!preventViewNotify){
53505 this.grid.getView().onRowDeselect(index);
53507 this.fireEvent("rowdeselect", this, index);
53508 this.fireEvent("selectionchange", this);
53512 restoreLast : function(){
53514 this.last = this._last;
53519 acceptsNav : function(row, col, cm){
53520 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53524 onEditorKey : function(field, e){
53525 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
53530 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53532 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53534 }else if(k == e.ENTER && !e.ctrlKey){
53538 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
53540 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
53542 }else if(k == e.ESC){
53546 g.startEditing(newCell[0], newCell[1]);
53551 * Ext JS Library 1.1.1
53552 * Copyright(c) 2006-2007, Ext JS, LLC.
53554 * Originally Released Under LGPL - original licence link has changed is not relivant.
53557 * <script type="text/javascript">
53560 * @class Roo.grid.CellSelectionModel
53561 * @extends Roo.grid.AbstractSelectionModel
53562 * This class provides the basic implementation for cell selection in a grid.
53564 * @param {Object} config The object containing the configuration of this model.
53565 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
53567 Roo.grid.CellSelectionModel = function(config){
53568 Roo.apply(this, config);
53570 this.selection = null;
53574 * @event beforerowselect
53575 * Fires before a cell is selected.
53576 * @param {SelectionModel} this
53577 * @param {Number} rowIndex The selected row index
53578 * @param {Number} colIndex The selected cell index
53580 "beforecellselect" : true,
53582 * @event cellselect
53583 * Fires when a cell is selected.
53584 * @param {SelectionModel} this
53585 * @param {Number} rowIndex The selected row index
53586 * @param {Number} colIndex The selected cell index
53588 "cellselect" : true,
53590 * @event selectionchange
53591 * Fires when the active selection changes.
53592 * @param {SelectionModel} this
53593 * @param {Object} selection null for no selection or an object (o) with two properties
53595 <li>o.record: the record object for the row the selection is in</li>
53596 <li>o.cell: An array of [rowIndex, columnIndex]</li>
53599 "selectionchange" : true,
53602 * Fires when the tab (or enter) was pressed on the last editable cell
53603 * You can use this to trigger add new row.
53604 * @param {SelectionModel} this
53608 * @event beforeeditnext
53609 * Fires before the next editable sell is made active
53610 * You can use this to skip to another cell or fire the tabend
53611 * if you set cell to false
53612 * @param {Object} eventdata object : { cell : [ row, col ] }
53614 "beforeeditnext" : true
53616 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
53619 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
53621 enter_is_tab: false,
53624 initEvents : function(){
53625 this.grid.on("mousedown", this.handleMouseDown, this);
53626 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
53627 var view = this.grid.view;
53628 view.on("refresh", this.onViewChange, this);
53629 view.on("rowupdated", this.onRowUpdated, this);
53630 view.on("beforerowremoved", this.clearSelections, this);
53631 view.on("beforerowsinserted", this.clearSelections, this);
53632 if(this.grid.isEditor){
53633 this.grid.on("beforeedit", this.beforeEdit, this);
53638 beforeEdit : function(e){
53639 this.select(e.row, e.column, false, true, e.record);
53643 onRowUpdated : function(v, index, r){
53644 if(this.selection && this.selection.record == r){
53645 v.onCellSelect(index, this.selection.cell[1]);
53650 onViewChange : function(){
53651 this.clearSelections(true);
53655 * Returns the currently selected cell,.
53656 * @return {Array} The selected cell (row, column) or null if none selected.
53658 getSelectedCell : function(){
53659 return this.selection ? this.selection.cell : null;
53663 * Clears all selections.
53664 * @param {Boolean} true to prevent the gridview from being notified about the change.
53666 clearSelections : function(preventNotify){
53667 var s = this.selection;
53669 if(preventNotify !== true){
53670 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
53672 this.selection = null;
53673 this.fireEvent("selectionchange", this, null);
53678 * Returns true if there is a selection.
53679 * @return {Boolean}
53681 hasSelection : function(){
53682 return this.selection ? true : false;
53686 handleMouseDown : function(e, t){
53687 var v = this.grid.getView();
53688 if(this.isLocked()){
53691 var row = v.findRowIndex(t);
53692 var cell = v.findCellIndex(t);
53693 if(row !== false && cell !== false){
53694 this.select(row, cell);
53700 * @param {Number} rowIndex
53701 * @param {Number} collIndex
53703 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
53704 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
53705 this.clearSelections();
53706 r = r || this.grid.dataSource.getAt(rowIndex);
53709 cell : [rowIndex, colIndex]
53711 if(!preventViewNotify){
53712 var v = this.grid.getView();
53713 v.onCellSelect(rowIndex, colIndex);
53714 if(preventFocus !== true){
53715 v.focusCell(rowIndex, colIndex);
53718 this.fireEvent("cellselect", this, rowIndex, colIndex);
53719 this.fireEvent("selectionchange", this, this.selection);
53724 isSelectable : function(rowIndex, colIndex, cm){
53725 return !cm.isHidden(colIndex);
53729 handleKeyDown : function(e){
53730 //Roo.log('Cell Sel Model handleKeyDown');
53731 if(!e.isNavKeyPress()){
53734 var g = this.grid, s = this.selection;
53737 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
53739 this.select(cell[0], cell[1]);
53744 var walk = function(row, col, step){
53745 return g.walkCells(row, col, step, sm.isSelectable, sm);
53747 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
53754 // handled by onEditorKey
53755 if (g.isEditor && g.editing) {
53759 newCell = walk(r, c-1, -1);
53761 newCell = walk(r, c+1, 1);
53766 newCell = walk(r+1, c, 1);
53770 newCell = walk(r-1, c, -1);
53774 newCell = walk(r, c+1, 1);
53778 newCell = walk(r, c-1, -1);
53783 if(g.isEditor && !g.editing){
53784 g.startEditing(r, c);
53793 this.select(newCell[0], newCell[1]);
53799 acceptsNav : function(row, col, cm){
53800 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53804 * @param {Number} field (not used) - as it's normally used as a listener
53805 * @param {Number} e - event - fake it by using
53807 * var e = Roo.EventObjectImpl.prototype;
53808 * e.keyCode = e.TAB
53812 onEditorKey : function(field, e){
53814 var k = e.getKey(),
53817 ed = g.activeEditor,
53819 ///Roo.log('onEditorKey' + k);
53822 if (this.enter_is_tab && k == e.ENTER) {
53828 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53830 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53836 } else if(k == e.ENTER && !e.ctrlKey){
53839 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53841 } else if(k == e.ESC){
53846 var ecall = { cell : newCell, forward : forward };
53847 this.fireEvent('beforeeditnext', ecall );
53848 newCell = ecall.cell;
53849 forward = ecall.forward;
53853 //Roo.log('next cell after edit');
53854 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
53855 } else if (forward) {
53856 // tabbed past last
53857 this.fireEvent.defer(100, this, ['tabend',this]);
53862 * Ext JS Library 1.1.1
53863 * Copyright(c) 2006-2007, Ext JS, LLC.
53865 * Originally Released Under LGPL - original licence link has changed is not relivant.
53868 * <script type="text/javascript">
53872 * @class Roo.grid.EditorGrid
53873 * @extends Roo.grid.Grid
53874 * Class for creating and editable grid.
53875 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53876 * The container MUST have some type of size defined for the grid to fill. The container will be
53877 * automatically set to position relative if it isn't already.
53878 * @param {Object} dataSource The data model to bind to
53879 * @param {Object} colModel The column model with info about this grid's columns
53881 Roo.grid.EditorGrid = function(container, config){
53882 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
53883 this.getGridEl().addClass("xedit-grid");
53885 if(!this.selModel){
53886 this.selModel = new Roo.grid.CellSelectionModel();
53889 this.activeEditor = null;
53893 * @event beforeedit
53894 * Fires before cell editing is triggered. The edit event object has the following properties <br />
53895 * <ul style="padding:5px;padding-left:16px;">
53896 * <li>grid - This grid</li>
53897 * <li>record - The record being edited</li>
53898 * <li>field - The field name being edited</li>
53899 * <li>value - The value for the field being edited.</li>
53900 * <li>row - The grid row index</li>
53901 * <li>column - The grid column index</li>
53902 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53904 * @param {Object} e An edit event (see above for description)
53906 "beforeedit" : true,
53909 * Fires after a cell is edited. <br />
53910 * <ul style="padding:5px;padding-left:16px;">
53911 * <li>grid - This grid</li>
53912 * <li>record - The record being edited</li>
53913 * <li>field - The field name being edited</li>
53914 * <li>value - The value being set</li>
53915 * <li>originalValue - The original value for the field, before the edit.</li>
53916 * <li>row - The grid row index</li>
53917 * <li>column - The grid column index</li>
53919 * @param {Object} e An edit event (see above for description)
53921 "afteredit" : true,
53923 * @event validateedit
53924 * Fires after a cell is edited, but before the value is set in the record.
53925 * You can use this to modify the value being set in the field, Return false
53926 * to cancel the change. The edit event object has the following properties <br />
53927 * <ul style="padding:5px;padding-left:16px;">
53928 * <li>editor - This editor</li>
53929 * <li>grid - This grid</li>
53930 * <li>record - The record being edited</li>
53931 * <li>field - The field name being edited</li>
53932 * <li>value - The value being set</li>
53933 * <li>originalValue - The original value for the field, before the edit.</li>
53934 * <li>row - The grid row index</li>
53935 * <li>column - The grid column index</li>
53936 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53938 * @param {Object} e An edit event (see above for description)
53940 "validateedit" : true
53942 this.on("bodyscroll", this.stopEditing, this);
53943 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
53946 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
53948 * @cfg {Number} clicksToEdit
53949 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
53956 trackMouseOver: false, // causes very odd FF errors
53958 onCellDblClick : function(g, row, col){
53959 this.startEditing(row, col);
53962 onEditComplete : function(ed, value, startValue){
53963 this.editing = false;
53964 this.activeEditor = null;
53965 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
53967 var field = this.colModel.getDataIndex(ed.col);
53972 originalValue: startValue,
53979 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
53982 if(String(value) !== String(startValue)){
53984 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
53985 r.set(field, e.value);
53986 // if we are dealing with a combo box..
53987 // then we also set the 'name' colum to be the displayField
53988 if (ed.field.displayField && ed.field.name) {
53989 r.set(ed.field.name, ed.field.el.dom.value);
53992 delete e.cancel; //?? why!!!
53993 this.fireEvent("afteredit", e);
53996 this.fireEvent("afteredit", e); // always fire it!
53998 this.view.focusCell(ed.row, ed.col);
54002 * Starts editing the specified for the specified row/column
54003 * @param {Number} rowIndex
54004 * @param {Number} colIndex
54006 startEditing : function(row, col){
54007 this.stopEditing();
54008 if(this.colModel.isCellEditable(col, row)){
54009 this.view.ensureVisible(row, col, true);
54011 var r = this.dataSource.getAt(row);
54012 var field = this.colModel.getDataIndex(col);
54013 var cell = Roo.get(this.view.getCell(row,col));
54018 value: r.data[field],
54023 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
54024 this.editing = true;
54025 var ed = this.colModel.getCellEditor(col, row);
54031 ed.render(ed.parentEl || document.body);
54037 (function(){ // complex but required for focus issues in safari, ie and opera
54041 ed.on("complete", this.onEditComplete, this, {single: true});
54042 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
54043 this.activeEditor = ed;
54044 var v = r.data[field];
54045 ed.startEdit(this.view.getCell(row, col), v);
54046 // combo's with 'displayField and name set
54047 if (ed.field.displayField && ed.field.name) {
54048 ed.field.el.dom.value = r.data[ed.field.name];
54052 }).defer(50, this);
54058 * Stops any active editing
54060 stopEditing : function(){
54061 if(this.activeEditor){
54062 this.activeEditor.completeEdit();
54064 this.activeEditor = null;
54068 * Called to get grid's drag proxy text, by default returns this.ddText.
54071 getDragDropText : function(){
54072 var count = this.selModel.getSelectedCell() ? 1 : 0;
54073 return String.format(this.ddText, count, count == 1 ? '' : 's');
54078 * Ext JS Library 1.1.1
54079 * Copyright(c) 2006-2007, Ext JS, LLC.
54081 * Originally Released Under LGPL - original licence link has changed is not relivant.
54084 * <script type="text/javascript">
54087 // private - not really -- you end up using it !
54088 // This is a support class used internally by the Grid components
54091 * @class Roo.grid.GridEditor
54092 * @extends Roo.Editor
54093 * Class for creating and editable grid elements.
54094 * @param {Object} config any settings (must include field)
54096 Roo.grid.GridEditor = function(field, config){
54097 if (!config && field.field) {
54099 field = Roo.factory(config.field, Roo.form);
54101 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
54102 field.monitorTab = false;
54105 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
54108 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
54111 alignment: "tl-tl",
54114 cls: "x-small-editor x-grid-editor",
54119 * Ext JS Library 1.1.1
54120 * Copyright(c) 2006-2007, Ext JS, LLC.
54122 * Originally Released Under LGPL - original licence link has changed is not relivant.
54125 * <script type="text/javascript">
54130 Roo.grid.PropertyRecord = Roo.data.Record.create([
54131 {name:'name',type:'string'}, 'value'
54135 Roo.grid.PropertyStore = function(grid, source){
54137 this.store = new Roo.data.Store({
54138 recordType : Roo.grid.PropertyRecord
54140 this.store.on('update', this.onUpdate, this);
54142 this.setSource(source);
54144 Roo.grid.PropertyStore.superclass.constructor.call(this);
54149 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
54150 setSource : function(o){
54152 this.store.removeAll();
54155 if(this.isEditableValue(o[k])){
54156 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
54159 this.store.loadRecords({records: data}, {}, true);
54162 onUpdate : function(ds, record, type){
54163 if(type == Roo.data.Record.EDIT){
54164 var v = record.data['value'];
54165 var oldValue = record.modified['value'];
54166 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
54167 this.source[record.id] = v;
54169 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
54176 getProperty : function(row){
54177 return this.store.getAt(row);
54180 isEditableValue: function(val){
54181 if(val && val instanceof Date){
54183 }else if(typeof val == 'object' || typeof val == 'function'){
54189 setValue : function(prop, value){
54190 this.source[prop] = value;
54191 this.store.getById(prop).set('value', value);
54194 getSource : function(){
54195 return this.source;
54199 Roo.grid.PropertyColumnModel = function(grid, store){
54202 g.PropertyColumnModel.superclass.constructor.call(this, [
54203 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
54204 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
54206 this.store = store;
54207 this.bselect = Roo.DomHelper.append(document.body, {
54208 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
54209 {tag: 'option', value: 'true', html: 'true'},
54210 {tag: 'option', value: 'false', html: 'false'}
54213 Roo.id(this.bselect);
54216 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
54217 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
54218 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
54219 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
54220 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
54222 this.renderCellDelegate = this.renderCell.createDelegate(this);
54223 this.renderPropDelegate = this.renderProp.createDelegate(this);
54226 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
54230 valueText : 'Value',
54232 dateFormat : 'm/j/Y',
54235 renderDate : function(dateVal){
54236 return dateVal.dateFormat(this.dateFormat);
54239 renderBool : function(bVal){
54240 return bVal ? 'true' : 'false';
54243 isCellEditable : function(colIndex, rowIndex){
54244 return colIndex == 1;
54247 getRenderer : function(col){
54249 this.renderCellDelegate : this.renderPropDelegate;
54252 renderProp : function(v){
54253 return this.getPropertyName(v);
54256 renderCell : function(val){
54258 if(val instanceof Date){
54259 rv = this.renderDate(val);
54260 }else if(typeof val == 'boolean'){
54261 rv = this.renderBool(val);
54263 return Roo.util.Format.htmlEncode(rv);
54266 getPropertyName : function(name){
54267 var pn = this.grid.propertyNames;
54268 return pn && pn[name] ? pn[name] : name;
54271 getCellEditor : function(colIndex, rowIndex){
54272 var p = this.store.getProperty(rowIndex);
54273 var n = p.data['name'], val = p.data['value'];
54275 if(typeof(this.grid.customEditors[n]) == 'string'){
54276 return this.editors[this.grid.customEditors[n]];
54278 if(typeof(this.grid.customEditors[n]) != 'undefined'){
54279 return this.grid.customEditors[n];
54281 if(val instanceof Date){
54282 return this.editors['date'];
54283 }else if(typeof val == 'number'){
54284 return this.editors['number'];
54285 }else if(typeof val == 'boolean'){
54286 return this.editors['boolean'];
54288 return this.editors['string'];
54294 * @class Roo.grid.PropertyGrid
54295 * @extends Roo.grid.EditorGrid
54296 * This class represents the interface of a component based property grid control.
54297 * <br><br>Usage:<pre><code>
54298 var grid = new Roo.grid.PropertyGrid("my-container-id", {
54306 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54307 * The container MUST have some type of size defined for the grid to fill. The container will be
54308 * automatically set to position relative if it isn't already.
54309 * @param {Object} config A config object that sets properties on this grid.
54311 Roo.grid.PropertyGrid = function(container, config){
54312 config = config || {};
54313 var store = new Roo.grid.PropertyStore(this);
54314 this.store = store;
54315 var cm = new Roo.grid.PropertyColumnModel(this, store);
54316 store.store.sort('name', 'ASC');
54317 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
54320 enableColLock:false,
54321 enableColumnMove:false,
54323 trackMouseOver: false,
54326 this.getGridEl().addClass('x-props-grid');
54327 this.lastEditRow = null;
54328 this.on('columnresize', this.onColumnResize, this);
54331 * @event beforepropertychange
54332 * Fires before a property changes (return false to stop?)
54333 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
54334 * @param {String} id Record Id
54335 * @param {String} newval New Value
54336 * @param {String} oldval Old Value
54338 "beforepropertychange": true,
54340 * @event propertychange
54341 * Fires after a property changes
54342 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
54343 * @param {String} id Record Id
54344 * @param {String} newval New Value
54345 * @param {String} oldval Old Value
54347 "propertychange": true
54349 this.customEditors = this.customEditors || {};
54351 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
54354 * @cfg {Object} customEditors map of colnames=> custom editors.
54355 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
54356 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
54357 * false disables editing of the field.
54361 * @cfg {Object} propertyNames map of property Names to their displayed value
54364 render : function(){
54365 Roo.grid.PropertyGrid.superclass.render.call(this);
54366 this.autoSize.defer(100, this);
54369 autoSize : function(){
54370 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
54372 this.view.fitColumns();
54376 onColumnResize : function(){
54377 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
54381 * Sets the data for the Grid
54382 * accepts a Key => Value object of all the elements avaiable.
54383 * @param {Object} data to appear in grid.
54385 setSource : function(source){
54386 this.store.setSource(source);
54390 * Gets all the data from the grid.
54391 * @return {Object} data data stored in grid
54393 getSource : function(){
54394 return this.store.getSource();
54398 * Ext JS Library 1.1.1
54399 * Copyright(c) 2006-2007, Ext JS, LLC.
54401 * Originally Released Under LGPL - original licence link has changed is not relivant.
54404 * <script type="text/javascript">
54408 * @class Roo.LoadMask
54409 * A simple utility class for generically masking elements while loading data. If the element being masked has
54410 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
54411 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
54412 * element's UpdateManager load indicator and will be destroyed after the initial load.
54414 * Create a new LoadMask
54415 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
54416 * @param {Object} config The config object
54418 Roo.LoadMask = function(el, config){
54419 this.el = Roo.get(el);
54420 Roo.apply(this, config);
54422 this.store.on('beforeload', this.onBeforeLoad, this);
54423 this.store.on('load', this.onLoad, this);
54424 this.store.on('loadexception', this.onLoadException, this);
54425 this.removeMask = false;
54427 var um = this.el.getUpdateManager();
54428 um.showLoadIndicator = false; // disable the default indicator
54429 um.on('beforeupdate', this.onBeforeLoad, this);
54430 um.on('update', this.onLoad, this);
54431 um.on('failure', this.onLoad, this);
54432 this.removeMask = true;
54436 Roo.LoadMask.prototype = {
54438 * @cfg {Boolean} removeMask
54439 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
54440 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
54443 * @cfg {String} msg
54444 * The text to display in a centered loading message box (defaults to 'Loading...')
54446 msg : 'Loading...',
54448 * @cfg {String} msgCls
54449 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
54451 msgCls : 'x-mask-loading',
54454 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
54460 * Disables the mask to prevent it from being displayed
54462 disable : function(){
54463 this.disabled = true;
54467 * Enables the mask so that it can be displayed
54469 enable : function(){
54470 this.disabled = false;
54473 onLoadException : function()
54475 Roo.log(arguments);
54477 if (typeof(arguments[3]) != 'undefined') {
54478 Roo.MessageBox.alert("Error loading",arguments[3]);
54482 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
54483 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
54492 this.el.unmask(this.removeMask);
54495 onLoad : function()
54497 this.el.unmask(this.removeMask);
54501 onBeforeLoad : function(){
54502 if(!this.disabled){
54503 this.el.mask(this.msg, this.msgCls);
54508 destroy : function(){
54510 this.store.un('beforeload', this.onBeforeLoad, this);
54511 this.store.un('load', this.onLoad, this);
54512 this.store.un('loadexception', this.onLoadException, this);
54514 var um = this.el.getUpdateManager();
54515 um.un('beforeupdate', this.onBeforeLoad, this);
54516 um.un('update', this.onLoad, this);
54517 um.un('failure', this.onLoad, this);
54522 * Ext JS Library 1.1.1
54523 * Copyright(c) 2006-2007, Ext JS, LLC.
54525 * Originally Released Under LGPL - original licence link has changed is not relivant.
54528 * <script type="text/javascript">
54533 * @class Roo.XTemplate
54534 * @extends Roo.Template
54535 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
54537 var t = new Roo.XTemplate(
54538 '<select name="{name}">',
54539 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
54543 // then append, applying the master template values
54546 * Supported features:
54551 {a_variable} - output encoded.
54552 {a_variable.format:("Y-m-d")} - call a method on the variable
54553 {a_variable:raw} - unencoded output
54554 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
54555 {a_variable:this.method_on_template(...)} - call a method on the template object.
54560 <tpl for="a_variable or condition.."></tpl>
54561 <tpl if="a_variable or condition"></tpl>
54562 <tpl exec="some javascript"></tpl>
54563 <tpl name="named_template"></tpl> (experimental)
54565 <tpl for="."></tpl> - just iterate the property..
54566 <tpl for=".."></tpl> - iterates with the parent (probably the template)
54570 Roo.XTemplate = function()
54572 Roo.XTemplate.superclass.constructor.apply(this, arguments);
54579 Roo.extend(Roo.XTemplate, Roo.Template, {
54582 * The various sub templates
54587 * basic tag replacing syntax
54590 * // you can fake an object call by doing this
54594 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
54597 * compile the template
54599 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
54602 compile: function()
54606 s = ['<tpl>', s, '</tpl>'].join('');
54608 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
54609 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
54610 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
54611 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
54612 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
54617 while(true == !!(m = s.match(re))){
54618 var forMatch = m[0].match(nameRe),
54619 ifMatch = m[0].match(ifRe),
54620 execMatch = m[0].match(execRe),
54621 namedMatch = m[0].match(namedRe),
54626 name = forMatch && forMatch[1] ? forMatch[1] : '';
54629 // if - puts fn into test..
54630 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
54632 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
54637 // exec - calls a function... returns empty if true is returned.
54638 exp = execMatch && execMatch[1] ? execMatch[1] : null;
54640 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
54648 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
54649 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
54650 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
54653 var uid = namedMatch ? namedMatch[1] : id;
54657 id: namedMatch ? namedMatch[1] : id,
54664 s = s.replace(m[0], '');
54666 s = s.replace(m[0], '{xtpl'+ id + '}');
54671 for(var i = tpls.length-1; i >= 0; --i){
54672 this.compileTpl(tpls[i]);
54673 this.tpls[tpls[i].id] = tpls[i];
54675 this.master = tpls[tpls.length-1];
54679 * same as applyTemplate, except it's done to one of the subTemplates
54680 * when using named templates, you can do:
54682 * var str = pl.applySubTemplate('your-name', values);
54685 * @param {Number} id of the template
54686 * @param {Object} values to apply to template
54687 * @param {Object} parent (normaly the instance of this object)
54689 applySubTemplate : function(id, values, parent)
54693 var t = this.tpls[id];
54697 if(t.test && !t.test.call(this, values, parent)){
54701 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
54702 Roo.log(e.toString());
54708 if(t.exec && t.exec.call(this, values, parent)){
54712 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
54713 Roo.log(e.toString());
54718 var vs = t.target ? t.target.call(this, values, parent) : values;
54719 parent = t.target ? values : parent;
54720 if(t.target && vs instanceof Array){
54722 for(var i = 0, len = vs.length; i < len; i++){
54723 buf[buf.length] = t.compiled.call(this, vs[i], parent);
54725 return buf.join('');
54727 return t.compiled.call(this, vs, parent);
54729 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
54730 Roo.log(e.toString());
54731 Roo.log(t.compiled);
54736 compileTpl : function(tpl)
54738 var fm = Roo.util.Format;
54739 var useF = this.disableFormats !== true;
54740 var sep = Roo.isGecko ? "+" : ",";
54741 var undef = function(str) {
54742 Roo.log("Property not found :" + str);
54746 var fn = function(m, name, format, args)
54748 //Roo.log(arguments);
54749 args = args ? args.replace(/\\'/g,"'") : args;
54750 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
54751 if (typeof(format) == 'undefined') {
54752 format= 'htmlEncode';
54754 if (format == 'raw' ) {
54758 if(name.substr(0, 4) == 'xtpl'){
54759 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
54762 // build an array of options to determine if value is undefined..
54764 // basically get 'xxxx.yyyy' then do
54765 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
54766 // (function () { Roo.log("Property not found"); return ''; })() :
54771 Roo.each(name.split('.'), function(st) {
54772 lookfor += (lookfor.length ? '.': '') + st;
54773 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
54776 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
54779 if(format && useF){
54781 args = args ? ',' + args : "";
54783 if(format.substr(0, 5) != "this."){
54784 format = "fm." + format + '(';
54786 format = 'this.call("'+ format.substr(5) + '", ';
54790 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
54794 // called with xxyx.yuu:(test,test)
54796 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
54798 // raw.. - :raw modifier..
54799 return "'"+ sep + udef_st + name + ")"+sep+"'";
54803 // branched to use + in gecko and [].join() in others
54805 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
54806 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
54809 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
54810 body.push(tpl.body.replace(/(\r\n|\n)/g,
54811 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
54812 body.push("'].join('');};};");
54813 body = body.join('');
54816 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
54818 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
54824 applyTemplate : function(values){
54825 return this.master.compiled.call(this, values, {});
54826 //var s = this.subs;
54829 apply : function(){
54830 return this.applyTemplate.apply(this, arguments);
54835 Roo.XTemplate.from = function(el){
54836 el = Roo.getDom(el);
54837 return new Roo.XTemplate(el.value || el.innerHTML);
54839 * Original code for Roojs - LGPL
54840 * <script type="text/javascript">
54844 * @class Roo.XComponent
54845 * A delayed Element creator...
54846 * Or a way to group chunks of interface together.
54848 * Mypart.xyx = new Roo.XComponent({
54850 parent : 'Mypart.xyz', // empty == document.element.!!
54854 disabled : function() {}
54856 tree : function() { // return an tree of xtype declared components
54860 xtype : 'NestedLayoutPanel',
54867 * It can be used to build a big heiracy, with parent etc.
54868 * or you can just use this to render a single compoent to a dom element
54869 * MYPART.render(Roo.Element | String(id) | dom_element )
54871 * @extends Roo.util.Observable
54873 * @param cfg {Object} configuration of component
54876 Roo.XComponent = function(cfg) {
54877 Roo.apply(this, cfg);
54881 * Fires when this the componnt is built
54882 * @param {Roo.XComponent} c the component
54887 this.region = this.region || 'center'; // default..
54888 Roo.XComponent.register(this);
54889 this.modules = false;
54890 this.el = false; // where the layout goes..
54894 Roo.extend(Roo.XComponent, Roo.util.Observable, {
54897 * The created element (with Roo.factory())
54898 * @type {Roo.Layout}
54904 * for BC - use el in new code
54905 * @type {Roo.Layout}
54911 * for BC - use el in new code
54912 * @type {Roo.Layout}
54917 * @cfg {Function|boolean} disabled
54918 * If this module is disabled by some rule, return true from the funtion
54923 * @cfg {String} parent
54924 * Name of parent element which it get xtype added to..
54929 * @cfg {String} order
54930 * Used to set the order in which elements are created (usefull for multiple tabs)
54935 * @cfg {String} name
54936 * String to display while loading.
54940 * @cfg {String} region
54941 * Region to render component to (defaults to center)
54946 * @cfg {Array} items
54947 * A single item array - the first element is the root of the tree..
54948 * It's done this way to stay compatible with the Xtype system...
54954 * The method that retuns the tree of parts that make up this compoennt
54961 * render element to dom or tree
54962 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
54965 render : function(el)
54969 var hp = this.parent ? 1 : 0;
54971 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
54972 // if parent is a '#.....' string, then let's use that..
54973 var ename = this.parent.substr(1)
54974 this.parent = false;
54975 el = Roo.get(ename);
54977 Roo.log("Warning - element can not be found :#" + ename );
54983 if (!this.parent) {
54985 el = el ? Roo.get(el) : false;
54987 // it's a top level one..
54989 el : new Roo.BorderLayout(el || document.body, {
54995 tabPosition: 'top',
54996 //resizeTabs: true,
54997 alwaysShowTabs: el && hp? false : true,
54998 hideTabs: el || !hp ? true : false,
55005 if (!this.parent.el) {
55006 // probably an old style ctor, which has been disabled.
55010 // The 'tree' method is '_tree now'
55012 var tree = this._tree ? this._tree() : this.tree();
55013 tree.region = tree.region || this.region;
55014 this.el = this.parent.el.addxtype(tree);
55015 this.fireEvent('built', this);
55017 this.panel = this.el;
55018 this.layout = this.panel.layout;
55019 this.parentLayout = this.parent.layout || false;
55025 Roo.apply(Roo.XComponent, {
55027 * @property hideProgress
55028 * true to disable the building progress bar.. usefull on single page renders.
55031 hideProgress : false,
55033 * @property buildCompleted
55034 * True when the builder has completed building the interface.
55037 buildCompleted : false,
55040 * @property topModule
55041 * the upper most module - uses document.element as it's constructor.
55048 * @property modules
55049 * array of modules to be created by registration system.
55050 * @type {Array} of Roo.XComponent
55055 * @property elmodules
55056 * array of modules to be created by which use #ID
55057 * @type {Array} of Roo.XComponent
55064 * Register components to be built later.
55066 * This solves the following issues
55067 * - Building is not done on page load, but after an authentication process has occured.
55068 * - Interface elements are registered on page load
55069 * - Parent Interface elements may not be loaded before child, so this handles that..
55076 module : 'Pman.Tab.projectMgr',
55078 parent : 'Pman.layout',
55079 disabled : false, // or use a function..
55082 * * @param {Object} details about module
55084 register : function(obj) {
55086 Roo.XComponent.event.fireEvent('register', obj);
55087 switch(typeof(obj.disabled) ) {
55093 if ( obj.disabled() ) {
55099 if (obj.disabled) {
55105 this.modules.push(obj);
55109 * convert a string to an object..
55110 * eg. 'AAA.BBB' -> finds AAA.BBB
55114 toObject : function(str)
55116 if (!str || typeof(str) == 'object') {
55119 if (str.substring(0,1) == '#') {
55123 var ar = str.split('.');
55128 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
55130 throw "Module not found : " + str;
55134 throw "Module not found : " + str;
55136 Roo.each(ar, function(e) {
55137 if (typeof(o[e]) == 'undefined') {
55138 throw "Module not found : " + str;
55149 * move modules into their correct place in the tree..
55152 preBuild : function ()
55155 Roo.each(this.modules , function (obj)
55157 Roo.XComponent.event.fireEvent('beforebuild', obj);
55159 var opar = obj.parent;
55161 obj.parent = this.toObject(opar);
55163 Roo.log("parent:toObject failed: " + e.toString());
55168 Roo.debug && Roo.log("GOT top level module");
55169 Roo.debug && Roo.log(obj);
55170 obj.modules = new Roo.util.MixedCollection(false,
55171 function(o) { return o.order + '' }
55173 this.topModule = obj;
55176 // parent is a string (usually a dom element name..)
55177 if (typeof(obj.parent) == 'string') {
55178 this.elmodules.push(obj);
55181 if (obj.parent.constructor != Roo.XComponent) {
55182 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
55184 if (!obj.parent.modules) {
55185 obj.parent.modules = new Roo.util.MixedCollection(false,
55186 function(o) { return o.order + '' }
55189 if (obj.parent.disabled) {
55190 obj.disabled = true;
55192 obj.parent.modules.add(obj);
55197 * make a list of modules to build.
55198 * @return {Array} list of modules.
55201 buildOrder : function()
55204 var cmp = function(a,b) {
55205 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
55207 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
55208 throw "No top level modules to build";
55211 // make a flat list in order of modules to build.
55212 var mods = this.topModule ? [ this.topModule ] : [];
55215 // elmodules (is a list of DOM based modules )
55216 Roo.each(this.elmodules, function(e) {
55218 if (!this.topModule &&
55219 typeof(e.parent) == 'string' &&
55220 e.parent.substring(0,1) == '#' &&
55221 Roo.get(e.parent.substr(1))
55224 _this.topModule = e;
55230 // add modules to their parents..
55231 var addMod = function(m) {
55232 Roo.debug && Roo.log("build Order: add: " + m.name);
55235 if (m.modules && !m.disabled) {
55236 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
55237 m.modules.keySort('ASC', cmp );
55238 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
55240 m.modules.each(addMod);
55242 Roo.debug && Roo.log("build Order: no child modules");
55244 // not sure if this is used any more..
55246 m.finalize.name = m.name + " (clean up) ";
55247 mods.push(m.finalize);
55251 if (this.topModule && this.topModule.modules) {
55252 this.topModule.modules.keySort('ASC', cmp );
55253 this.topModule.modules.each(addMod);
55259 * Build the registered modules.
55260 * @param {Object} parent element.
55261 * @param {Function} optional method to call after module has been added.
55269 var mods = this.buildOrder();
55271 //this.allmods = mods;
55272 //Roo.debug && Roo.log(mods);
55274 if (!mods.length) { // should not happen
55275 throw "NO modules!!!";
55279 var msg = "Building Interface...";
55280 // flash it up as modal - so we store the mask!?
55281 if (!this.hideProgress) {
55282 Roo.MessageBox.show({ title: 'loading' });
55283 Roo.MessageBox.show({
55284 title: "Please wait...",
55293 var total = mods.length;
55296 var progressRun = function() {
55297 if (!mods.length) {
55298 Roo.debug && Roo.log('hide?');
55299 if (!this.hideProgress) {
55300 Roo.MessageBox.hide();
55302 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
55308 var m = mods.shift();
55311 Roo.debug && Roo.log(m);
55312 // not sure if this is supported any more.. - modules that are are just function
55313 if (typeof(m) == 'function') {
55315 return progressRun.defer(10, _this);
55319 msg = "Building Interface " + (total - mods.length) +
55321 (m.name ? (' - ' + m.name) : '');
55322 Roo.debug && Roo.log(msg);
55323 if (!this.hideProgress) {
55324 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
55328 // is the module disabled?
55329 var disabled = (typeof(m.disabled) == 'function') ?
55330 m.disabled.call(m.module.disabled) : m.disabled;
55334 return progressRun(); // we do not update the display!
55342 // it's 10 on top level, and 1 on others??? why...
55343 return progressRun.defer(10, _this);
55346 progressRun.defer(1, _this);
55360 * wrapper for event.on - aliased later..
55361 * Typically use to register a event handler for register:
55363 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
55372 Roo.XComponent.event = new Roo.util.Observable({
55376 * Fires when an Component is registered,
55377 * set the disable property on the Component to stop registration.
55378 * @param {Roo.XComponent} c the component being registerd.
55383 * @event beforebuild
55384 * Fires before each Component is built
55385 * can be used to apply permissions.
55386 * @param {Roo.XComponent} c the component being registerd.
55389 'beforebuild' : true,
55391 * @event buildcomplete
55392 * Fires on the top level element when all elements have been built
55393 * @param {Roo.XComponent} the top level component.
55395 'buildcomplete' : true
55400 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);