4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
620 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
621 * you may want to set this to true.
624 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
629 * Selects a single element as a Roo Element
630 * This is about as close as you can get to jQuery's $('do crazy stuff')
631 * @param {String} selector The selector/xpath query
632 * @param {Node} root (optional) The start of the query (defaults to document).
633 * @return {Roo.Element}
635 selectNode : function(selector, root)
637 var node = Roo.DomQuery.selectNode(selector,root);
638 return node ? Roo.get(node) : new Roo.Element(false);
646 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
647 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 * Ext JS Library 1.1.1
651 * Copyright(c) 2006-2007, Ext JS, LLC.
653 * Originally Released Under LGPL - original licence link has changed is not relivant.
656 * <script type="text/javascript">
660 // wrappedn so fnCleanup is not in global scope...
662 function fnCleanUp() {
663 var p = Function.prototype;
664 delete p.createSequence;
666 delete p.createDelegate;
667 delete p.createCallback;
668 delete p.createInterceptor;
670 window.detachEvent("onunload", fnCleanUp);
672 window.attachEvent("onunload", fnCleanUp);
679 * These functions are available on every Function object (any JavaScript function).
681 Roo.apply(Function.prototype, {
683 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
684 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
685 * Will create a function that is bound to those 2 args.
686 * @return {Function} The new function
688 createCallback : function(/*args...*/){
689 // make args available, in function below
690 var args = arguments;
693 return method.apply(window, args);
698 * Creates a delegate (callback) that sets the scope to obj.
699 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
700 * Will create a function that is automatically scoped to this.
701 * @param {Object} obj (optional) The object for which the scope is set
702 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
703 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
704 * if a number the args are inserted at the specified position
705 * @return {Function} The new function
707 createDelegate : function(obj, args, appendArgs){
710 var callArgs = args || arguments;
711 if(appendArgs === true){
712 callArgs = Array.prototype.slice.call(arguments, 0);
713 callArgs = callArgs.concat(args);
714 }else if(typeof appendArgs == "number"){
715 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
716 var applyArgs = [appendArgs, 0].concat(args); // create method call params
717 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
719 return method.apply(obj || window, callArgs);
724 * Calls this function after the number of millseconds specified.
725 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
726 * @param {Object} obj (optional) The object for which the scope is set
727 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
728 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
729 * if a number the args are inserted at the specified position
730 * @return {Number} The timeout id that can be used with clearTimeout
732 defer : function(millis, obj, args, appendArgs){
733 var fn = this.createDelegate(obj, args, appendArgs);
735 return setTimeout(fn, millis);
741 * Create a combined function call sequence of the original function + the passed function.
742 * The resulting function returns the results of the original function.
743 * The passed fcn is called with the parameters of the original function
744 * @param {Function} fcn The function to sequence
745 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
746 * @return {Function} The new function
748 createSequence : function(fcn, scope){
749 if(typeof fcn != "function"){
754 var retval = method.apply(this || window, arguments);
755 fcn.apply(scope || this || window, arguments);
761 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
762 * The resulting function returns the results of the original function.
763 * The passed fcn is called with the parameters of the original function.
765 * @param {Function} fcn The function to call before the original
766 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
767 * @return {Function} The new function
769 createInterceptor : function(fcn, scope){
770 if(typeof fcn != "function"){
777 if(fcn.apply(scope || this || window, arguments) === false){
780 return method.apply(this || window, arguments);
786 * Ext JS Library 1.1.1
787 * Copyright(c) 2006-2007, Ext JS, LLC.
789 * Originally Released Under LGPL - original licence link has changed is not relivant.
792 * <script type="text/javascript">
795 Roo.applyIf(String, {
800 * Escapes the passed string for ' and \
801 * @param {String} string The string to escape
802 * @return {String} The escaped string
805 escape : function(string) {
806 return string.replace(/('|\\)/g, "\\$1");
810 * Pads the left side of a string with a specified character. This is especially useful
811 * for normalizing number and date strings. Example usage:
813 var s = String.leftPad('123', 5, '0');
814 // s now contains the string: '00123'
816 * @param {String} string The original string
817 * @param {Number} size The total length of the output string
818 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
819 * @return {String} The padded string
822 leftPad : function (val, size, ch) {
823 var result = new String(val);
824 if(ch === null || ch === undefined || ch === '') {
827 while (result.length < size) {
828 result = ch + result;
834 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
835 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
837 var cls = 'my-class', text = 'Some text';
838 var s = String.format('<div class="{0}">{1}</div>', cls, text);
839 // s now contains the string: '<div class="my-class">Some text</div>'
841 * @param {String} string The tokenized string to be formatted
842 * @param {String} value1 The value to replace token {0}
843 * @param {String} value2 Etc...
844 * @return {String} The formatted string
847 format : function(format){
848 var args = Array.prototype.slice.call(arguments, 1);
849 return format.replace(/\{(\d+)\}/g, function(m, i){
850 return Roo.util.Format.htmlEncode(args[i]);
856 * Utility function that allows you to easily switch a string between two alternating values. The passed value
857 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
858 * they are already different, the first value passed in is returned. Note that this method returns the new value
859 * but does not change the current string.
861 // alternate sort directions
862 sort = sort.toggle('ASC', 'DESC');
864 // instead of conditional logic:
865 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
867 * @param {String} value The value to compare to the current string
868 * @param {String} other The new value to use if the string already equals the first value passed in
869 * @return {String} The new value
872 String.prototype.toggle = function(value, other){
873 return this == value ? other : value;
876 * Ext JS Library 1.1.1
877 * Copyright(c) 2006-2007, Ext JS, LLC.
879 * Originally Released Under LGPL - original licence link has changed is not relivant.
882 * <script type="text/javascript">
888 Roo.applyIf(Number.prototype, {
890 * Checks whether or not the current number is within a desired range. If the number is already within the
891 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
892 * exceeded. Note that this method returns the constrained value but does not change the current number.
893 * @param {Number} min The minimum number in the range
894 * @param {Number} max The maximum number in the range
895 * @return {Number} The constrained value if outside the range, otherwise the current value
897 constrain : function(min, max){
898 return Math.min(Math.max(this, min), max);
902 * Ext JS Library 1.1.1
903 * Copyright(c) 2006-2007, Ext JS, LLC.
905 * Originally Released Under LGPL - original licence link has changed is not relivant.
908 * <script type="text/javascript">
913 Roo.applyIf(Array.prototype, {
915 * Checks whether or not the specified object exists in the array.
916 * @param {Object} o The object to check for
917 * @return {Number} The index of o in the array (or -1 if it is not found)
919 indexOf : function(o){
920 for (var i = 0, len = this.length; i < len; i++){
921 if(this[i] == o) return i;
927 * Removes the specified object from the array. If the object is not found nothing happens.
928 * @param {Object} o The object to remove
930 remove : function(o){
931 var index = this.indexOf(o);
933 this.splice(index, 1);
937 * Map (JS 1.6 compatibility)
938 * @param {Function} function to call
942 var len = this.length >>> 0;
943 if (typeof fun != "function")
944 throw new TypeError();
946 var res = new Array(len);
947 var thisp = arguments[1];
948 for (var i = 0; i < len; i++)
951 res[i] = fun.call(thisp, this[i], i, this);
962 * Ext JS Library 1.1.1
963 * Copyright(c) 2006-2007, Ext JS, LLC.
965 * Originally Released Under LGPL - original licence link has changed is not relivant.
968 * <script type="text/javascript">
974 * The date parsing and format syntax is a subset of
975 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
976 * supported will provide results equivalent to their PHP versions.
978 * Following is the list of all currently supported formats:
981 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
983 Format Output Description
984 ------ ---------- --------------------------------------------------------------
985 d 10 Day of the month, 2 digits with leading zeros
986 D Wed A textual representation of a day, three letters
987 j 10 Day of the month without leading zeros
988 l Wednesday A full textual representation of the day of the week
989 S th English ordinal day of month suffix, 2 chars (use with j)
990 w 3 Numeric representation of the day of the week
991 z 9 The julian date, or day of the year (0-365)
992 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
993 F January A full textual representation of the month
994 m 01 Numeric representation of a month, with leading zeros
995 M Jan Month name abbreviation, three letters
996 n 1 Numeric representation of a month, without leading zeros
997 t 31 Number of days in the given month
998 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
999 Y 2007 A full numeric representation of a year, 4 digits
1000 y 07 A two digit representation of a year
1001 a pm Lowercase Ante meridiem and Post meridiem
1002 A PM Uppercase Ante meridiem and Post meridiem
1003 g 3 12-hour format of an hour without leading zeros
1004 G 15 24-hour format of an hour without leading zeros
1005 h 03 12-hour format of an hour with leading zeros
1006 H 15 24-hour format of an hour with leading zeros
1007 i 05 Minutes with leading zeros
1008 s 01 Seconds, with leading zeros
1009 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1010 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1011 T CST Timezone setting of the machine running the code
1012 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1015 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1017 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1018 document.write(dt.format('Y-m-d')); //2007-01-10
1019 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1020 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1023 * Here are some standard date/time patterns that you might find helpful. They
1024 * are not part of the source of Date.js, but to use them you can simply copy this
1025 * block of code into any script that is included after Date.js and they will also become
1026 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1029 ISO8601Long:"Y-m-d H:i:s",
1030 ISO8601Short:"Y-m-d",
1032 LongDate: "l, F d, Y",
1033 FullDateTime: "l, F d, Y g:i:s A",
1036 LongTime: "g:i:s A",
1037 SortableDateTime: "Y-m-d\\TH:i:s",
1038 UniversalSortableDateTime: "Y-m-d H:i:sO",
1045 var dt = new Date();
1046 document.write(dt.format(Date.patterns.ShortDate));
1051 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1052 * They generate precompiled functions from date formats instead of parsing and
1053 * processing the pattern every time you format a date. These functions are available
1054 * on every Date object (any javascript function).
1056 * The original article and download are here:
1057 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1064 Returns the number of milliseconds between this date and date
1065 @param {Date} date (optional) Defaults to now
1066 @return {Number} The diff in milliseconds
1067 @member Date getElapsed
1069 Date.prototype.getElapsed = function(date) {
1070 return Math.abs((date || new Date()).getTime()-this.getTime());
1072 // was in date file..
1076 Date.parseFunctions = {count:0};
1078 Date.parseRegexes = [];
1080 Date.formatFunctions = {count:0};
1083 Date.prototype.dateFormat = function(format) {
1084 if (Date.formatFunctions[format] == null) {
1085 Date.createNewFormat(format);
1087 var func = Date.formatFunctions[format];
1088 return this[func]();
1093 * Formats a date given the supplied format string
1094 * @param {String} format The format string
1095 * @return {String} The formatted date
1098 Date.prototype.format = Date.prototype.dateFormat;
1101 Date.createNewFormat = function(format) {
1102 var funcName = "format" + Date.formatFunctions.count++;
1103 Date.formatFunctions[format] = funcName;
1104 var code = "Date.prototype." + funcName + " = function(){return ";
1105 var special = false;
1107 for (var i = 0; i < format.length; ++i) {
1108 ch = format.charAt(i);
1109 if (!special && ch == "\\") {
1114 code += "'" + String.escape(ch) + "' + ";
1117 code += Date.getFormatCode(ch);
1120 /** eval:var:zzzzzzzzzzzzz */
1121 eval(code.substring(0, code.length - 3) + ";}");
1125 Date.getFormatCode = function(character) {
1126 switch (character) {
1128 return "String.leftPad(this.getDate(), 2, '0') + ";
1130 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1132 return "this.getDate() + ";
1134 return "Date.dayNames[this.getDay()] + ";
1136 return "this.getSuffix() + ";
1138 return "this.getDay() + ";
1140 return "this.getDayOfYear() + ";
1142 return "this.getWeekOfYear() + ";
1144 return "Date.monthNames[this.getMonth()] + ";
1146 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1148 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1150 return "(this.getMonth() + 1) + ";
1152 return "this.getDaysInMonth() + ";
1154 return "(this.isLeapYear() ? 1 : 0) + ";
1156 return "this.getFullYear() + ";
1158 return "('' + this.getFullYear()).substring(2, 4) + ";
1160 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1162 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1164 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1166 return "this.getHours() + ";
1168 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1170 return "String.leftPad(this.getHours(), 2, '0') + ";
1172 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1174 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1176 return "this.getGMTOffset() + ";
1178 return "this.getGMTColonOffset() + ";
1180 return "this.getTimezone() + ";
1182 return "(this.getTimezoneOffset() * -60) + ";
1184 return "'" + String.escape(character) + "' + ";
1189 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1190 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1191 * the date format that is not specified will default to the current date value for that part. Time parts can also
1192 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1193 * string or the parse operation will fail.
1196 //dt = Fri May 25 2007 (current date)
1197 var dt = new Date();
1199 //dt = Thu May 25 2006 (today's month/day in 2006)
1200 dt = Date.parseDate("2006", "Y");
1202 //dt = Sun Jan 15 2006 (all date parts specified)
1203 dt = Date.parseDate("2006-1-15", "Y-m-d");
1205 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1206 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1208 * @param {String} input The unparsed date as a string
1209 * @param {String} format The format the date is in
1210 * @return {Date} The parsed date
1213 Date.parseDate = function(input, format) {
1214 if (Date.parseFunctions[format] == null) {
1215 Date.createParser(format);
1217 var func = Date.parseFunctions[format];
1218 return Date[func](input);
1223 Date.createParser = function(format) {
1224 var funcName = "parse" + Date.parseFunctions.count++;
1225 var regexNum = Date.parseRegexes.length;
1226 var currentGroup = 1;
1227 Date.parseFunctions[format] = funcName;
1229 var code = "Date." + funcName + " = function(input){\n"
1230 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1231 + "var d = new Date();\n"
1232 + "y = d.getFullYear();\n"
1233 + "m = d.getMonth();\n"
1234 + "d = d.getDate();\n"
1235 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1236 + "if (results && results.length > 0) {";
1239 var special = false;
1241 for (var i = 0; i < format.length; ++i) {
1242 ch = format.charAt(i);
1243 if (!special && ch == "\\") {
1248 regex += String.escape(ch);
1251 var obj = Date.formatCodeToRegex(ch, currentGroup);
1252 currentGroup += obj.g;
1254 if (obj.g && obj.c) {
1260 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1261 + "{v = new Date(y, m, d, h, i, s);}\n"
1262 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1265 + "{v = new Date(y, m, d, h);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1267 + "{v = new Date(y, m, d);}\n"
1268 + "else if (y >= 0 && m >= 0)\n"
1269 + "{v = new Date(y, m);}\n"
1270 + "else if (y >= 0)\n"
1271 + "{v = new Date(y);}\n"
1272 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1273 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1274 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1278 /** eval:var:zzzzzzzzzzzzz */
1283 Date.formatCodeToRegex = function(character, currentGroup) {
1284 switch (character) {
1288 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1292 s:"(\\d{1,2})"}; // day of month without leading zeroes
1295 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1296 s:"(\\d{2})"}; // day of month with leading zeroes
1300 s:"(?:" + Date.dayNames.join("|") + ")"};
1304 s:"(?:st|nd|rd|th)"};
1319 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1320 s:"(" + Date.monthNames.join("|") + ")"};
1323 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1324 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1328 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1332 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1343 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1347 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1348 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1352 c:"if (results[" + currentGroup + "] == 'am') {\n"
1353 + "if (h == 12) { h = 0; }\n"
1354 + "} else { if (h < 12) { h += 12; }}",
1358 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1365 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1366 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1370 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1374 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1378 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1383 "o = results[", currentGroup, "];\n",
1384 "var sn = o.substring(0,1);\n", // get + / - sign
1385 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1386 "var mn = o.substring(3,5) % 60;\n", // get minutes
1387 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1388 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1390 s:"([+\-]\\d{2,4})"};
1396 "o = results[", currentGroup, "];\n",
1397 "var sn = o.substring(0,1);\n",
1398 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1399 "var mn = o.substring(4,6) % 60;\n",
1400 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1401 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1411 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1412 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1416 s:String.escape(character)};
1421 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1422 * @return {String} The abbreviated timezone name (e.g. 'CST')
1424 Date.prototype.getTimezone = function() {
1425 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1429 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1430 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1432 Date.prototype.getGMTOffset = function() {
1433 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1434 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1435 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1439 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1440 * @return {String} 2-characters representing hours and 2-characters representing minutes
1441 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1443 Date.prototype.getGMTColonOffset = function() {
1444 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1445 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1447 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1451 * Get the numeric day number of the year, adjusted for leap year.
1452 * @return {Number} 0 through 364 (365 in leap years)
1454 Date.prototype.getDayOfYear = function() {
1456 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1457 for (var i = 0; i < this.getMonth(); ++i) {
1458 num += Date.daysInMonth[i];
1460 return num + this.getDate() - 1;
1464 * Get the string representation of the numeric week number of the year
1465 * (equivalent to the format specifier 'W').
1466 * @return {String} '00' through '52'
1468 Date.prototype.getWeekOfYear = function() {
1469 // Skip to Thursday of this week
1470 var now = this.getDayOfYear() + (4 - this.getDay());
1471 // Find the first Thursday of the year
1472 var jan1 = new Date(this.getFullYear(), 0, 1);
1473 var then = (7 - jan1.getDay() + 4);
1474 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1478 * Whether or not the current date is in a leap year.
1479 * @return {Boolean} True if the current date is in a leap year, else false
1481 Date.prototype.isLeapYear = function() {
1482 var year = this.getFullYear();
1483 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1487 * Get the first day of the current month, adjusted for leap year. The returned value
1488 * is the numeric day index within the week (0-6) which can be used in conjunction with
1489 * the {@link #monthNames} array to retrieve the textual day name.
1492 var dt = new Date('1/10/2007');
1493 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1495 * @return {Number} The day number (0-6)
1497 Date.prototype.getFirstDayOfMonth = function() {
1498 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1499 return (day < 0) ? (day + 7) : day;
1503 * Get the last day of the current month, adjusted for leap year. The returned value
1504 * is the numeric day index within the week (0-6) which can be used in conjunction with
1505 * the {@link #monthNames} array to retrieve the textual day name.
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1511 * @return {Number} The day number (0-6)
1513 Date.prototype.getLastDayOfMonth = function() {
1514 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1515 return (day < 0) ? (day + 7) : day;
1520 * Get the first date of this date's month
1523 Date.prototype.getFirstDateOfMonth = function() {
1524 return new Date(this.getFullYear(), this.getMonth(), 1);
1528 * Get the last date of this date's month
1531 Date.prototype.getLastDateOfMonth = function() {
1532 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 * Get the number of days in the current month, adjusted for leap year.
1536 * @return {Number} The number of days in the month
1538 Date.prototype.getDaysInMonth = function() {
1539 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1540 return Date.daysInMonth[this.getMonth()];
1544 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1545 * @return {String} 'st, 'nd', 'rd' or 'th'
1547 Date.prototype.getSuffix = function() {
1548 switch (this.getDate()) {
1565 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568 * An array of textual month names.
1569 * Override these values for international dates, for example...
1570 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1589 * An array of textual day names.
1590 * Override these values for international dates, for example...
1591 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1607 Date.monthNumbers = {
1622 * Creates and returns a new Date instance with the exact same date value as the called instance.
1623 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1624 * variable will also be changed. When the intention is to create a new variable that will not
1625 * modify the original instance, you should create a clone.
1627 * Example of correctly cloning a date:
1630 var orig = new Date('10/1/2006');
1633 document.write(orig); //returns 'Thu Oct 05 2006'!
1636 var orig = new Date('10/1/2006');
1637 var copy = orig.clone();
1639 document.write(orig); //returns 'Thu Oct 01 2006'
1641 * @return {Date} The new Date instance
1643 Date.prototype.clone = function() {
1644 return new Date(this.getTime());
1648 * Clears any time information from this date
1649 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1650 @return {Date} this or the clone
1652 Date.prototype.clearTime = function(clone){
1654 return this.clone().clearTime();
1659 this.setMilliseconds(0);
1664 // safari setMonth is broken
1666 Date.brokenSetMonth = Date.prototype.setMonth;
1667 Date.prototype.setMonth = function(num){
1669 var n = Math.ceil(-num);
1670 var back_year = Math.ceil(n/12);
1671 var month = (n % 12) ? 12 - n % 12 : 0 ;
1672 this.setFullYear(this.getFullYear() - back_year);
1673 return Date.brokenSetMonth.call(this, month);
1675 return Date.brokenSetMonth.apply(this, arguments);
1680 /** Date interval constant
1684 /** Date interval constant
1688 /** Date interval constant
1692 /** Date interval constant
1696 /** Date interval constant
1700 /** Date interval constant
1704 /** Date interval constant
1710 * Provides a convenient method of performing basic date arithmetic. This method
1711 * does not modify the Date instance being called - it creates and returns
1712 * a new Date instance containing the resulting date value.
1717 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1718 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1720 //Negative values will subtract correctly:
1721 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1722 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1724 //You can even chain several calls together in one line!
1725 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1726 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729 * @param {String} interval A valid date interval enum value
1730 * @param {Number} value The amount to add to the current date
1731 * @return {Date} The new Date instance
1733 Date.prototype.add = function(interval, value){
1734 var d = this.clone();
1735 if (!interval || value === 0) return d;
1736 switch(interval.toLowerCase()){
1738 d.setMilliseconds(this.getMilliseconds() + value);
1741 d.setSeconds(this.getSeconds() + value);
1744 d.setMinutes(this.getMinutes() + value);
1747 d.setHours(this.getHours() + value);
1750 d.setDate(this.getDate() + value);
1753 var day = this.getDate();
1755 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758 d.setMonth(this.getMonth() + value);
1761 d.setFullYear(this.getFullYear() + value);
1768 * Ext JS Library 1.1.1
1769 * Copyright(c) 2006-2007, Ext JS, LLC.
1771 * Originally Released Under LGPL - original licence link has changed is not relivant.
1774 * <script type="text/javascript">
1778 * @class Roo.lib.Dom
1781 * Dom utils (from YIU afaik)
1786 * Get the view width
1787 * @param {Boolean} full True will get the full document, otherwise it's the view width
1788 * @return {Number} The width
1791 getViewWidth : function(full) {
1792 return full ? this.getDocumentWidth() : this.getViewportWidth();
1795 * Get the view height
1796 * @param {Boolean} full True will get the full document, otherwise it's the view height
1797 * @return {Number} The height
1799 getViewHeight : function(full) {
1800 return full ? this.getDocumentHeight() : this.getViewportHeight();
1803 getDocumentHeight: function() {
1804 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1805 return Math.max(scrollHeight, this.getViewportHeight());
1808 getDocumentWidth: function() {
1809 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1810 return Math.max(scrollWidth, this.getViewportWidth());
1813 getViewportHeight: function() {
1814 var height = self.innerHeight;
1815 var mode = document.compatMode;
1817 if ((mode || Roo.isIE) && !Roo.isOpera) {
1818 height = (mode == "CSS1Compat") ?
1819 document.documentElement.clientHeight :
1820 document.body.clientHeight;
1826 getViewportWidth: function() {
1827 var width = self.innerWidth;
1828 var mode = document.compatMode;
1830 if (mode || Roo.isIE) {
1831 width = (mode == "CSS1Compat") ?
1832 document.documentElement.clientWidth :
1833 document.body.clientWidth;
1838 isAncestor : function(p, c) {
1845 if (p.contains && !Roo.isSafari) {
1846 return p.contains(c);
1847 } else if (p.compareDocumentPosition) {
1848 return !!(p.compareDocumentPosition(c) & 16);
1850 var parent = c.parentNode;
1855 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858 parent = parent.parentNode;
1864 getRegion : function(el) {
1865 return Roo.lib.Region.getRegion(el);
1868 getY : function(el) {
1869 return this.getXY(el)[1];
1872 getX : function(el) {
1873 return this.getXY(el)[0];
1876 getXY : function(el) {
1877 var p, pe, b, scroll, bd = document.body;
1878 el = Roo.getDom(el);
1879 var fly = Roo.lib.AnimBase.fly;
1880 if (el.getBoundingClientRect) {
1881 b = el.getBoundingClientRect();
1882 scroll = fly(document).getScroll();
1883 return [b.left + scroll.left, b.top + scroll.top];
1889 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1896 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1903 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1904 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1911 if (p != el && pe.getStyle('overflow') != 'visible') {
1919 if (Roo.isSafari && hasAbsolute) {
1924 if (Roo.isGecko && !hasAbsolute) {
1926 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1927 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1931 while (p && p != bd) {
1932 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1944 setXY : function(el, xy) {
1945 el = Roo.fly(el, '_setXY');
1947 var pts = el.translatePoints(xy);
1948 if (xy[0] !== false) {
1949 el.dom.style.left = pts.left + "px";
1951 if (xy[1] !== false) {
1952 el.dom.style.top = pts.top + "px";
1956 setX : function(el, x) {
1957 this.setXY(el, [x, false]);
1960 setY : function(el, y) {
1961 this.setXY(el, [false, y]);
1965 * Portions of this file are based on pieces of Yahoo User Interface Library
1966 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1967 * YUI licensed under the BSD License:
1968 * http://developer.yahoo.net/yui/license.txt
1969 * <script type="text/javascript">
1973 Roo.lib.Event = function() {
1974 var loadComplete = false;
1976 var unloadListeners = [];
1978 var onAvailStack = [];
1980 var lastError = null;
1993 startInterval: function() {
1994 if (!this._interval) {
1996 var callback = function() {
1997 self._tryPreloadAttach();
1999 this._interval = setInterval(callback, this.POLL_INTERVAL);
2004 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2005 onAvailStack.push({ id: p_id,
2008 override: p_override,
2009 checkReady: false });
2011 retryCount = this.POLL_RETRYS;
2012 this.startInterval();
2016 addListener: function(el, eventName, fn) {
2017 el = Roo.getDom(el);
2022 if ("unload" == eventName) {
2023 unloadListeners[unloadListeners.length] =
2024 [el, eventName, fn];
2028 var wrappedFn = function(e) {
2029 return fn(Roo.lib.Event.getEvent(e));
2032 var li = [el, eventName, fn, wrappedFn];
2034 var index = listeners.length;
2035 listeners[index] = li;
2037 this.doAdd(el, eventName, wrappedFn, false);
2043 removeListener: function(el, eventName, fn) {
2046 el = Roo.getDom(el);
2049 return this.purgeElement(el, false, eventName);
2053 if ("unload" == eventName) {
2055 for (i = 0,len = unloadListeners.length; i < len; i++) {
2056 var li = unloadListeners[i];
2059 li[1] == eventName &&
2061 unloadListeners.splice(i, 1);
2069 var cacheItem = null;
2072 var index = arguments[3];
2074 if ("undefined" == typeof index) {
2075 index = this._getCacheIndex(el, eventName, fn);
2079 cacheItem = listeners[index];
2082 if (!el || !cacheItem) {
2086 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2088 delete listeners[index][this.WFN];
2089 delete listeners[index][this.FN];
2090 listeners.splice(index, 1);
2097 getTarget: function(ev, resolveTextNode) {
2098 ev = ev.browserEvent || ev;
2099 var t = ev.target || ev.srcElement;
2100 return this.resolveTextNode(t);
2104 resolveTextNode: function(node) {
2105 if (Roo.isSafari && node && 3 == node.nodeType) {
2106 return node.parentNode;
2113 getPageX: function(ev) {
2114 ev = ev.browserEvent || ev;
2116 if (!x && 0 !== x) {
2117 x = ev.clientX || 0;
2120 x += this.getScroll()[1];
2128 getPageY: function(ev) {
2129 ev = ev.browserEvent || ev;
2131 if (!y && 0 !== y) {
2132 y = ev.clientY || 0;
2135 y += this.getScroll()[0];
2144 getXY: function(ev) {
2145 ev = ev.browserEvent || ev;
2146 return [this.getPageX(ev), this.getPageY(ev)];
2150 getRelatedTarget: function(ev) {
2151 ev = ev.browserEvent || ev;
2152 var t = ev.relatedTarget;
2154 if (ev.type == "mouseout") {
2156 } else if (ev.type == "mouseover") {
2161 return this.resolveTextNode(t);
2165 getTime: function(ev) {
2166 ev = ev.browserEvent || ev;
2168 var t = new Date().getTime();
2172 this.lastError = ex;
2181 stopEvent: function(ev) {
2182 this.stopPropagation(ev);
2183 this.preventDefault(ev);
2187 stopPropagation: function(ev) {
2188 ev = ev.browserEvent || ev;
2189 if (ev.stopPropagation) {
2190 ev.stopPropagation();
2192 ev.cancelBubble = true;
2197 preventDefault: function(ev) {
2198 ev = ev.browserEvent || ev;
2199 if(ev.preventDefault) {
2200 ev.preventDefault();
2202 ev.returnValue = false;
2207 getEvent: function(e) {
2208 var ev = e || window.event;
2210 var c = this.getEvent.caller;
2212 ev = c.arguments[0];
2213 if (ev && Event == ev.constructor) {
2223 getCharCode: function(ev) {
2224 ev = ev.browserEvent || ev;
2225 return ev.charCode || ev.keyCode || 0;
2229 _getCacheIndex: function(el, eventName, fn) {
2230 for (var i = 0,len = listeners.length; i < len; ++i) {
2231 var li = listeners[i];
2233 li[this.FN] == fn &&
2234 li[this.EL] == el &&
2235 li[this.TYPE] == eventName) {
2247 getEl: function(id) {
2248 return document.getElementById(id);
2252 clearCache: function() {
2256 _load: function(e) {
2257 loadComplete = true;
2258 var EU = Roo.lib.Event;
2262 EU.doRemove(window, "load", EU._load);
2267 _tryPreloadAttach: function() {
2276 var tryAgain = !loadComplete;
2278 tryAgain = (retryCount > 0);
2283 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2284 var item = onAvailStack[i];
2286 var el = this.getEl(item.id);
2289 if (!item.checkReady ||
2292 (document && document.body)) {
2295 if (item.override) {
2296 if (item.override === true) {
2299 scope = item.override;
2302 item.fn.call(scope, item.obj);
2303 onAvailStack[i] = null;
2306 notAvail.push(item);
2311 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2315 this.startInterval();
2317 clearInterval(this._interval);
2318 this._interval = null;
2321 this.locked = false;
2328 purgeElement: function(el, recurse, eventName) {
2329 var elListeners = this.getListeners(el, eventName);
2331 for (var i = 0,len = elListeners.length; i < len; ++i) {
2332 var l = elListeners[i];
2333 this.removeListener(el, l.type, l.fn);
2337 if (recurse && el && el.childNodes) {
2338 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2339 this.purgeElement(el.childNodes[i], recurse, eventName);
2345 getListeners: function(el, eventName) {
2346 var results = [], searchLists;
2348 searchLists = [listeners, unloadListeners];
2349 } else if (eventName == "unload") {
2350 searchLists = [unloadListeners];
2352 searchLists = [listeners];
2355 for (var j = 0; j < searchLists.length; ++j) {
2356 var searchList = searchLists[j];
2357 if (searchList && searchList.length > 0) {
2358 for (var i = 0,len = searchList.length; i < len; ++i) {
2359 var l = searchList[i];
2360 if (l && l[this.EL] === el &&
2361 (!eventName || eventName === l[this.TYPE])) {
2366 adjust: l[this.ADJ_SCOPE],
2374 return (results.length) ? results : null;
2378 _unload: function(e) {
2380 var EU = Roo.lib.Event, i, j, l, len, index;
2382 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2383 l = unloadListeners[i];
2386 if (l[EU.ADJ_SCOPE]) {
2387 if (l[EU.ADJ_SCOPE] === true) {
2390 scope = l[EU.ADJ_SCOPE];
2393 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2394 unloadListeners[i] = null;
2400 unloadListeners = null;
2402 if (listeners && listeners.length > 0) {
2403 j = listeners.length;
2406 l = listeners[index];
2408 EU.removeListener(l[EU.EL], l[EU.TYPE],
2418 EU.doRemove(window, "unload", EU._unload);
2423 getScroll: function() {
2424 var dd = document.documentElement, db = document.body;
2425 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2426 return [dd.scrollTop, dd.scrollLeft];
2428 return [db.scrollTop, db.scrollLeft];
2435 doAdd: function () {
2436 if (window.addEventListener) {
2437 return function(el, eventName, fn, capture) {
2438 el.addEventListener(eventName, fn, (capture));
2440 } else if (window.attachEvent) {
2441 return function(el, eventName, fn, capture) {
2442 el.attachEvent("on" + eventName, fn);
2451 doRemove: function() {
2452 if (window.removeEventListener) {
2453 return function (el, eventName, fn, capture) {
2454 el.removeEventListener(eventName, fn, (capture));
2456 } else if (window.detachEvent) {
2457 return function (el, eventName, fn) {
2458 el.detachEvent("on" + eventName, fn);
2470 var E = Roo.lib.Event;
2471 E.on = E.addListener;
2472 E.un = E.removeListener;
2474 if (document && document.body) {
2477 E.doAdd(window, "load", E._load);
2479 E.doAdd(window, "unload", E._unload);
2480 E._tryPreloadAttach();
2484 * Portions of this file are based on pieces of Yahoo User Interface Library
2485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2486 * YUI licensed under the BSD License:
2487 * http://developer.yahoo.net/yui/license.txt
2488 * <script type="text/javascript">
2494 * @class Roo.lib.Ajax
2501 request : function(method, uri, cb, data, options) {
2503 var hs = options.headers;
2506 if(hs.hasOwnProperty(h)){
2507 this.initHeader(h, hs[h], false);
2511 if(options.xmlData){
2512 this.initHeader('Content-Type', 'text/xml', false);
2514 data = options.xmlData;
2518 return this.asyncRequest(method, uri, cb, data);
2521 serializeForm : function(form) {
2522 if(typeof form == 'string') {
2523 form = (document.getElementById(form) || document.forms[form]);
2526 var el, name, val, disabled, data = '', hasSubmit = false;
2527 for (var i = 0; i < form.elements.length; i++) {
2528 el = form.elements[i];
2529 disabled = form.elements[i].disabled;
2530 name = form.elements[i].name;
2531 val = form.elements[i].value;
2533 if (!disabled && name){
2537 case 'select-multiple':
2538 for (var j = 0; j < el.options.length; j++) {
2539 if (el.options[j].selected) {
2541 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2544 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2565 if(hasSubmit == false) {
2566 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2571 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2576 data = data.substr(0, data.length - 1);
2584 useDefaultHeader:true,
2586 defaultPostHeader:'application/x-www-form-urlencoded',
2588 useDefaultXhrHeader:true,
2590 defaultXhrHeader:'XMLHttpRequest',
2592 hasDefaultHeaders:true,
2604 setProgId:function(id)
2606 this.activeX.unshift(id);
2609 setDefaultPostHeader:function(b)
2611 this.useDefaultHeader = b;
2614 setDefaultXhrHeader:function(b)
2616 this.useDefaultXhrHeader = b;
2619 setPollingInterval:function(i)
2621 if (typeof i == 'number' && isFinite(i)) {
2622 this.pollInterval = i;
2626 createXhrObject:function(transactionId)
2632 http = new XMLHttpRequest();
2634 obj = { conn:http, tId:transactionId };
2638 for (var i = 0; i < this.activeX.length; ++i) {
2642 http = new ActiveXObject(this.activeX[i]);
2644 obj = { conn:http, tId:transactionId };
2657 getConnectionObject:function()
2660 var tId = this.transactionId;
2664 o = this.createXhrObject(tId);
2666 this.transactionId++;
2677 asyncRequest:function(method, uri, callback, postData)
2679 var o = this.getConnectionObject();
2685 o.conn.open(method, uri, true);
2687 if (this.useDefaultXhrHeader) {
2688 if (!this.defaultHeaders['X-Requested-With']) {
2689 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2693 if(postData && this.useDefaultHeader){
2694 this.initHeader('Content-Type', this.defaultPostHeader);
2697 if (this.hasDefaultHeaders || this.hasHeaders) {
2701 this.handleReadyState(o, callback);
2702 o.conn.send(postData || null);
2708 handleReadyState:function(o, callback)
2712 if (callback && callback.timeout) {
2713 this.timeout[o.tId] = window.setTimeout(function() {
2714 oConn.abort(o, callback, true);
2715 }, callback.timeout);
2718 this.poll[o.tId] = window.setInterval(
2720 if (o.conn && o.conn.readyState == 4) {
2721 window.clearInterval(oConn.poll[o.tId]);
2722 delete oConn.poll[o.tId];
2724 if(callback && callback.timeout) {
2725 window.clearTimeout(oConn.timeout[o.tId]);
2726 delete oConn.timeout[o.tId];
2729 oConn.handleTransactionResponse(o, callback);
2732 , this.pollInterval);
2735 handleTransactionResponse:function(o, callback, isAbort)
2739 this.releaseObject(o);
2743 var httpStatus, responseObject;
2747 if (o.conn.status !== undefined && o.conn.status != 0) {
2748 httpStatus = o.conn.status;
2760 if (httpStatus >= 200 && httpStatus < 300) {
2761 responseObject = this.createResponseObject(o, callback.argument);
2762 if (callback.success) {
2763 if (!callback.scope) {
2764 callback.success(responseObject);
2769 callback.success.apply(callback.scope, [responseObject]);
2774 switch (httpStatus) {
2782 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2783 if (callback.failure) {
2784 if (!callback.scope) {
2785 callback.failure(responseObject);
2788 callback.failure.apply(callback.scope, [responseObject]);
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.failure) {
2795 if (!callback.scope) {
2796 callback.failure(responseObject);
2799 callback.failure.apply(callback.scope, [responseObject]);
2805 this.releaseObject(o);
2806 responseObject = null;
2809 createResponseObject:function(o, callbackArg)
2816 var headerStr = o.conn.getAllResponseHeaders();
2817 var header = headerStr.split('\n');
2818 for (var i = 0; i < header.length; i++) {
2819 var delimitPos = header[i].indexOf(':');
2820 if (delimitPos != -1) {
2821 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2829 obj.status = o.conn.status;
2830 obj.statusText = o.conn.statusText;
2831 obj.getResponseHeader = headerObj;
2832 obj.getAllResponseHeaders = headerStr;
2833 obj.responseText = o.conn.responseText;
2834 obj.responseXML = o.conn.responseXML;
2836 if (typeof callbackArg !== undefined) {
2837 obj.argument = callbackArg;
2843 createExceptionObject:function(tId, callbackArg, isAbort)
2846 var COMM_ERROR = 'communication failure';
2847 var ABORT_CODE = -1;
2848 var ABORT_ERROR = 'transaction aborted';
2854 obj.status = ABORT_CODE;
2855 obj.statusText = ABORT_ERROR;
2858 obj.status = COMM_CODE;
2859 obj.statusText = COMM_ERROR;
2863 obj.argument = callbackArg;
2869 initHeader:function(label, value, isDefault)
2871 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2873 if (headerObj[label] === undefined) {
2874 headerObj[label] = value;
2879 headerObj[label] = value + "," + headerObj[label];
2883 this.hasDefaultHeaders = true;
2886 this.hasHeaders = true;
2891 setHeader:function(o)
2893 if (this.hasDefaultHeaders) {
2894 for (var prop in this.defaultHeaders) {
2895 if (this.defaultHeaders.hasOwnProperty(prop)) {
2896 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2901 if (this.hasHeaders) {
2902 for (var prop in this.headers) {
2903 if (this.headers.hasOwnProperty(prop)) {
2904 o.conn.setRequestHeader(prop, this.headers[prop]);
2908 this.hasHeaders = false;
2912 resetDefaultHeaders:function() {
2913 delete this.defaultHeaders;
2914 this.defaultHeaders = {};
2915 this.hasDefaultHeaders = false;
2918 abort:function(o, callback, isTimeout)
2920 if(this.isCallInProgress(o)) {
2922 window.clearInterval(this.poll[o.tId]);
2923 delete this.poll[o.tId];
2925 delete this.timeout[o.tId];
2928 this.handleTransactionResponse(o, callback, true);
2938 isCallInProgress:function(o)
2941 return o.conn.readyState != 4 && o.conn.readyState != 0;
2950 releaseObject:function(o)
2959 'MSXML2.XMLHTTP.3.0',
2967 * Portions of this file are based on pieces of Yahoo User Interface Library
2968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2969 * YUI licensed under the BSD License:
2970 * http://developer.yahoo.net/yui/license.txt
2971 * <script type="text/javascript">
2975 Roo.lib.Region = function(t, r, b, l) {
2985 Roo.lib.Region.prototype = {
2986 contains : function(region) {
2987 return ( region.left >= this.left &&
2988 region.right <= this.right &&
2989 region.top >= this.top &&
2990 region.bottom <= this.bottom );
2994 getArea : function() {
2995 return ( (this.bottom - this.top) * (this.right - this.left) );
2998 intersect : function(region) {
2999 var t = Math.max(this.top, region.top);
3000 var r = Math.min(this.right, region.right);
3001 var b = Math.min(this.bottom, region.bottom);
3002 var l = Math.max(this.left, region.left);
3004 if (b >= t && r >= l) {
3005 return new Roo.lib.Region(t, r, b, l);
3010 union : function(region) {
3011 var t = Math.min(this.top, region.top);
3012 var r = Math.max(this.right, region.right);
3013 var b = Math.max(this.bottom, region.bottom);
3014 var l = Math.min(this.left, region.left);
3016 return new Roo.lib.Region(t, r, b, l);
3019 adjust : function(t, l, b, r) {
3028 Roo.lib.Region.getRegion = function(el) {
3029 var p = Roo.lib.Dom.getXY(el);
3032 var r = p[0] + el.offsetWidth;
3033 var b = p[1] + el.offsetHeight;
3036 return new Roo.lib.Region(t, r, b, l);
3039 * Portions of this file are based on pieces of Yahoo User Interface Library
3040 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3041 * YUI licensed under the BSD License:
3042 * http://developer.yahoo.net/yui/license.txt
3043 * <script type="text/javascript">
3046 //@@dep Roo.lib.Region
3049 Roo.lib.Point = function(x, y) {
3050 if (x instanceof Array) {
3054 this.x = this.right = this.left = this[0] = x;
3055 this.y = this.top = this.bottom = this[1] = y;
3058 Roo.lib.Point.prototype = new Roo.lib.Region();
3060 * Portions of this file are based on pieces of Yahoo User Interface Library
3061 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3062 * YUI licensed under the BSD License:
3063 * http://developer.yahoo.net/yui/license.txt
3064 * <script type="text/javascript">
3071 scroll : function(el, args, duration, easing, cb, scope) {
3072 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3075 motion : function(el, args, duration, easing, cb, scope) {
3076 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3079 color : function(el, args, duration, easing, cb, scope) {
3080 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3083 run : function(el, args, duration, easing, cb, scope, type) {
3084 type = type || Roo.lib.AnimBase;
3085 if (typeof easing == "string") {
3086 easing = Roo.lib.Easing[easing];
3088 var anim = new type(el, args, duration, easing);
3089 anim.animateX(function() {
3090 Roo.callback(cb, scope);
3096 * Portions of this file are based on pieces of Yahoo User Interface Library
3097 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3098 * YUI licensed under the BSD License:
3099 * http://developer.yahoo.net/yui/license.txt
3100 * <script type="text/javascript">
3108 if (!libFlyweight) {
3109 libFlyweight = new Roo.Element.Flyweight();
3111 libFlyweight.dom = el;
3112 return libFlyweight;
3115 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3119 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3121 this.init(el, attributes, duration, method);
3125 Roo.lib.AnimBase.fly = fly;
3129 Roo.lib.AnimBase.prototype = {
3131 toString: function() {
3132 var el = this.getEl();
3133 var id = el.id || el.tagName;
3134 return ("Anim " + id);
3138 noNegatives: /width|height|opacity|padding/i,
3139 offsetAttribute: /^((width|height)|(top|left))$/,
3140 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3141 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3145 doMethod: function(attr, start, end) {
3146 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3150 setAttribute: function(attr, val, unit) {
3151 if (this.patterns.noNegatives.test(attr)) {
3152 val = (val > 0) ? val : 0;
3155 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3159 getAttribute: function(attr) {
3160 var el = this.getEl();
3161 var val = fly(el).getStyle(attr);
3163 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3164 return parseFloat(val);
3167 var a = this.patterns.offsetAttribute.exec(attr) || [];
3168 var pos = !!( a[3] );
3169 var box = !!( a[2] );
3172 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3173 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3182 getDefaultUnit: function(attr) {
3183 if (this.patterns.defaultUnit.test(attr)) {
3190 animateX : function(callback, scope) {
3191 var f = function() {
3192 this.onComplete.removeListener(f);
3193 if (typeof callback == "function") {
3194 callback.call(scope || this, this);
3197 this.onComplete.addListener(f, this);
3202 setRuntimeAttribute: function(attr) {
3205 var attributes = this.attributes;
3207 this.runtimeAttributes[attr] = {};
3209 var isset = function(prop) {
3210 return (typeof prop !== 'undefined');
3213 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3217 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3220 if (isset(attributes[attr]['to'])) {
3221 end = attributes[attr]['to'];
3222 } else if (isset(attributes[attr]['by'])) {
3223 if (start.constructor == Array) {
3225 for (var i = 0, len = start.length; i < len; ++i) {
3226 end[i] = start[i] + attributes[attr]['by'][i];
3229 end = start + attributes[attr]['by'];
3233 this.runtimeAttributes[attr].start = start;
3234 this.runtimeAttributes[attr].end = end;
3237 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3241 init: function(el, attributes, duration, method) {
3243 var isAnimated = false;
3246 var startTime = null;
3249 var actualFrames = 0;
3252 el = Roo.getDom(el);
3255 this.attributes = attributes || {};
3258 this.duration = duration || 1;
3261 this.method = method || Roo.lib.Easing.easeNone;
3264 this.useSeconds = true;
3267 this.currentFrame = 0;
3270 this.totalFrames = Roo.lib.AnimMgr.fps;
3273 this.getEl = function() {
3278 this.isAnimated = function() {
3283 this.getStartTime = function() {
3287 this.runtimeAttributes = {};
3290 this.animate = function() {
3291 if (this.isAnimated()) {
3295 this.currentFrame = 0;
3297 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3299 Roo.lib.AnimMgr.registerElement(this);
3303 this.stop = function(finish) {
3305 this.currentFrame = this.totalFrames;
3306 this._onTween.fire();
3308 Roo.lib.AnimMgr.stop(this);
3311 var onStart = function() {
3312 this.onStart.fire();
3314 this.runtimeAttributes = {};
3315 for (var attr in this.attributes) {
3316 this.setRuntimeAttribute(attr);
3321 startTime = new Date();
3325 var onTween = function() {
3327 duration: new Date() - this.getStartTime(),
3328 currentFrame: this.currentFrame
3331 data.toString = function() {
3333 'duration: ' + data.duration +
3334 ', currentFrame: ' + data.currentFrame
3338 this.onTween.fire(data);
3340 var runtimeAttributes = this.runtimeAttributes;
3342 for (var attr in runtimeAttributes) {
3343 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3349 var onComplete = function() {
3350 var actual_duration = (new Date() - startTime) / 1000 ;
3353 duration: actual_duration,
3354 frames: actualFrames,
3355 fps: actualFrames / actual_duration
3358 data.toString = function() {
3360 'duration: ' + data.duration +
3361 ', frames: ' + data.frames +
3362 ', fps: ' + data.fps
3368 this.onComplete.fire(data);
3372 this._onStart = new Roo.util.Event(this);
3373 this.onStart = new Roo.util.Event(this);
3374 this.onTween = new Roo.util.Event(this);
3375 this._onTween = new Roo.util.Event(this);
3376 this.onComplete = new Roo.util.Event(this);
3377 this._onComplete = new Roo.util.Event(this);
3378 this._onStart.addListener(onStart);
3379 this._onTween.addListener(onTween);
3380 this._onComplete.addListener(onComplete);
3385 * Portions of this file are based on pieces of Yahoo User Interface Library
3386 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3387 * YUI licensed under the BSD License:
3388 * http://developer.yahoo.net/yui/license.txt
3389 * <script type="text/javascript">
3393 Roo.lib.AnimMgr = new function() {
3410 this.registerElement = function(tween) {
3411 queue[queue.length] = tween;
3413 tween._onStart.fire();
3418 this.unRegister = function(tween, index) {
3419 tween._onComplete.fire();
3420 index = index || getIndex(tween);
3422 queue.splice(index, 1);
3426 if (tweenCount <= 0) {
3432 this.start = function() {
3433 if (thread === null) {
3434 thread = setInterval(this.run, this.delay);
3439 this.stop = function(tween) {
3441 clearInterval(thread);
3443 for (var i = 0, len = queue.length; i < len; ++i) {
3444 if (queue[0].isAnimated()) {
3445 this.unRegister(queue[0], 0);
3454 this.unRegister(tween);
3459 this.run = function() {
3460 for (var i = 0, len = queue.length; i < len; ++i) {
3461 var tween = queue[i];
3462 if (!tween || !tween.isAnimated()) {
3466 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3468 tween.currentFrame += 1;
3470 if (tween.useSeconds) {
3471 correctFrame(tween);
3473 tween._onTween.fire();
3476 Roo.lib.AnimMgr.stop(tween, i);
3481 var getIndex = function(anim) {
3482 for (var i = 0, len = queue.length; i < len; ++i) {
3483 if (queue[i] == anim) {
3491 var correctFrame = function(tween) {
3492 var frames = tween.totalFrames;
3493 var frame = tween.currentFrame;
3494 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3495 var elapsed = (new Date() - tween.getStartTime());
3498 if (elapsed < tween.duration * 1000) {
3499 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3501 tweak = frames - (frame + 1);
3503 if (tweak > 0 && isFinite(tweak)) {
3504 if (tween.currentFrame + tweak >= frames) {
3505 tweak = frames - (frame + 1);
3508 tween.currentFrame += tweak;
3512 * Portions of this file are based on pieces of Yahoo User Interface Library
3513 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3514 * YUI licensed under the BSD License:
3515 * http://developer.yahoo.net/yui/license.txt
3516 * <script type="text/javascript">
3519 Roo.lib.Bezier = new function() {
3521 this.getPosition = function(points, t) {
3522 var n = points.length;
3525 for (var i = 0; i < n; ++i) {
3526 tmp[i] = [points[i][0], points[i][1]];
3529 for (var j = 1; j < n; ++j) {
3530 for (i = 0; i < n - j; ++i) {
3531 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3532 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3536 return [ tmp[0][0], tmp[0][1] ];
3540 * Portions of this file are based on pieces of Yahoo User Interface Library
3541 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3542 * YUI licensed under the BSD License:
3543 * http://developer.yahoo.net/yui/license.txt
3544 * <script type="text/javascript">
3549 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3550 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3553 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3555 var fly = Roo.lib.AnimBase.fly;
3557 var superclass = Y.ColorAnim.superclass;
3558 var proto = Y.ColorAnim.prototype;
3560 proto.toString = function() {
3561 var el = this.getEl();
3562 var id = el.id || el.tagName;
3563 return ("ColorAnim " + id);
3566 proto.patterns.color = /color$/i;
3567 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3568 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3569 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3570 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3573 proto.parseColor = function(s) {
3574 if (s.length == 3) {
3578 var c = this.patterns.hex.exec(s);
3579 if (c && c.length == 4) {
3580 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3583 c = this.patterns.rgb.exec(s);
3584 if (c && c.length == 4) {
3585 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3588 c = this.patterns.hex3.exec(s);
3589 if (c && c.length == 4) {
3590 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3595 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3596 proto.getAttribute = function(attr) {
3597 var el = this.getEl();
3598 if (this.patterns.color.test(attr)) {
3599 var val = fly(el).getStyle(attr);
3601 if (this.patterns.transparent.test(val)) {
3602 var parent = el.parentNode;
3603 val = fly(parent).getStyle(attr);
3605 while (parent && this.patterns.transparent.test(val)) {
3606 parent = parent.parentNode;
3607 val = fly(parent).getStyle(attr);
3608 if (parent.tagName.toUpperCase() == 'HTML') {
3614 val = superclass.getAttribute.call(this, attr);
3619 proto.getAttribute = function(attr) {
3620 var el = this.getEl();
3621 if (this.patterns.color.test(attr)) {
3622 var val = fly(el).getStyle(attr);
3624 if (this.patterns.transparent.test(val)) {
3625 var parent = el.parentNode;
3626 val = fly(parent).getStyle(attr);
3628 while (parent && this.patterns.transparent.test(val)) {
3629 parent = parent.parentNode;
3630 val = fly(parent).getStyle(attr);
3631 if (parent.tagName.toUpperCase() == 'HTML') {
3637 val = superclass.getAttribute.call(this, attr);
3643 proto.doMethod = function(attr, start, end) {
3646 if (this.patterns.color.test(attr)) {
3648 for (var i = 0, len = start.length; i < len; ++i) {
3649 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3652 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3655 val = superclass.doMethod.call(this, attr, start, end);
3661 proto.setRuntimeAttribute = function(attr) {
3662 superclass.setRuntimeAttribute.call(this, attr);
3664 if (this.patterns.color.test(attr)) {
3665 var attributes = this.attributes;
3666 var start = this.parseColor(this.runtimeAttributes[attr].start);
3667 var end = this.parseColor(this.runtimeAttributes[attr].end);
3669 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3670 end = this.parseColor(attributes[attr].by);
3672 for (var i = 0, len = start.length; i < len; ++i) {
3673 end[i] = start[i] + end[i];
3677 this.runtimeAttributes[attr].start = start;
3678 this.runtimeAttributes[attr].end = end;
3684 * Portions of this file are based on pieces of Yahoo User Interface Library
3685 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3686 * YUI licensed under the BSD License:
3687 * http://developer.yahoo.net/yui/license.txt
3688 * <script type="text/javascript">
3694 easeNone: function (t, b, c, d) {
3695 return c * t / d + b;
3699 easeIn: function (t, b, c, d) {
3700 return c * (t /= d) * t + b;
3704 easeOut: function (t, b, c, d) {
3705 return -c * (t /= d) * (t - 2) + b;
3709 easeBoth: function (t, b, c, d) {
3710 if ((t /= d / 2) < 1) {
3711 return c / 2 * t * t + b;
3714 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3718 easeInStrong: function (t, b, c, d) {
3719 return c * (t /= d) * t * t * t + b;
3723 easeOutStrong: function (t, b, c, d) {
3724 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3728 easeBothStrong: function (t, b, c, d) {
3729 if ((t /= d / 2) < 1) {
3730 return c / 2 * t * t * t * t + b;
3733 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3738 elasticIn: function (t, b, c, d, a, p) {
3742 if ((t /= d) == 1) {
3749 if (!a || a < Math.abs(c)) {
3754 var s = p / (2 * Math.PI) * Math.asin(c / a);
3757 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3761 elasticOut: function (t, b, c, d, a, p) {
3765 if ((t /= d) == 1) {
3772 if (!a || a < Math.abs(c)) {
3777 var s = p / (2 * Math.PI) * Math.asin(c / a);
3780 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3784 elasticBoth: function (t, b, c, d, a, p) {
3789 if ((t /= d / 2) == 2) {
3797 if (!a || a < Math.abs(c)) {
3802 var s = p / (2 * Math.PI) * Math.asin(c / a);
3806 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3807 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3809 return a * Math.pow(2, -10 * (t -= 1)) *
3810 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3815 backIn: function (t, b, c, d, s) {
3816 if (typeof s == 'undefined') {
3819 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3823 backOut: function (t, b, c, d, s) {
3824 if (typeof s == 'undefined') {
3827 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3831 backBoth: function (t, b, c, d, s) {
3832 if (typeof s == 'undefined') {
3836 if ((t /= d / 2 ) < 1) {
3837 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3839 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3843 bounceIn: function (t, b, c, d) {
3844 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3848 bounceOut: function (t, b, c, d) {
3849 if ((t /= d) < (1 / 2.75)) {
3850 return c * (7.5625 * t * t) + b;
3851 } else if (t < (2 / 2.75)) {
3852 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3853 } else if (t < (2.5 / 2.75)) {
3854 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3856 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3860 bounceBoth: function (t, b, c, d) {
3862 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3864 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3867 * Portions of this file are based on pieces of Yahoo User Interface Library
3868 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3869 * YUI licensed under the BSD License:
3870 * http://developer.yahoo.net/yui/license.txt
3871 * <script type="text/javascript">
3875 Roo.lib.Motion = function(el, attributes, duration, method) {
3877 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3881 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3885 var superclass = Y.Motion.superclass;
3886 var proto = Y.Motion.prototype;
3888 proto.toString = function() {
3889 var el = this.getEl();
3890 var id = el.id || el.tagName;
3891 return ("Motion " + id);
3894 proto.patterns.points = /^points$/i;
3896 proto.setAttribute = function(attr, val, unit) {
3897 if (this.patterns.points.test(attr)) {
3898 unit = unit || 'px';
3899 superclass.setAttribute.call(this, 'left', val[0], unit);
3900 superclass.setAttribute.call(this, 'top', val[1], unit);
3902 superclass.setAttribute.call(this, attr, val, unit);
3906 proto.getAttribute = function(attr) {
3907 if (this.patterns.points.test(attr)) {
3909 superclass.getAttribute.call(this, 'left'),
3910 superclass.getAttribute.call(this, 'top')
3913 val = superclass.getAttribute.call(this, attr);
3919 proto.doMethod = function(attr, start, end) {
3922 if (this.patterns.points.test(attr)) {
3923 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3924 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3926 val = superclass.doMethod.call(this, attr, start, end);
3931 proto.setRuntimeAttribute = function(attr) {
3932 if (this.patterns.points.test(attr)) {
3933 var el = this.getEl();
3934 var attributes = this.attributes;
3936 var control = attributes['points']['control'] || [];
3940 if (control.length > 0 && !(control[0] instanceof Array)) {
3941 control = [control];
3944 for (i = 0,len = control.length; i < len; ++i) {
3945 tmp[i] = control[i];
3950 Roo.fly(el).position();
3952 if (isset(attributes['points']['from'])) {
3953 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3956 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3959 start = this.getAttribute('points');
3962 if (isset(attributes['points']['to'])) {
3963 end = translateValues.call(this, attributes['points']['to'], start);
3965 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3966 for (i = 0,len = control.length; i < len; ++i) {
3967 control[i] = translateValues.call(this, control[i], start);
3971 } else if (isset(attributes['points']['by'])) {
3972 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3974 for (i = 0,len = control.length; i < len; ++i) {
3975 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3979 this.runtimeAttributes[attr] = [start];
3981 if (control.length > 0) {
3982 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3985 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3988 superclass.setRuntimeAttribute.call(this, attr);
3992 var translateValues = function(val, start) {
3993 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3994 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3999 var isset = function(prop) {
4000 return (typeof prop !== 'undefined');
4004 * Portions of this file are based on pieces of Yahoo User Interface Library
4005 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4006 * YUI licensed under the BSD License:
4007 * http://developer.yahoo.net/yui/license.txt
4008 * <script type="text/javascript">
4012 Roo.lib.Scroll = function(el, attributes, duration, method) {
4014 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4018 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4022 var superclass = Y.Scroll.superclass;
4023 var proto = Y.Scroll.prototype;
4025 proto.toString = function() {
4026 var el = this.getEl();
4027 var id = el.id || el.tagName;
4028 return ("Scroll " + id);
4031 proto.doMethod = function(attr, start, end) {
4034 if (attr == 'scroll') {
4036 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4037 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4041 val = superclass.doMethod.call(this, attr, start, end);
4046 proto.getAttribute = function(attr) {
4048 var el = this.getEl();
4050 if (attr == 'scroll') {
4051 val = [ el.scrollLeft, el.scrollTop ];
4053 val = superclass.getAttribute.call(this, attr);
4059 proto.setAttribute = function(attr, val, unit) {
4060 var el = this.getEl();
4062 if (attr == 'scroll') {
4063 el.scrollLeft = val[0];
4064 el.scrollTop = val[1];
4066 superclass.setAttribute.call(this, attr, val, unit);
4072 * Ext JS Library 1.1.1
4073 * Copyright(c) 2006-2007, Ext JS, LLC.
4075 * Originally Released Under LGPL - original licence link has changed is not relivant.
4078 * <script type="text/javascript">
4082 // nasty IE9 hack - what a pile of crap that is..
4084 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4085 Range.prototype.createContextualFragment = function (html) {
4086 var doc = window.document;
4087 var container = doc.createElement("div");
4088 container.innerHTML = html;
4089 var frag = doc.createDocumentFragment(), n;
4090 while ((n = container.firstChild)) {
4091 frag.appendChild(n);
4098 * @class Roo.DomHelper
4099 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4100 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4103 Roo.DomHelper = function(){
4104 var tempTableEl = null;
4105 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4106 var tableRe = /^table|tbody|tr|td$/i;
4108 // build as innerHTML where available
4110 var createHtml = function(o){
4111 if(typeof o == 'string'){
4120 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4121 if(attr == "style"){
4123 if(typeof s == "function"){
4126 if(typeof s == "string"){
4127 b += ' style="' + s + '"';
4128 }else if(typeof s == "object"){
4131 if(typeof s[key] != "function"){
4132 b += key + ":" + s[key] + ";";
4139 b += ' class="' + o["cls"] + '"';
4140 }else if(attr == "htmlFor"){
4141 b += ' for="' + o["htmlFor"] + '"';
4143 b += " " + attr + '="' + o[attr] + '"';
4147 if(emptyTags.test(o.tag)){
4151 var cn = o.children || o.cn;
4153 //http://bugs.kde.org/show_bug.cgi?id=71506
4154 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4155 for(var i = 0, len = cn.length; i < len; i++) {
4156 b += createHtml(cn[i], b);
4159 b += createHtml(cn, b);
4165 b += "</" + o.tag + ">";
4172 var createDom = function(o, parentNode){
4174 // defininition craeted..
4176 if (o.ns && o.ns != 'html') {
4178 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4179 xmlns[o.ns] = o.xmlns;
4182 if (typeof(xmlns[o.ns]) == 'undefined') {
4183 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4189 if (typeof(o) == 'string') {
4190 return parentNode.appendChild(document.createTextNode(o));
4192 o.tag = o.tag || div;
4193 if (o.ns && Roo.isIE) {
4195 o.tag = o.ns + ':' + o.tag;
4198 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4199 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4202 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4203 attr == "style" || typeof o[attr] == "function") continue;
4205 if(attr=="cls" && Roo.isIE){
4206 el.className = o["cls"];
4208 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4209 else el[attr] = o[attr];
4212 Roo.DomHelper.applyStyles(el, o.style);
4213 var cn = o.children || o.cn;
4215 //http://bugs.kde.org/show_bug.cgi?id=71506
4216 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4217 for(var i = 0, len = cn.length; i < len; i++) {
4218 createDom(cn[i], el);
4225 el.innerHTML = o.html;
4228 parentNode.appendChild(el);
4233 var ieTable = function(depth, s, h, e){
4234 tempTableEl.innerHTML = [s, h, e].join('');
4235 var i = -1, el = tempTableEl;
4242 // kill repeat to save bytes
4246 tbe = '</tbody>'+te,
4252 * Nasty code for IE's broken table implementation
4254 var insertIntoTable = function(tag, where, el, html){
4256 tempTableEl = document.createElement('div');
4261 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4264 if(where == 'beforebegin'){
4268 before = el.nextSibling;
4271 node = ieTable(4, trs, html, tre);
4273 else if(tag == 'tr'){
4274 if(where == 'beforebegin'){
4277 node = ieTable(3, tbs, html, tbe);
4278 } else if(where == 'afterend'){
4279 before = el.nextSibling;
4281 node = ieTable(3, tbs, html, tbe);
4282 } else{ // INTO a TR
4283 if(where == 'afterbegin'){
4284 before = el.firstChild;
4286 node = ieTable(4, trs, html, tre);
4288 } else if(tag == 'tbody'){
4289 if(where == 'beforebegin'){
4292 node = ieTable(2, ts, html, te);
4293 } else if(where == 'afterend'){
4294 before = el.nextSibling;
4296 node = ieTable(2, ts, html, te);
4298 if(where == 'afterbegin'){
4299 before = el.firstChild;
4301 node = ieTable(3, tbs, html, tbe);
4304 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4307 if(where == 'afterbegin'){
4308 before = el.firstChild;
4310 node = ieTable(2, ts, html, te);
4312 el.insertBefore(node, before);
4317 /** True to force the use of DOM instead of html fragments @type Boolean */
4321 * Returns the markup for the passed Element(s) config
4322 * @param {Object} o The Dom object spec (and children)
4325 markup : function(o){
4326 return createHtml(o);
4330 * Applies a style specification to an element
4331 * @param {String/HTMLElement} el The element to apply styles to
4332 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4333 * a function which returns such a specification.
4335 applyStyles : function(el, styles){
4338 if(typeof styles == "string"){
4339 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4341 while ((matches = re.exec(styles)) != null){
4342 el.setStyle(matches[1], matches[2]);
4344 }else if (typeof styles == "object"){
4345 for (var style in styles){
4346 el.setStyle(style, styles[style]);
4348 }else if (typeof styles == "function"){
4349 Roo.DomHelper.applyStyles(el, styles.call());
4355 * Inserts an HTML fragment into the Dom
4356 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4357 * @param {HTMLElement} el The context element
4358 * @param {String} html The HTML fragmenet
4359 * @return {HTMLElement} The new node
4361 insertHtml : function(where, el, html){
4362 where = where.toLowerCase();
4363 if(el.insertAdjacentHTML){
4364 if(tableRe.test(el.tagName)){
4366 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4372 el.insertAdjacentHTML('BeforeBegin', html);
4373 return el.previousSibling;
4375 el.insertAdjacentHTML('AfterBegin', html);
4376 return el.firstChild;
4378 el.insertAdjacentHTML('BeforeEnd', html);
4379 return el.lastChild;
4381 el.insertAdjacentHTML('AfterEnd', html);
4382 return el.nextSibling;
4384 throw 'Illegal insertion point -> "' + where + '"';
4386 var range = el.ownerDocument.createRange();
4390 range.setStartBefore(el);
4391 frag = range.createContextualFragment(html);
4392 el.parentNode.insertBefore(frag, el);
4393 return el.previousSibling;
4396 range.setStartBefore(el.firstChild);
4397 frag = range.createContextualFragment(html);
4398 el.insertBefore(frag, el.firstChild);
4399 return el.firstChild;
4401 el.innerHTML = html;
4402 return el.firstChild;
4406 range.setStartAfter(el.lastChild);
4407 frag = range.createContextualFragment(html);
4408 el.appendChild(frag);
4409 return el.lastChild;
4411 el.innerHTML = html;
4412 return el.lastChild;
4415 range.setStartAfter(el);
4416 frag = range.createContextualFragment(html);
4417 el.parentNode.insertBefore(frag, el.nextSibling);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4424 * Creates new Dom element(s) and inserts them before el
4425 * @param {String/HTMLElement/Element} el The context element
4426 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4427 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4428 * @return {HTMLElement/Roo.Element} The new node
4430 insertBefore : function(el, o, returnElement){
4431 return this.doInsert(el, o, returnElement, "beforeBegin");
4435 * Creates new Dom element(s) and inserts them after el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object} o The Dom object spec (and children)
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertAfter : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4446 * Creates new Dom element(s) and inserts them as the first child of el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertFirst : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterBegin");
4457 doInsert : function(el, o, returnElement, pos, sibling){
4458 el = Roo.getDom(el);
4460 if(this.useDom || o.ns){
4461 newNode = createDom(o, null);
4462 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4464 var html = createHtml(o);
4465 newNode = this.insertHtml(pos, el, html);
4467 return returnElement ? Roo.get(newNode, true) : newNode;
4471 * Creates new Dom element(s) and appends them to el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 append : function(el, o, returnElement){
4478 el = Roo.getDom(el);
4480 if(this.useDom || o.ns){
4481 newNode = createDom(o, null);
4482 el.appendChild(newNode);
4484 var html = createHtml(o);
4485 newNode = this.insertHtml("beforeEnd", el, html);
4487 return returnElement ? Roo.get(newNode, true) : newNode;
4491 * Creates new Dom element(s) and overwrites the contents of el with them
4492 * @param {String/HTMLElement/Element} el The context element
4493 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495 * @return {HTMLElement/Roo.Element} The new node
4497 overwrite : function(el, o, returnElement){
4498 el = Roo.getDom(el);
4501 while (el.childNodes.length) {
4502 el.removeChild(el.firstChild);
4506 el.innerHTML = createHtml(o);
4509 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4513 * Creates a new Roo.DomHelper.Template from the Dom object spec
4514 * @param {Object} o The Dom object spec (and children)
4515 * @return {Roo.DomHelper.Template} The new template
4517 createTemplate : function(o){
4518 var html = createHtml(o);
4519 return new Roo.Template(html);
4525 * Ext JS Library 1.1.1
4526 * Copyright(c) 2006-2007, Ext JS, LLC.
4528 * Originally Released Under LGPL - original licence link has changed is not relivant.
4531 * <script type="text/javascript">
4535 * @class Roo.Template
4536 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4537 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4540 var t = new Roo.Template({
4541 html : '<div name="{id}">' +
4542 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4544 myformat: function (value, allValues) {
4545 return 'XX' + value;
4548 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4550 * For more information see this blog post with examples:
4551 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4552 - Create Elements using DOM, HTML fragments and Templates</a>.
4554 * @param {Object} cfg - Configuration object.
4556 Roo.Template = function(cfg){
4558 if(cfg instanceof Array){
4560 }else if(arguments.length > 1){
4561 cfg = Array.prototype.join.call(arguments, "");
4565 if (typeof(cfg) == 'object') {
4576 Roo.Template.prototype = {
4579 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4580 * it should be fixed so that template is observable...
4584 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4588 * Returns an HTML fragment of this template with the specified values applied.
4589 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4590 * @return {String} The HTML fragment
4592 applyTemplate : function(values){
4596 return this.compiled(values);
4598 var useF = this.disableFormats !== true;
4599 var fm = Roo.util.Format, tpl = this;
4600 var fn = function(m, name, format, args){
4602 if(format.substr(0, 5) == "this."){
4603 return tpl.call(format.substr(5), values[name], values);
4606 // quoted values are required for strings in compiled templates,
4607 // but for non compiled we need to strip them
4608 // quoted reversed for jsmin
4609 var re = /^\s*['"](.*)["']\s*$/;
4610 args = args.split(',');
4611 for(var i = 0, len = args.length; i < len; i++){
4612 args[i] = args[i].replace(re, "$1");
4614 args = [values[name]].concat(args);
4616 args = [values[name]];
4618 return fm[format].apply(fm, args);
4621 return values[name] !== undefined ? values[name] : "";
4624 return this.html.replace(this.re, fn);
4642 this.loading = true;
4643 this.compiled = false;
4645 var cx = new Roo.data.Connection();
4649 success : function (response) {
4651 _t.html = response.responseText;
4655 failure : function(response) {
4656 Roo.log("Template failed to load from " + _t.url);
4663 * Sets the HTML used as the template and optionally compiles it.
4664 * @param {String} html
4665 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4666 * @return {Roo.Template} this
4668 set : function(html, compile){
4670 this.compiled = null;
4678 * True to disable format functions (defaults to false)
4681 disableFormats : false,
4684 * The regular expression used to match template variables
4688 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4691 * Compiles the template into an internal function, eliminating the RegEx overhead.
4692 * @return {Roo.Template} this
4694 compile : function(){
4695 var fm = Roo.util.Format;
4696 var useF = this.disableFormats !== true;
4697 var sep = Roo.isGecko ? "+" : ",";
4698 var fn = function(m, name, format, args){
4700 args = args ? ',' + args : "";
4701 if(format.substr(0, 5) != "this."){
4702 format = "fm." + format + '(';
4704 format = 'this.call("'+ format.substr(5) + '", ';
4708 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4710 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4713 // branched to use + in gecko and [].join() in others
4715 body = "this.compiled = function(values){ return '" +
4716 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4719 body = ["this.compiled = function(values){ return ['"];
4720 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4721 body.push("'].join('');};");
4722 body = body.join('');
4732 // private function used to call members
4733 call : function(fnName, value, allValues){
4734 return this[fnName](value, allValues);
4738 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4739 * @param {String/HTMLElement/Roo.Element} el The context element
4740 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4741 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4742 * @return {HTMLElement/Roo.Element} The new node or Element
4744 insertFirst: function(el, values, returnElement){
4745 return this.doInsert('afterBegin', el, values, returnElement);
4749 * Applies the supplied values to the template and inserts the new node(s) before el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertBefore: function(el, values, returnElement){
4756 return this.doInsert('beforeBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) after el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertAfter : function(el, values, returnElement){
4767 return this.doInsert('afterEnd', el, values, returnElement);
4771 * Applies the supplied values to the template and appends the new node(s) to el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 append : function(el, values, returnElement){
4778 return this.doInsert('beforeEnd', el, values, returnElement);
4781 doInsert : function(where, el, values, returnEl){
4782 el = Roo.getDom(el);
4783 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4784 return returnEl ? Roo.get(newNode, true) : newNode;
4788 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4789 * @param {String/HTMLElement/Roo.Element} el The context element
4790 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4791 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4792 * @return {HTMLElement/Roo.Element} The new node or Element
4794 overwrite : function(el, values, returnElement){
4795 el = Roo.getDom(el);
4796 el.innerHTML = this.applyTemplate(values);
4797 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4801 * Alias for {@link #applyTemplate}
4804 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4807 Roo.DomHelper.Template = Roo.Template;
4810 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4811 * @param {String/HTMLElement} el A DOM element or its id
4812 * @returns {Roo.Template} The created template
4815 Roo.Template.from = function(el){
4816 el = Roo.getDom(el);
4817 return new Roo.Template(el.value || el.innerHTML);
4820 * Ext JS Library 1.1.1
4821 * Copyright(c) 2006-2007, Ext JS, LLC.
4823 * Originally Released Under LGPL - original licence link has changed is not relivant.
4826 * <script type="text/javascript">
4831 * This is code is also distributed under MIT license for use
4832 * with jQuery and prototype JavaScript libraries.
4835 * @class Roo.DomQuery
4836 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4838 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4841 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4843 <h4>Element Selectors:</h4>
4845 <li> <b>*</b> any element</li>
4846 <li> <b>E</b> an element with the tag E</li>
4847 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4848 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4849 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4850 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4852 <h4>Attribute Selectors:</h4>
4853 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4855 <li> <b>E[foo]</b> has an attribute "foo"</li>
4856 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4857 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4858 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4859 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4860 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4861 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4863 <h4>Pseudo Classes:</h4>
4865 <li> <b>E:first-child</b> E is the first child of its parent</li>
4866 <li> <b>E:last-child</b> E is the last child of its parent</li>
4867 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4868 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4869 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4870 <li> <b>E:only-child</b> E is the only child of its parent</li>
4871 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4872 <li> <b>E:first</b> the first E in the resultset</li>
4873 <li> <b>E:last</b> the last E in the resultset</li>
4874 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4875 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4876 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4877 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4878 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4879 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4880 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4881 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4882 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4884 <h4>CSS Value Selectors:</h4>
4886 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4887 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4888 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4889 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4890 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4891 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4895 Roo.DomQuery = function(){
4896 var cache = {}, simpleCache = {}, valueCache = {};
4897 var nonSpace = /\S/;
4898 var trimRe = /^\s+|\s+$/g;
4899 var tplRe = /\{(\d+)\}/g;
4900 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4901 var tagTokenRe = /^(#)?([\w-\*]+)/;
4902 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4904 function child(p, index){
4906 var n = p.firstChild;
4908 if(n.nodeType == 1){
4919 while((n = n.nextSibling) && n.nodeType != 1);
4924 while((n = n.previousSibling) && n.nodeType != 1);
4928 function children(d){
4929 var n = d.firstChild, ni = -1;
4931 var nx = n.nextSibling;
4932 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4942 function byClassName(c, a, v){
4946 var r = [], ri = -1, cn;
4947 for(var i = 0, ci; ci = c[i]; i++){
4948 if((' '+ci.className+' ').indexOf(v) != -1){
4955 function attrValue(n, attr){
4956 if(!n.tagName && typeof n.length != "undefined"){
4965 if(attr == "class" || attr == "className"){
4968 return n.getAttribute(attr) || n[attr];
4972 function getNodes(ns, mode, tagName){
4973 var result = [], ri = -1, cs;
4977 tagName = tagName || "*";
4978 if(typeof ns.getElementsByTagName != "undefined"){
4982 for(var i = 0, ni; ni = ns[i]; i++){
4983 cs = ni.getElementsByTagName(tagName);
4984 for(var j = 0, ci; ci = cs[j]; j++){
4988 }else if(mode == "/" || mode == ">"){
4989 var utag = tagName.toUpperCase();
4990 for(var i = 0, ni, cn; ni = ns[i]; i++){
4991 cn = ni.children || ni.childNodes;
4992 for(var j = 0, cj; cj = cn[j]; j++){
4993 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4998 }else if(mode == "+"){
4999 var utag = tagName.toUpperCase();
5000 for(var i = 0, n; n = ns[i]; i++){
5001 while((n = n.nextSibling) && n.nodeType != 1);
5002 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5006 }else if(mode == "~"){
5007 for(var i = 0, n; n = ns[i]; i++){
5008 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5017 function concat(a, b){
5021 for(var i = 0, l = b.length; i < l; i++){
5027 function byTag(cs, tagName){
5028 if(cs.tagName || cs == document){
5034 var r = [], ri = -1;
5035 tagName = tagName.toLowerCase();
5036 for(var i = 0, ci; ci = cs[i]; i++){
5037 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5044 function byId(cs, attr, id){
5045 if(cs.tagName || cs == document){
5051 var r = [], ri = -1;
5052 for(var i = 0,ci; ci = cs[i]; i++){
5053 if(ci && ci.id == id){
5061 function byAttribute(cs, attr, value, op, custom){
5062 var r = [], ri = -1, st = custom=="{";
5063 var f = Roo.DomQuery.operators[op];
5064 for(var i = 0, ci; ci = cs[i]; i++){
5067 a = Roo.DomQuery.getStyle(ci, attr);
5069 else if(attr == "class" || attr == "className"){
5071 }else if(attr == "for"){
5073 }else if(attr == "href"){
5074 a = ci.getAttribute("href", 2);
5076 a = ci.getAttribute(attr);
5078 if((f && f(a, value)) || (!f && a)){
5085 function byPseudo(cs, name, value){
5086 return Roo.DomQuery.pseudos[name](cs, value);
5089 // This is for IE MSXML which does not support expandos.
5090 // IE runs the same speed using setAttribute, however FF slows way down
5091 // and Safari completely fails so they need to continue to use expandos.
5092 var isIE = window.ActiveXObject ? true : false;
5094 // this eval is stop the compressor from
5095 // renaming the variable to something shorter
5097 /** eval:var:batch */
5102 function nodupIEXml(cs){
5104 cs[0].setAttribute("_nodup", d);
5106 for(var i = 1, len = cs.length; i < len; i++){
5108 if(!c.getAttribute("_nodup") != d){
5109 c.setAttribute("_nodup", d);
5113 for(var i = 0, len = cs.length; i < len; i++){
5114 cs[i].removeAttribute("_nodup");
5123 var len = cs.length, c, i, r = cs, cj, ri = -1;
5124 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5127 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5128 return nodupIEXml(cs);
5132 for(i = 1; c = cs[i]; i++){
5137 for(var j = 0; j < i; j++){
5140 for(j = i+1; cj = cs[j]; j++){
5152 function quickDiffIEXml(c1, c2){
5154 for(var i = 0, len = c1.length; i < len; i++){
5155 c1[i].setAttribute("_qdiff", d);
5158 for(var i = 0, len = c2.length; i < len; i++){
5159 if(c2[i].getAttribute("_qdiff") != d){
5160 r[r.length] = c2[i];
5163 for(var i = 0, len = c1.length; i < len; i++){
5164 c1[i].removeAttribute("_qdiff");
5169 function quickDiff(c1, c2){
5170 var len1 = c1.length;
5174 if(isIE && c1[0].selectSingleNode){
5175 return quickDiffIEXml(c1, c2);
5178 for(var i = 0; i < len1; i++){
5182 for(var i = 0, len = c2.length; i < len; i++){
5183 if(c2[i]._qdiff != d){
5184 r[r.length] = c2[i];
5190 function quickId(ns, mode, root, id){
5192 var d = root.ownerDocument || root;
5193 return d.getElementById(id);
5195 ns = getNodes(ns, mode, "*");
5196 return byId(ns, null, id);
5200 getStyle : function(el, name){
5201 return Roo.fly(el).getStyle(name);
5204 * Compiles a selector/xpath query into a reusable function. The returned function
5205 * takes one parameter "root" (optional), which is the context node from where the query should start.
5206 * @param {String} selector The selector/xpath query
5207 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5208 * @return {Function}
5210 compile : function(path, type){
5211 type = type || "select";
5213 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5214 var q = path, mode, lq;
5215 var tk = Roo.DomQuery.matchers;
5216 var tklen = tk.length;
5219 // accept leading mode switch
5220 var lmode = q.match(modeRe);
5221 if(lmode && lmode[1]){
5222 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5223 q = q.replace(lmode[1], "");
5225 // strip leading slashes
5226 while(path.substr(0, 1)=="/"){
5227 path = path.substr(1);
5230 while(q && lq != q){
5232 var tm = q.match(tagTokenRe);
5233 if(type == "select"){
5236 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5238 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5240 q = q.replace(tm[0], "");
5241 }else if(q.substr(0, 1) != '@'){
5242 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5247 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5254 while(!(mm = q.match(modeRe))){
5255 var matched = false;
5256 for(var j = 0; j < tklen; j++){
5258 var m = q.match(t.re);
5260 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5263 q = q.replace(m[0], "");
5268 // prevent infinite loop on bad selector
5270 throw 'Error parsing selector, parsing failed at "' + q + '"';
5274 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5275 q = q.replace(mm[1], "");
5278 fn[fn.length] = "return nodup(n);\n}";
5281 * list of variables that need from compression as they are used by eval.
5291 * eval:var:byClassName
5293 * eval:var:byAttribute
5294 * eval:var:attrValue
5302 * Selects a group of elements.
5303 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5304 * @param {Node} root (optional) The start of the query (defaults to document).
5307 select : function(path, root, type){
5308 if(!root || root == document){
5311 if(typeof root == "string"){
5312 root = document.getElementById(root);
5314 var paths = path.split(",");
5316 for(var i = 0, len = paths.length; i < len; i++){
5317 var p = paths[i].replace(trimRe, "");
5319 cache[p] = Roo.DomQuery.compile(p);
5321 throw p + " is not a valid selector";
5324 var result = cache[p](root);
5325 if(result && result != document){
5326 results = results.concat(result);
5329 if(paths.length > 1){
5330 return nodup(results);
5336 * Selects a single element.
5337 * @param {String} selector The selector/xpath query
5338 * @param {Node} root (optional) The start of the query (defaults to document).
5341 selectNode : function(path, root){
5342 return Roo.DomQuery.select(path, root)[0];
5346 * Selects the value of a node, optionally replacing null with the defaultValue.
5347 * @param {String} selector The selector/xpath query
5348 * @param {Node} root (optional) The start of the query (defaults to document).
5349 * @param {String} defaultValue
5351 selectValue : function(path, root, defaultValue){
5352 path = path.replace(trimRe, "");
5353 if(!valueCache[path]){
5354 valueCache[path] = Roo.DomQuery.compile(path, "select");
5356 var n = valueCache[path](root);
5357 n = n[0] ? n[0] : n;
5358 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5359 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5363 * Selects the value of a node, parsing integers and floats.
5364 * @param {String} selector The selector/xpath query
5365 * @param {Node} root (optional) The start of the query (defaults to document).
5366 * @param {Number} defaultValue
5369 selectNumber : function(path, root, defaultValue){
5370 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5371 return parseFloat(v);
5375 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5376 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5377 * @param {String} selector The simple selector to test
5380 is : function(el, ss){
5381 if(typeof el == "string"){
5382 el = document.getElementById(el);
5384 var isArray = (el instanceof Array);
5385 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5386 return isArray ? (result.length == el.length) : (result.length > 0);
5390 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5391 * @param {Array} el An array of elements to filter
5392 * @param {String} selector The simple selector to test
5393 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5394 * the selector instead of the ones that match
5397 filter : function(els, ss, nonMatches){
5398 ss = ss.replace(trimRe, "");
5399 if(!simpleCache[ss]){
5400 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5402 var result = simpleCache[ss](els);
5403 return nonMatches ? quickDiff(result, els) : result;
5407 * Collection of matching regular expressions and code snippets.
5411 select: 'n = byClassName(n, null, " {1} ");'
5413 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5414 select: 'n = byPseudo(n, "{1}", "{2}");'
5416 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5417 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5420 select: 'n = byId(n, null, "{1}");'
5423 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5428 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5429 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5432 "=" : function(a, v){
5435 "!=" : function(a, v){
5438 "^=" : function(a, v){
5439 return a && a.substr(0, v.length) == v;
5441 "$=" : function(a, v){
5442 return a && a.substr(a.length-v.length) == v;
5444 "*=" : function(a, v){
5445 return a && a.indexOf(v) !== -1;
5447 "%=" : function(a, v){
5448 return (a % v) == 0;
5450 "|=" : function(a, v){
5451 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5453 "~=" : function(a, v){
5454 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5459 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5460 * and the argument (if any) supplied in the selector.
5463 "first-child" : function(c){
5464 var r = [], ri = -1, n;
5465 for(var i = 0, ci; ci = n = c[i]; i++){
5466 while((n = n.previousSibling) && n.nodeType != 1);
5474 "last-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.nextSibling) && n.nodeType != 1);
5485 "nth-child" : function(c, a) {
5486 var r = [], ri = -1;
5487 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5488 var f = (m[1] || 1) - 0, l = m[2] - 0;
5489 for(var i = 0, n; n = c[i]; i++){
5490 var pn = n.parentNode;
5491 if (batch != pn._batch) {
5493 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5494 if(cn.nodeType == 1){
5501 if (l == 0 || n.nodeIndex == l){
5504 } else if ((n.nodeIndex + l) % f == 0){
5512 "only-child" : function(c){
5513 var r = [], ri = -1;;
5514 for(var i = 0, ci; ci = c[i]; i++){
5515 if(!prev(ci) && !next(ci)){
5522 "empty" : function(c){
5523 var r = [], ri = -1;
5524 for(var i = 0, ci; ci = c[i]; i++){
5525 var cns = ci.childNodes, j = 0, cn, empty = true;
5528 if(cn.nodeType == 1 || cn.nodeType == 3){
5540 "contains" : function(c, v){
5541 var r = [], ri = -1;
5542 for(var i = 0, ci; ci = c[i]; i++){
5543 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5550 "nodeValue" : function(c, v){
5551 var r = [], ri = -1;
5552 for(var i = 0, ci; ci = c[i]; i++){
5553 if(ci.firstChild && ci.firstChild.nodeValue == v){
5560 "checked" : function(c){
5561 var r = [], ri = -1;
5562 for(var i = 0, ci; ci = c[i]; i++){
5563 if(ci.checked == true){
5570 "not" : function(c, ss){
5571 return Roo.DomQuery.filter(c, ss, true);
5574 "odd" : function(c){
5575 return this["nth-child"](c, "odd");
5578 "even" : function(c){
5579 return this["nth-child"](c, "even");
5582 "nth" : function(c, a){
5583 return c[a-1] || [];
5586 "first" : function(c){
5590 "last" : function(c){
5591 return c[c.length-1] || [];
5594 "has" : function(c, ss){
5595 var s = Roo.DomQuery.select;
5596 var r = [], ri = -1;
5597 for(var i = 0, ci; ci = c[i]; i++){
5598 if(s(ss, ci).length > 0){
5605 "next" : function(c, ss){
5606 var is = Roo.DomQuery.is;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5617 "prev" : function(c, ss){
5618 var is = Roo.DomQuery.is;
5619 var r = [], ri = -1;
5620 for(var i = 0, ci; ci = c[i]; i++){
5633 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5634 * @param {String} path The selector/xpath query
5635 * @param {Node} root (optional) The start of the query (defaults to document).
5640 Roo.query = Roo.DomQuery.select;
5643 * Ext JS Library 1.1.1
5644 * Copyright(c) 2006-2007, Ext JS, LLC.
5646 * Originally Released Under LGPL - original licence link has changed is not relivant.
5649 * <script type="text/javascript">
5653 * @class Roo.util.Observable
5654 * Base class that provides a common interface for publishing events. Subclasses are expected to
5655 * to have a property "events" with all the events defined.<br>
5658 Employee = function(name){
5665 Roo.extend(Employee, Roo.util.Observable);
5667 * @param {Object} config properties to use (incuding events / listeners)
5670 Roo.util.Observable = function(cfg){
5673 this.addEvents(cfg.events || {});
5675 delete cfg.events; // make sure
5678 Roo.apply(this, cfg);
5681 this.on(this.listeners);
5682 delete this.listeners;
5685 Roo.util.Observable.prototype = {
5687 * @cfg {Object} listeners list of events and functions to call for this object,
5691 'click' : function(e) {
5701 * Fires the specified event with the passed parameters (minus the event name).
5702 * @param {String} eventName
5703 * @param {Object...} args Variable number of parameters are passed to handlers
5704 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5706 fireEvent : function(){
5707 var ce = this.events[arguments[0].toLowerCase()];
5708 if(typeof ce == "object"){
5709 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5716 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5719 * Appends an event handler to this component
5720 * @param {String} eventName The type of event to listen for
5721 * @param {Function} handler The method the event invokes
5722 * @param {Object} scope (optional) The scope in which to execute the handler
5723 * function. The handler function's "this" context.
5724 * @param {Object} options (optional) An object containing handler configuration
5725 * properties. This may contain any of the following properties:<ul>
5726 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5727 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5728 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5729 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5730 * by the specified number of milliseconds. If the event fires again within that time, the original
5731 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5734 * <b>Combining Options</b><br>
5735 * Using the options argument, it is possible to combine different types of listeners:<br>
5737 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5739 el.on('click', this.onClick, this, {
5746 * <b>Attaching multiple handlers in 1 call</b><br>
5747 * The method also allows for a single argument to be passed which is a config object containing properties
5748 * which specify multiple handlers.
5757 fn: this.onMouseOver,
5761 fn: this.onMouseOut,
5767 * Or a shorthand syntax which passes the same scope object to all handlers:
5770 'click': this.onClick,
5771 'mouseover': this.onMouseOver,
5772 'mouseout': this.onMouseOut,
5777 addListener : function(eventName, fn, scope, o){
5778 if(typeof eventName == "object"){
5781 if(this.filterOptRe.test(e)){
5784 if(typeof o[e] == "function"){
5786 this.addListener(e, o[e], o.scope, o);
5788 // individual options
5789 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5794 o = (!o || typeof o == "boolean") ? {} : o;
5795 eventName = eventName.toLowerCase();
5796 var ce = this.events[eventName] || true;
5797 if(typeof ce == "boolean"){
5798 ce = new Roo.util.Event(this, eventName);
5799 this.events[eventName] = ce;
5801 ce.addListener(fn, scope, o);
5805 * Removes a listener
5806 * @param {String} eventName The type of event to listen for
5807 * @param {Function} handler The handler to remove
5808 * @param {Object} scope (optional) The scope (this object) for the handler
5810 removeListener : function(eventName, fn, scope){
5811 var ce = this.events[eventName.toLowerCase()];
5812 if(typeof ce == "object"){
5813 ce.removeListener(fn, scope);
5818 * Removes all listeners for this object
5820 purgeListeners : function(){
5821 for(var evt in this.events){
5822 if(typeof this.events[evt] == "object"){
5823 this.events[evt].clearListeners();
5828 relayEvents : function(o, events){
5829 var createHandler = function(ename){
5831 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5834 for(var i = 0, len = events.length; i < len; i++){
5835 var ename = events[i];
5836 if(!this.events[ename]){ this.events[ename] = true; };
5837 o.on(ename, createHandler(ename), this);
5842 * Used to define events on this Observable
5843 * @param {Object} object The object with the events defined
5845 addEvents : function(o){
5849 Roo.applyIf(this.events, o);
5853 * Checks to see if this object has any listeners for a specified event
5854 * @param {String} eventName The name of the event to check for
5855 * @return {Boolean} True if the event is being listened for, else false
5857 hasListener : function(eventName){
5858 var e = this.events[eventName];
5859 return typeof e == "object" && e.listeners.length > 0;
5863 * Appends an event handler to this element (shorthand for addListener)
5864 * @param {String} eventName The type of event to listen for
5865 * @param {Function} handler The method the event invokes
5866 * @param {Object} scope (optional) The scope in which to execute the handler
5867 * function. The handler function's "this" context.
5868 * @param {Object} options (optional)
5871 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5873 * Removes a listener (shorthand for removeListener)
5874 * @param {String} eventName The type of event to listen for
5875 * @param {Function} handler The handler to remove
5876 * @param {Object} scope (optional) The scope (this object) for the handler
5879 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5882 * Starts capture on the specified Observable. All events will be passed
5883 * to the supplied function with the event name + standard signature of the event
5884 * <b>before</b> the event is fired. If the supplied function returns false,
5885 * the event will not fire.
5886 * @param {Observable} o The Observable to capture
5887 * @param {Function} fn The function to call
5888 * @param {Object} scope (optional) The scope (this object) for the fn
5891 Roo.util.Observable.capture = function(o, fn, scope){
5892 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5896 * Removes <b>all</b> added captures from the Observable.
5897 * @param {Observable} o The Observable to release
5900 Roo.util.Observable.releaseCapture = function(o){
5901 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5906 var createBuffered = function(h, o, scope){
5907 var task = new Roo.util.DelayedTask();
5909 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5913 var createSingle = function(h, e, fn, scope){
5915 e.removeListener(fn, scope);
5916 return h.apply(scope, arguments);
5920 var createDelayed = function(h, o, scope){
5922 var args = Array.prototype.slice.call(arguments, 0);
5923 setTimeout(function(){
5924 h.apply(scope, args);
5929 Roo.util.Event = function(obj, name){
5932 this.listeners = [];
5935 Roo.util.Event.prototype = {
5936 addListener : function(fn, scope, options){
5937 var o = options || {};
5938 scope = scope || this.obj;
5939 if(!this.isListening(fn, scope)){
5940 var l = {fn: fn, scope: scope, options: o};
5943 h = createDelayed(h, o, scope);
5946 h = createSingle(h, this, fn, scope);
5949 h = createBuffered(h, o, scope);
5952 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5953 this.listeners.push(l);
5955 this.listeners = this.listeners.slice(0);
5956 this.listeners.push(l);
5961 findListener : function(fn, scope){
5962 scope = scope || this.obj;
5963 var ls = this.listeners;
5964 for(var i = 0, len = ls.length; i < len; i++){
5966 if(l.fn == fn && l.scope == scope){
5973 isListening : function(fn, scope){
5974 return this.findListener(fn, scope) != -1;
5977 removeListener : function(fn, scope){
5979 if((index = this.findListener(fn, scope)) != -1){
5981 this.listeners.splice(index, 1);
5983 this.listeners = this.listeners.slice(0);
5984 this.listeners.splice(index, 1);
5991 clearListeners : function(){
5992 this.listeners = [];
5996 var ls = this.listeners, scope, len = ls.length;
5999 var args = Array.prototype.slice.call(arguments, 0);
6000 for(var i = 0; i < len; i++){
6002 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6003 this.firing = false;
6007 this.firing = false;
6014 * Ext JS Library 1.1.1
6015 * Copyright(c) 2006-2007, Ext JS, LLC.
6017 * Originally Released Under LGPL - original licence link has changed is not relivant.
6020 * <script type="text/javascript">
6024 * @class Roo.EventManager
6025 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6026 * several useful events directly.
6027 * See {@link Roo.EventObject} for more details on normalized event objects.
6030 Roo.EventManager = function(){
6031 var docReadyEvent, docReadyProcId, docReadyState = false;
6032 var resizeEvent, resizeTask, textEvent, textSize;
6033 var E = Roo.lib.Event;
6034 var D = Roo.lib.Dom;
6037 var fireDocReady = function(){
6039 docReadyState = true;
6042 clearInterval(docReadyProcId);
6044 if(Roo.isGecko || Roo.isOpera) {
6045 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6048 var defer = document.getElementById("ie-deferred-loader");
6050 defer.onreadystatechange = null;
6051 defer.parentNode.removeChild(defer);
6055 docReadyEvent.fire();
6056 docReadyEvent.clearListeners();
6061 var initDocReady = function(){
6062 docReadyEvent = new Roo.util.Event();
6063 if(Roo.isGecko || Roo.isOpera) {
6064 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6066 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6067 var defer = document.getElementById("ie-deferred-loader");
6068 defer.onreadystatechange = function(){
6069 if(this.readyState == "complete"){
6073 }else if(Roo.isSafari){
6074 docReadyProcId = setInterval(function(){
6075 var rs = document.readyState;
6076 if(rs == "complete") {
6081 // no matter what, make sure it fires on load
6082 E.on(window, "load", fireDocReady);
6085 var createBuffered = function(h, o){
6086 var task = new Roo.util.DelayedTask(h);
6088 // create new event object impl so new events don't wipe out properties
6089 e = new Roo.EventObjectImpl(e);
6090 task.delay(o.buffer, h, null, [e]);
6094 var createSingle = function(h, el, ename, fn){
6096 Roo.EventManager.removeListener(el, ename, fn);
6101 var createDelayed = function(h, o){
6103 // create new event object impl so new events don't wipe out properties
6104 e = new Roo.EventObjectImpl(e);
6105 setTimeout(function(){
6111 var listen = function(element, ename, opt, fn, scope){
6112 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6113 fn = fn || o.fn; scope = scope || o.scope;
6114 var el = Roo.getDom(element);
6116 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6118 var h = function(e){
6119 e = Roo.EventObject.setEvent(e);
6122 t = e.getTarget(o.delegate, el);
6129 if(o.stopEvent === true){
6132 if(o.preventDefault === true){
6135 if(o.stopPropagation === true){
6136 e.stopPropagation();
6139 if(o.normalized === false){
6143 fn.call(scope || el, e, t, o);
6146 h = createDelayed(h, o);
6149 h = createSingle(h, el, ename, fn);
6152 h = createBuffered(h, o);
6154 fn._handlers = fn._handlers || [];
6155 fn._handlers.push([Roo.id(el), ename, h]);
6158 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6159 el.addEventListener("DOMMouseScroll", h, false);
6160 E.on(window, 'unload', function(){
6161 el.removeEventListener("DOMMouseScroll", h, false);
6164 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6165 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6170 var stopListening = function(el, ename, fn){
6171 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6173 for(var i = 0, len = hds.length; i < len; i++){
6175 if(h[0] == id && h[1] == ename){
6182 E.un(el, ename, hd);
6183 el = Roo.getDom(el);
6184 if(ename == "mousewheel" && el.addEventListener){
6185 el.removeEventListener("DOMMouseScroll", hd, false);
6187 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6188 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6192 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6199 * @scope Roo.EventManager
6204 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6205 * object with a Roo.EventObject
6206 * @param {Function} fn The method the event invokes
6207 * @param {Object} scope An object that becomes the scope of the handler
6208 * @param {boolean} override If true, the obj passed in becomes
6209 * the execution scope of the listener
6210 * @return {Function} The wrapped function
6213 wrap : function(fn, scope, override){
6215 Roo.EventObject.setEvent(e);
6216 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6221 * Appends an event handler to an element (shorthand for addListener)
6222 * @param {String/HTMLElement} element The html element or id to assign the
6223 * @param {String} eventName The type of event to listen for
6224 * @param {Function} handler The method the event invokes
6225 * @param {Object} scope (optional) The scope in which to execute the handler
6226 * function. The handler function's "this" context.
6227 * @param {Object} options (optional) An object containing handler configuration
6228 * properties. This may contain any of the following properties:<ul>
6229 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6230 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6231 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6232 * <li>preventDefault {Boolean} True to prevent the default action</li>
6233 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6234 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6235 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6236 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6237 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6238 * by the specified number of milliseconds. If the event fires again within that time, the original
6239 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6242 * <b>Combining Options</b><br>
6243 * Using the options argument, it is possible to combine different types of listeners:<br>
6245 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6247 el.on('click', this.onClick, this, {
6254 * <b>Attaching multiple handlers in 1 call</b><br>
6255 * The method also allows for a single argument to be passed which is a config object containing properties
6256 * which specify multiple handlers.
6266 fn: this.onMouseOver
6275 * Or a shorthand syntax:<br>
6278 'click' : this.onClick,
6279 'mouseover' : this.onMouseOver,
6280 'mouseout' : this.onMouseOut
6284 addListener : function(element, eventName, fn, scope, options){
6285 if(typeof eventName == "object"){
6291 if(typeof o[e] == "function"){
6293 listen(element, e, o, o[e], o.scope);
6295 // individual options
6296 listen(element, e, o[e]);
6301 return listen(element, eventName, options, fn, scope);
6305 * Removes an event handler
6307 * @param {String/HTMLElement} element The id or html element to remove the
6309 * @param {String} eventName The type of event
6310 * @param {Function} fn
6311 * @return {Boolean} True if a listener was actually removed
6313 removeListener : function(element, eventName, fn){
6314 return stopListening(element, eventName, fn);
6318 * Fires when the document is ready (before onload and before images are loaded). Can be
6319 * accessed shorthanded Roo.onReady().
6320 * @param {Function} fn The method the event invokes
6321 * @param {Object} scope An object that becomes the scope of the handler
6322 * @param {boolean} options
6324 onDocumentReady : function(fn, scope, options){
6325 if(docReadyState){ // if it already fired
6326 docReadyEvent.addListener(fn, scope, options);
6327 docReadyEvent.fire();
6328 docReadyEvent.clearListeners();
6334 docReadyEvent.addListener(fn, scope, options);
6338 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6339 * @param {Function} fn The method the event invokes
6340 * @param {Object} scope An object that becomes the scope of the handler
6341 * @param {boolean} options
6343 onWindowResize : function(fn, scope, options){
6345 resizeEvent = new Roo.util.Event();
6346 resizeTask = new Roo.util.DelayedTask(function(){
6347 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6349 E.on(window, "resize", function(){
6351 resizeTask.delay(50);
6353 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6357 resizeEvent.addListener(fn, scope, options);
6361 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6362 * @param {Function} fn The method the event invokes
6363 * @param {Object} scope An object that becomes the scope of the handler
6364 * @param {boolean} options
6366 onTextResize : function(fn, scope, options){
6368 textEvent = new Roo.util.Event();
6369 var textEl = new Roo.Element(document.createElement('div'));
6370 textEl.dom.className = 'x-text-resize';
6371 textEl.dom.innerHTML = 'X';
6372 textEl.appendTo(document.body);
6373 textSize = textEl.dom.offsetHeight;
6374 setInterval(function(){
6375 if(textEl.dom.offsetHeight != textSize){
6376 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6378 }, this.textResizeInterval);
6380 textEvent.addListener(fn, scope, options);
6384 * Removes the passed window resize listener.
6385 * @param {Function} fn The method the event invokes
6386 * @param {Object} scope The scope of handler
6388 removeResizeListener : function(fn, scope){
6390 resizeEvent.removeListener(fn, scope);
6395 fireResize : function(){
6397 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6401 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6405 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6407 textResizeInterval : 50
6412 * @scopeAlias pub=Roo.EventManager
6416 * Appends an event handler to an element (shorthand for addListener)
6417 * @param {String/HTMLElement} element The html element or id to assign the
6418 * @param {String} eventName The type of event to listen for
6419 * @param {Function} handler The method the event invokes
6420 * @param {Object} scope (optional) The scope in which to execute the handler
6421 * function. The handler function's "this" context.
6422 * @param {Object} options (optional) An object containing handler configuration
6423 * properties. This may contain any of the following properties:<ul>
6424 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6425 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6426 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6427 * <li>preventDefault {Boolean} True to prevent the default action</li>
6428 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6429 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6430 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6431 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6432 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6433 * by the specified number of milliseconds. If the event fires again within that time, the original
6434 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6437 * <b>Combining Options</b><br>
6438 * Using the options argument, it is possible to combine different types of listeners:<br>
6440 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6442 el.on('click', this.onClick, this, {
6449 * <b>Attaching multiple handlers in 1 call</b><br>
6450 * The method also allows for a single argument to be passed which is a config object containing properties
6451 * which specify multiple handlers.
6461 fn: this.onMouseOver
6470 * Or a shorthand syntax:<br>
6473 'click' : this.onClick,
6474 'mouseover' : this.onMouseOver,
6475 'mouseout' : this.onMouseOut
6479 pub.on = pub.addListener;
6480 pub.un = pub.removeListener;
6482 pub.stoppedMouseDownEvent = new Roo.util.Event();
6486 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6487 * @param {Function} fn The method the event invokes
6488 * @param {Object} scope An object that becomes the scope of the handler
6489 * @param {boolean} override If true, the obj passed in becomes
6490 * the execution scope of the listener
6494 Roo.onReady = Roo.EventManager.onDocumentReady;
6496 Roo.onReady(function(){
6497 var bd = Roo.get(document.body);
6502 : Roo.isGecko ? "roo-gecko"
6503 : Roo.isOpera ? "roo-opera"
6504 : Roo.isSafari ? "roo-safari" : ""];
6507 cls.push("roo-mac");
6510 cls.push("roo-linux");
6512 if(Roo.isBorderBox){
6513 cls.push('roo-border-box');
6515 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6516 var p = bd.dom.parentNode;
6518 p.className += ' roo-strict';
6521 bd.addClass(cls.join(' '));
6525 * @class Roo.EventObject
6526 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6527 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6530 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6532 var target = e.getTarget();
6535 var myDiv = Roo.get("myDiv");
6536 myDiv.on("click", handleClick);
6538 Roo.EventManager.on("myDiv", 'click', handleClick);
6539 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6543 Roo.EventObject = function(){
6545 var E = Roo.lib.Event;
6547 // safari keypress events for special keys return bad keycodes
6550 63235 : 39, // right
6553 63276 : 33, // page up
6554 63277 : 34, // page down
6555 63272 : 46, // delete
6560 // normalize button clicks
6561 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6562 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6564 Roo.EventObjectImpl = function(e){
6566 this.setEvent(e.browserEvent || e);
6569 Roo.EventObjectImpl.prototype = {
6571 * Used to fix doc tools.
6572 * @scope Roo.EventObject.prototype
6578 /** The normal browser event */
6579 browserEvent : null,
6580 /** The button pressed in a mouse event */
6582 /** True if the shift key was down during the event */
6584 /** True if the control key was down during the event */
6586 /** True if the alt key was down during the event */
6645 setEvent : function(e){
6646 if(e == this || (e && e.browserEvent)){ // already wrapped
6649 this.browserEvent = e;
6651 // normalize buttons
6652 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6653 if(e.type == 'click' && this.button == -1){
6657 this.shiftKey = e.shiftKey;
6658 // mac metaKey behaves like ctrlKey
6659 this.ctrlKey = e.ctrlKey || e.metaKey;
6660 this.altKey = e.altKey;
6661 // in getKey these will be normalized for the mac
6662 this.keyCode = e.keyCode;
6663 // keyup warnings on firefox.
6664 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6665 // cache the target for the delayed and or buffered events
6666 this.target = E.getTarget(e);
6668 this.xy = E.getXY(e);
6671 this.shiftKey = false;
6672 this.ctrlKey = false;
6673 this.altKey = false;
6683 * Stop the event (preventDefault and stopPropagation)
6685 stopEvent : function(){
6686 if(this.browserEvent){
6687 if(this.browserEvent.type == 'mousedown'){
6688 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6690 E.stopEvent(this.browserEvent);
6695 * Prevents the browsers default handling of the event.
6697 preventDefault : function(){
6698 if(this.browserEvent){
6699 E.preventDefault(this.browserEvent);
6704 isNavKeyPress : function(){
6705 var k = this.keyCode;
6706 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6707 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6710 isSpecialKey : function(){
6711 var k = this.keyCode;
6712 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6713 (k == 16) || (k == 17) ||
6714 (k >= 18 && k <= 20) ||
6715 (k >= 33 && k <= 35) ||
6716 (k >= 36 && k <= 39) ||
6717 (k >= 44 && k <= 45);
6720 * Cancels bubbling of the event.
6722 stopPropagation : function(){
6723 if(this.browserEvent){
6724 if(this.type == 'mousedown'){
6725 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6727 E.stopPropagation(this.browserEvent);
6732 * Gets the key code for the event.
6735 getCharCode : function(){
6736 return this.charCode || this.keyCode;
6740 * Returns a normalized keyCode for the event.
6741 * @return {Number} The key code
6743 getKey : function(){
6744 var k = this.keyCode || this.charCode;
6745 return Roo.isSafari ? (safariKeys[k] || k) : k;
6749 * Gets the x coordinate of the event.
6752 getPageX : function(){
6757 * Gets the y coordinate of the event.
6760 getPageY : function(){
6765 * Gets the time of the event.
6768 getTime : function(){
6769 if(this.browserEvent){
6770 return E.getTime(this.browserEvent);
6776 * Gets the page coordinates of the event.
6777 * @return {Array} The xy values like [x, y]
6784 * Gets the target for the event.
6785 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6786 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6787 search as a number or element (defaults to 10 || document.body)
6788 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6789 * @return {HTMLelement}
6791 getTarget : function(selector, maxDepth, returnEl){
6792 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6795 * Gets the related target.
6796 * @return {HTMLElement}
6798 getRelatedTarget : function(){
6799 if(this.browserEvent){
6800 return E.getRelatedTarget(this.browserEvent);
6806 * Normalizes mouse wheel delta across browsers
6807 * @return {Number} The delta
6809 getWheelDelta : function(){
6810 var e = this.browserEvent;
6812 if(e.wheelDelta){ /* IE/Opera. */
6813 delta = e.wheelDelta/120;
6814 }else if(e.detail){ /* Mozilla case. */
6815 delta = -e.detail/3;
6821 * Returns true if the control, meta, shift or alt key was pressed during this event.
6824 hasModifier : function(){
6825 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6829 * Returns true if the target of this event equals el or is a child of el
6830 * @param {String/HTMLElement/Element} el
6831 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6834 within : function(el, related){
6835 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6836 return t && Roo.fly(el).contains(t);
6839 getPoint : function(){
6840 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6844 return new Roo.EventObjectImpl();
6849 * Ext JS Library 1.1.1
6850 * Copyright(c) 2006-2007, Ext JS, LLC.
6852 * Originally Released Under LGPL - original licence link has changed is not relivant.
6855 * <script type="text/javascript">
6859 // was in Composite Element!??!?!
6862 var D = Roo.lib.Dom;
6863 var E = Roo.lib.Event;
6864 var A = Roo.lib.Anim;
6866 // local style camelizing for speed
6868 var camelRe = /(-[a-z])/gi;
6869 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6870 var view = document.defaultView;
6873 * @class Roo.Element
6874 * Represents an Element in the DOM.<br><br>
6877 var el = Roo.get("my-div");
6880 var el = getEl("my-div");
6882 // or with a DOM element
6883 var el = Roo.get(myDivElement);
6885 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6886 * each call instead of constructing a new one.<br><br>
6887 * <b>Animations</b><br />
6888 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6889 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6891 Option Default Description
6892 --------- -------- ---------------------------------------------
6893 duration .35 The duration of the animation in seconds
6894 easing easeOut The YUI easing method
6895 callback none A function to execute when the anim completes
6896 scope this The scope (this) of the callback function
6898 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6899 * manipulate the animation. Here's an example:
6901 var el = Roo.get("my-div");
6906 // default animation
6907 el.setWidth(100, true);
6909 // animation with some options set
6916 // using the "anim" property to get the Anim object
6922 el.setWidth(100, opt);
6924 if(opt.anim.isAnimated()){
6928 * <b> Composite (Collections of) Elements</b><br />
6929 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6930 * @constructor Create a new Element directly.
6931 * @param {String/HTMLElement} element
6932 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6934 Roo.Element = function(element, forceNew){
6935 var dom = typeof element == "string" ?
6936 document.getElementById(element) : element;
6937 if(!dom){ // invalid id/element
6941 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6942 return Roo.Element.cache[id];
6952 * The DOM element ID
6955 this.id = id || Roo.id(dom);
6958 var El = Roo.Element;
6962 * The element's default display mode (defaults to "")
6965 originalDisplay : "",
6969 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6974 * Sets the element's visibility mode. When setVisible() is called it
6975 * will use this to determine whether to set the visibility or the display property.
6976 * @param visMode Element.VISIBILITY or Element.DISPLAY
6977 * @return {Roo.Element} this
6979 setVisibilityMode : function(visMode){
6980 this.visibilityMode = visMode;
6984 * Convenience method for setVisibilityMode(Element.DISPLAY)
6985 * @param {String} display (optional) What to set display to when visible
6986 * @return {Roo.Element} this
6988 enableDisplayMode : function(display){
6989 this.setVisibilityMode(El.DISPLAY);
6990 if(typeof display != "undefined") this.originalDisplay = display;
6995 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
6996 * @param {String} selector The simple selector to test
6997 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6998 search as a number or element (defaults to 10 || document.body)
6999 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7000 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7002 findParent : function(simpleSelector, maxDepth, returnEl){
7003 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7004 maxDepth = maxDepth || 50;
7005 if(typeof maxDepth != "number"){
7006 stopEl = Roo.getDom(maxDepth);
7009 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7010 if(dq.is(p, simpleSelector)){
7011 return returnEl ? Roo.get(p) : p;
7021 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7022 * @param {String} selector The simple selector to test
7023 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7024 search as a number or element (defaults to 10 || document.body)
7025 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7026 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7028 findParentNode : function(simpleSelector, maxDepth, returnEl){
7029 var p = Roo.fly(this.dom.parentNode, '_internal');
7030 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7034 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7035 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7036 * @param {String} selector The simple selector to test
7037 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7038 search as a number or element (defaults to 10 || document.body)
7039 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7041 up : function(simpleSelector, maxDepth){
7042 return this.findParentNode(simpleSelector, maxDepth, true);
7048 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7049 * @param {String} selector The simple selector to test
7050 * @return {Boolean} True if this element matches the selector, else false
7052 is : function(simpleSelector){
7053 return Roo.DomQuery.is(this.dom, simpleSelector);
7057 * Perform animation on this element.
7058 * @param {Object} args The YUI animation control args
7059 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7060 * @param {Function} onComplete (optional) Function to call when animation completes
7061 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7062 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7063 * @return {Roo.Element} this
7065 animate : function(args, duration, onComplete, easing, animType){
7066 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7071 * @private Internal animation call
7073 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7074 animType = animType || 'run';
7076 var anim = Roo.lib.Anim[animType](
7078 (opt.duration || defaultDur) || .35,
7079 (opt.easing || defaultEase) || 'easeOut',
7081 Roo.callback(cb, this);
7082 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7090 // private legacy anim prep
7091 preanim : function(a, i){
7092 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7096 * Removes worthless text nodes
7097 * @param {Boolean} forceReclean (optional) By default the element
7098 * keeps track if it has been cleaned already so
7099 * you can call this over and over. However, if you update the element and
7100 * need to force a reclean, you can pass true.
7102 clean : function(forceReclean){
7103 if(this.isCleaned && forceReclean !== true){
7107 var d = this.dom, n = d.firstChild, ni = -1;
7109 var nx = n.nextSibling;
7110 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7117 this.isCleaned = true;
7122 calcOffsetsTo : function(el){
7125 var restorePos = false;
7126 if(el.getStyle('position') == 'static'){
7127 el.position('relative');
7132 while(op && op != d && op.tagName != 'HTML'){
7135 op = op.offsetParent;
7138 el.position('static');
7144 * Scrolls this element into view within the passed container.
7145 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7146 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7147 * @return {Roo.Element} this
7149 scrollIntoView : function(container, hscroll){
7150 var c = Roo.getDom(container) || document.body;
7153 var o = this.calcOffsetsTo(c),
7156 b = t+el.offsetHeight,
7157 r = l+el.offsetWidth;
7159 var ch = c.clientHeight;
7160 var ct = parseInt(c.scrollTop, 10);
7161 var cl = parseInt(c.scrollLeft, 10);
7163 var cr = cl + c.clientWidth;
7171 if(hscroll !== false){
7175 c.scrollLeft = r-c.clientWidth;
7182 scrollChildIntoView : function(child, hscroll){
7183 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7187 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7188 * the new height may not be available immediately.
7189 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7190 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7191 * @param {Function} onComplete (optional) Function to call when animation completes
7192 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7193 * @return {Roo.Element} this
7195 autoHeight : function(animate, duration, onComplete, easing){
7196 var oldHeight = this.getHeight();
7198 this.setHeight(1); // force clipping
7199 setTimeout(function(){
7200 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7202 this.setHeight(height);
7204 if(typeof onComplete == "function"){
7208 this.setHeight(oldHeight); // restore original height
7209 this.setHeight(height, animate, duration, function(){
7211 if(typeof onComplete == "function") onComplete();
7212 }.createDelegate(this), easing);
7214 }.createDelegate(this), 0);
7219 * Returns true if this element is an ancestor of the passed element
7220 * @param {HTMLElement/String} el The element to check
7221 * @return {Boolean} True if this element is an ancestor of el, else false
7223 contains : function(el){
7224 if(!el){return false;}
7225 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7229 * Checks whether the element is currently visible using both visibility and display properties.
7230 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7231 * @return {Boolean} True if the element is currently visible, else false
7233 isVisible : function(deep) {
7234 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7235 if(deep !== true || !vis){
7238 var p = this.dom.parentNode;
7239 while(p && p.tagName.toLowerCase() != "body"){
7240 if(!Roo.fly(p, '_isVisible').isVisible()){
7249 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7250 * @param {String} selector The CSS selector
7251 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7252 * @return {CompositeElement/CompositeElementLite} The composite element
7254 select : function(selector, unique){
7255 return El.select(selector, unique, this.dom);
7259 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7260 * @param {String} selector The CSS selector
7261 * @return {Array} An array of the matched nodes
7263 query : function(selector, unique){
7264 return Roo.DomQuery.select(selector, this.dom);
7268 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7269 * @param {String} selector The CSS selector
7270 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7271 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7273 child : function(selector, returnDom){
7274 var n = Roo.DomQuery.selectNode(selector, this.dom);
7275 return returnDom ? n : Roo.get(n);
7279 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 down : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7291 * @param {String} group The group the DD object is member of
7292 * @param {Object} config The DD config object
7293 * @param {Object} overrides An object containing methods to override/implement on the DD object
7294 * @return {Roo.dd.DD} The DD object
7296 initDD : function(group, config, overrides){
7297 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7298 return Roo.apply(dd, overrides);
7302 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7303 * @param {String} group The group the DDProxy object is member of
7304 * @param {Object} config The DDProxy config object
7305 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7306 * @return {Roo.dd.DDProxy} The DDProxy object
7308 initDDProxy : function(group, config, overrides){
7309 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7310 return Roo.apply(dd, overrides);
7314 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7315 * @param {String} group The group the DDTarget object is member of
7316 * @param {Object} config The DDTarget config object
7317 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7318 * @return {Roo.dd.DDTarget} The DDTarget object
7320 initDDTarget : function(group, config, overrides){
7321 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7322 return Roo.apply(dd, overrides);
7326 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7327 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7328 * @param {Boolean} visible Whether the element is visible
7329 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7330 * @return {Roo.Element} this
7332 setVisible : function(visible, animate){
7334 if(this.visibilityMode == El.DISPLAY){
7335 this.setDisplayed(visible);
7338 this.dom.style.visibility = visible ? "visible" : "hidden";
7341 // closure for composites
7343 var visMode = this.visibilityMode;
7345 this.setOpacity(.01);
7346 this.setVisible(true);
7348 this.anim({opacity: { to: (visible?1:0) }},
7349 this.preanim(arguments, 1),
7350 null, .35, 'easeIn', function(){
7352 if(visMode == El.DISPLAY){
7353 dom.style.display = "none";
7355 dom.style.visibility = "hidden";
7357 Roo.get(dom).setOpacity(1);
7365 * Returns true if display is not "none"
7368 isDisplayed : function() {
7369 return this.getStyle("display") != "none";
7373 * Toggles the element's visibility or display, depending on visibility mode.
7374 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7375 * @return {Roo.Element} this
7377 toggle : function(animate){
7378 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7383 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7384 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7385 * @return {Roo.Element} this
7387 setDisplayed : function(value) {
7388 if(typeof value == "boolean"){
7389 value = value ? this.originalDisplay : "none";
7391 this.setStyle("display", value);
7396 * Tries to focus the element. Any exceptions are caught and ignored.
7397 * @return {Roo.Element} this
7399 focus : function() {
7407 * Tries to blur the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7418 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7419 * @param {String/Array} className The CSS class to add, or an array of classes
7420 * @return {Roo.Element} this
7422 addClass : function(className){
7423 if(className instanceof Array){
7424 for(var i = 0, len = className.length; i < len; i++) {
7425 this.addClass(className[i]);
7428 if(className && !this.hasClass(className)){
7429 this.dom.className = this.dom.className + " " + className;
7436 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7437 * @param {String/Array} className The CSS class to add, or an array of classes
7438 * @return {Roo.Element} this
7440 radioClass : function(className){
7441 var siblings = this.dom.parentNode.childNodes;
7442 for(var i = 0; i < siblings.length; i++) {
7443 var s = siblings[i];
7444 if(s.nodeType == 1){
7445 Roo.get(s).removeClass(className);
7448 this.addClass(className);
7453 * Removes one or more CSS classes from the element.
7454 * @param {String/Array} className The CSS class to remove, or an array of classes
7455 * @return {Roo.Element} this
7457 removeClass : function(className){
7458 if(!className || !this.dom.className){
7461 if(className instanceof Array){
7462 for(var i = 0, len = className.length; i < len; i++) {
7463 this.removeClass(className[i]);
7466 if(this.hasClass(className)){
7467 var re = this.classReCache[className];
7469 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7470 this.classReCache[className] = re;
7472 this.dom.className =
7473 this.dom.className.replace(re, " ");
7483 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7484 * @param {String} className The CSS class to toggle
7485 * @return {Roo.Element} this
7487 toggleClass : function(className){
7488 if(this.hasClass(className)){
7489 this.removeClass(className);
7491 this.addClass(className);
7497 * Checks if the specified CSS class exists on this element's DOM node.
7498 * @param {String} className The CSS class to check for
7499 * @return {Boolean} True if the class exists, else false
7501 hasClass : function(className){
7502 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7506 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7507 * @param {String} oldClassName The CSS class to replace
7508 * @param {String} newClassName The replacement CSS class
7509 * @return {Roo.Element} this
7511 replaceClass : function(oldClassName, newClassName){
7512 this.removeClass(oldClassName);
7513 this.addClass(newClassName);
7518 * Returns an object with properties matching the styles requested.
7519 * For example, el.getStyles('color', 'font-size', 'width') might return
7520 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7521 * @param {String} style1 A style name
7522 * @param {String} style2 A style name
7523 * @param {String} etc.
7524 * @return {Object} The style object
7526 getStyles : function(){
7527 var a = arguments, len = a.length, r = {};
7528 for(var i = 0; i < len; i++){
7529 r[a[i]] = this.getStyle(a[i]);
7535 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7536 * @param {String} property The style property whose value is returned.
7537 * @return {String} The current value of the style property for this element.
7539 getStyle : function(){
7540 return view && view.getComputedStyle ?
7542 var el = this.dom, v, cs, camel;
7543 if(prop == 'float'){
7546 if(el.style && (v = el.style[prop])){
7549 if(cs = view.getComputedStyle(el, "")){
7550 if(!(camel = propCache[prop])){
7551 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7558 var el = this.dom, v, cs, camel;
7559 if(prop == 'opacity'){
7560 if(typeof el.style.filter == 'string'){
7561 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7563 var fv = parseFloat(m[1]);
7565 return fv ? fv / 100 : 0;
7570 }else if(prop == 'float'){
7571 prop = "styleFloat";
7573 if(!(camel = propCache[prop])){
7574 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7576 if(v = el.style[camel]){
7579 if(cs = el.currentStyle){
7587 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7588 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7589 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7590 * @return {Roo.Element} this
7592 setStyle : function(prop, value){
7593 if(typeof prop == "string"){
7595 if (prop == 'float') {
7596 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7601 if(!(camel = propCache[prop])){
7602 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7605 if(camel == 'opacity') {
7606 this.setOpacity(value);
7608 this.dom.style[camel] = value;
7611 for(var style in prop){
7612 if(typeof prop[style] != "function"){
7613 this.setStyle(style, prop[style]);
7621 * More flexible version of {@link #setStyle} for setting style properties.
7622 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7623 * a function which returns such a specification.
7624 * @return {Roo.Element} this
7626 applyStyles : function(style){
7627 Roo.DomHelper.applyStyles(this.dom, style);
7632 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7633 * @return {Number} The X position of the element
7636 return D.getX(this.dom);
7640 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7641 * @return {Number} The Y position of the element
7644 return D.getY(this.dom);
7648 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7649 * @return {Array} The XY position of the element
7652 return D.getXY(this.dom);
7656 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7657 * @param {Number} The X position of the element
7658 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7659 * @return {Roo.Element} this
7661 setX : function(x, animate){
7663 D.setX(this.dom, x);
7665 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7671 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7672 * @param {Number} The Y position of the element
7673 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7674 * @return {Roo.Element} this
7676 setY : function(y, animate){
7678 D.setY(this.dom, y);
7680 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7686 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7687 * @param {String} left The left CSS property value
7688 * @return {Roo.Element} this
7690 setLeft : function(left){
7691 this.setStyle("left", this.addUnits(left));
7696 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7697 * @param {String} top The top CSS property value
7698 * @return {Roo.Element} this
7700 setTop : function(top){
7701 this.setStyle("top", this.addUnits(top));
7706 * Sets the element's CSS right style.
7707 * @param {String} right The right CSS property value
7708 * @return {Roo.Element} this
7710 setRight : function(right){
7711 this.setStyle("right", this.addUnits(right));
7716 * Sets the element's CSS bottom style.
7717 * @param {String} bottom The bottom CSS property value
7718 * @return {Roo.Element} this
7720 setBottom : function(bottom){
7721 this.setStyle("bottom", this.addUnits(bottom));
7726 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7727 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7728 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7729 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730 * @return {Roo.Element} this
7732 setXY : function(pos, animate){
7734 D.setXY(this.dom, pos);
7736 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7742 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7743 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7744 * @param {Number} x X value for new position (coordinates are page-based)
7745 * @param {Number} y Y value for new position (coordinates are page-based)
7746 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747 * @return {Roo.Element} this
7749 setLocation : function(x, y, animate){
7750 this.setXY([x, y], this.preanim(arguments, 2));
7755 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7756 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7757 * @param {Number} x X value for new position (coordinates are page-based)
7758 * @param {Number} y Y value for new position (coordinates are page-based)
7759 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7760 * @return {Roo.Element} this
7762 moveTo : function(x, y, animate){
7763 this.setXY([x, y], this.preanim(arguments, 2));
7768 * Returns the region of the given element.
7769 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7770 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7772 getRegion : function(){
7773 return D.getRegion(this.dom);
7777 * Returns the offset height of the element
7778 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7779 * @return {Number} The element's height
7781 getHeight : function(contentHeight){
7782 var h = this.dom.offsetHeight || 0;
7783 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7787 * Returns the offset width of the element
7788 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7789 * @return {Number} The element's width
7791 getWidth : function(contentWidth){
7792 var w = this.dom.offsetWidth || 0;
7793 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7797 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7798 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7799 * if a height has not been set using CSS.
7802 getComputedHeight : function(){
7803 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7805 h = parseInt(this.getStyle('height'), 10) || 0;
7806 if(!this.isBorderBox()){
7807 h += this.getFrameWidth('tb');
7814 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7815 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7816 * if a width has not been set using CSS.
7819 getComputedWidth : function(){
7820 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7822 w = parseInt(this.getStyle('width'), 10) || 0;
7823 if(!this.isBorderBox()){
7824 w += this.getFrameWidth('lr');
7831 * Returns the size of the element.
7832 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7833 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7835 getSize : function(contentSize){
7836 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7840 * Returns the width and height of the viewport.
7841 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7843 getViewSize : function(){
7844 var d = this.dom, doc = document, aw = 0, ah = 0;
7845 if(d == doc || d == doc.body){
7846 return {width : D.getViewWidth(), height: D.getViewHeight()};
7849 width : d.clientWidth,
7850 height: d.clientHeight
7856 * Returns the value of the "value" attribute
7857 * @param {Boolean} asNumber true to parse the value as a number
7858 * @return {String/Number}
7860 getValue : function(asNumber){
7861 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7865 adjustWidth : function(width){
7866 if(typeof width == "number"){
7867 if(this.autoBoxAdjust && !this.isBorderBox()){
7868 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7878 adjustHeight : function(height){
7879 if(typeof height == "number"){
7880 if(this.autoBoxAdjust && !this.isBorderBox()){
7881 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7891 * Set the width of the element
7892 * @param {Number} width The new width
7893 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7894 * @return {Roo.Element} this
7896 setWidth : function(width, animate){
7897 width = this.adjustWidth(width);
7899 this.dom.style.width = this.addUnits(width);
7901 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7907 * Set the height of the element
7908 * @param {Number} height The new height
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setHeight : function(height, animate){
7913 height = this.adjustHeight(height);
7915 this.dom.style.height = this.addUnits(height);
7917 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7923 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7924 * @param {Number} width The new width
7925 * @param {Number} height The new height
7926 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7927 * @return {Roo.Element} this
7929 setSize : function(width, height, animate){
7930 if(typeof width == "object"){ // in case of object from getSize()
7931 height = width.height; width = width.width;
7933 width = this.adjustWidth(width); height = this.adjustHeight(height);
7935 this.dom.style.width = this.addUnits(width);
7936 this.dom.style.height = this.addUnits(height);
7938 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7944 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7945 * @param {Number} x X value for new position (coordinates are page-based)
7946 * @param {Number} y Y value for new position (coordinates are page-based)
7947 * @param {Number} width The new width
7948 * @param {Number} height The new height
7949 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7950 * @return {Roo.Element} this
7952 setBounds : function(x, y, width, height, animate){
7954 this.setSize(width, height);
7955 this.setLocation(x, y);
7957 width = this.adjustWidth(width); height = this.adjustHeight(height);
7958 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7959 this.preanim(arguments, 4), 'motion');
7965 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7966 * @param {Roo.lib.Region} region The region to fill
7967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7968 * @return {Roo.Element} this
7970 setRegion : function(region, animate){
7971 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7976 * Appends an event handler
7978 * @param {String} eventName The type of event to append
7979 * @param {Function} fn The method the event invokes
7980 * @param {Object} scope (optional) The scope (this object) of the fn
7981 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7983 addListener : function(eventName, fn, scope, options){
7985 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7990 * Removes an event handler from this element
7991 * @param {String} eventName the type of event to remove
7992 * @param {Function} fn the method the event invokes
7993 * @return {Roo.Element} this
7995 removeListener : function(eventName, fn){
7996 Roo.EventManager.removeListener(this.dom, eventName, fn);
8001 * Removes all previous added listeners from this element
8002 * @return {Roo.Element} this
8004 removeAllListeners : function(){
8005 E.purgeElement(this.dom);
8009 relayEvent : function(eventName, observable){
8010 this.on(eventName, function(e){
8011 observable.fireEvent(eventName, e);
8016 * Set the opacity of the element
8017 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8018 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8019 * @return {Roo.Element} this
8021 setOpacity : function(opacity, animate){
8023 var s = this.dom.style;
8026 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8027 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8029 s.opacity = opacity;
8032 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8038 * Gets the left X coordinate
8039 * @param {Boolean} local True to get the local css position instead of page coordinate
8042 getLeft : function(local){
8046 return parseInt(this.getStyle("left"), 10) || 0;
8051 * Gets the right X coordinate of the element (element X position + element width)
8052 * @param {Boolean} local True to get the local css position instead of page coordinate
8055 getRight : function(local){
8057 return this.getX() + this.getWidth();
8059 return (this.getLeft(true) + this.getWidth()) || 0;
8064 * Gets the top Y coordinate
8065 * @param {Boolean} local True to get the local css position instead of page coordinate
8068 getTop : function(local) {
8072 return parseInt(this.getStyle("top"), 10) || 0;
8077 * Gets the bottom Y coordinate of the element (element Y position + element height)
8078 * @param {Boolean} local True to get the local css position instead of page coordinate
8081 getBottom : function(local){
8083 return this.getY() + this.getHeight();
8085 return (this.getTop(true) + this.getHeight()) || 0;
8090 * Initializes positioning on this element. If a desired position is not passed, it will make the
8091 * the element positioned relative IF it is not already positioned.
8092 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8093 * @param {Number} zIndex (optional) The zIndex to apply
8094 * @param {Number} x (optional) Set the page X position
8095 * @param {Number} y (optional) Set the page Y position
8097 position : function(pos, zIndex, x, y){
8099 if(this.getStyle('position') == 'static'){
8100 this.setStyle('position', 'relative');
8103 this.setStyle("position", pos);
8106 this.setStyle("z-index", zIndex);
8108 if(x !== undefined && y !== undefined){
8110 }else if(x !== undefined){
8112 }else if(y !== undefined){
8118 * Clear positioning back to the default when the document was loaded
8119 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8120 * @return {Roo.Element} this
8122 clearPositioning : function(value){
8130 "position" : "static"
8136 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8137 * snapshot before performing an update and then restoring the element.
8140 getPositioning : function(){
8141 var l = this.getStyle("left");
8142 var t = this.getStyle("top");
8144 "position" : this.getStyle("position"),
8146 "right" : l ? "" : this.getStyle("right"),
8148 "bottom" : t ? "" : this.getStyle("bottom"),
8149 "z-index" : this.getStyle("z-index")
8154 * Gets the width of the border(s) for the specified side(s)
8155 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8156 * passing lr would get the border (l)eft width + the border (r)ight width.
8157 * @return {Number} The width of the sides passed added together
8159 getBorderWidth : function(side){
8160 return this.addStyles(side, El.borders);
8164 * Gets the width of the padding(s) for the specified side(s)
8165 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8166 * passing lr would get the padding (l)eft + the padding (r)ight.
8167 * @return {Number} The padding of the sides passed added together
8169 getPadding : function(side){
8170 return this.addStyles(side, El.paddings);
8174 * Set positioning with an object returned by getPositioning().
8175 * @param {Object} posCfg
8176 * @return {Roo.Element} this
8178 setPositioning : function(pc){
8179 this.applyStyles(pc);
8180 if(pc.right == "auto"){
8181 this.dom.style.right = "";
8183 if(pc.bottom == "auto"){
8184 this.dom.style.bottom = "";
8190 fixDisplay : function(){
8191 if(this.getStyle("display") == "none"){
8192 this.setStyle("visibility", "hidden");
8193 this.setStyle("display", this.originalDisplay); // first try reverting to default
8194 if(this.getStyle("display") == "none"){ // if that fails, default to block
8195 this.setStyle("display", "block");
8201 * Quick set left and top adding default units
8202 * @param {String} left The left CSS property value
8203 * @param {String} top The top CSS property value
8204 * @return {Roo.Element} this
8206 setLeftTop : function(left, top){
8207 this.dom.style.left = this.addUnits(left);
8208 this.dom.style.top = this.addUnits(top);
8213 * Move this element relative to its current position.
8214 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8215 * @param {Number} distance How far to move the element in pixels
8216 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8217 * @return {Roo.Element} this
8219 move : function(direction, distance, animate){
8220 var xy = this.getXY();
8221 direction = direction.toLowerCase();
8225 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8229 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8234 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8239 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8246 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8247 * @return {Roo.Element} this
8250 if(!this.isClipped){
8251 this.isClipped = true;
8252 this.originalClip = {
8253 "o": this.getStyle("overflow"),
8254 "x": this.getStyle("overflow-x"),
8255 "y": this.getStyle("overflow-y")
8257 this.setStyle("overflow", "hidden");
8258 this.setStyle("overflow-x", "hidden");
8259 this.setStyle("overflow-y", "hidden");
8265 * Return clipping (overflow) to original clipping before clip() was called
8266 * @return {Roo.Element} this
8268 unclip : function(){
8270 this.isClipped = false;
8271 var o = this.originalClip;
8272 if(o.o){this.setStyle("overflow", o.o);}
8273 if(o.x){this.setStyle("overflow-x", o.x);}
8274 if(o.y){this.setStyle("overflow-y", o.y);}
8281 * Gets the x,y coordinates specified by the anchor position on the element.
8282 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8283 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8284 * {width: (target width), height: (target height)} (defaults to the element's current size)
8285 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8286 * @return {Array} [x, y] An array containing the element's x and y coordinates
8288 getAnchorXY : function(anchor, local, s){
8289 //Passing a different size is useful for pre-calculating anchors,
8290 //especially for anchored animations that change the el size.
8292 var w, h, vp = false;
8295 if(d == document.body || d == document){
8297 w = D.getViewWidth(); h = D.getViewHeight();
8299 w = this.getWidth(); h = this.getHeight();
8302 w = s.width; h = s.height;
8304 var x = 0, y = 0, r = Math.round;
8305 switch((anchor || "tl").toLowerCase()){
8347 var sc = this.getScroll();
8348 return [x + sc.left, y + sc.top];
8350 //Add the element's offset xy
8351 var o = this.getXY();
8352 return [x+o[0], y+o[1]];
8356 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8357 * supported position values.
8358 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8359 * @param {String} position The position to align to.
8360 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8361 * @return {Array} [x, y]
8363 getAlignToXY : function(el, p, o){
8367 throw "Element.alignTo with an element that doesn't exist";
8369 var c = false; //constrain to viewport
8370 var p1 = "", p2 = "";
8377 }else if(p.indexOf("-") == -1){
8380 p = p.toLowerCase();
8381 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8383 throw "Element.alignTo with an invalid alignment " + p;
8385 p1 = m[1]; p2 = m[2]; c = !!m[3];
8387 //Subtract the aligned el's internal xy from the target's offset xy
8388 //plus custom offset to get the aligned el's new offset xy
8389 var a1 = this.getAnchorXY(p1, true);
8390 var a2 = el.getAnchorXY(p2, false);
8391 var x = a2[0] - a1[0] + o[0];
8392 var y = a2[1] - a1[1] + o[1];
8394 //constrain the aligned el to viewport if necessary
8395 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8396 // 5px of margin for ie
8397 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8399 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8400 //perpendicular to the vp border, allow the aligned el to slide on that border,
8401 //otherwise swap the aligned el to the opposite border of the target.
8402 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8403 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8404 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8405 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8408 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8409 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8411 if((x+w) > dw + scrollX){
8412 x = swapX ? r.left-w : dw+scrollX-w;
8415 x = swapX ? r.right : scrollX;
8417 if((y+h) > dh + scrollY){
8418 y = swapY ? r.top-h : dh+scrollY-h;
8421 y = swapY ? r.bottom : scrollY;
8428 getConstrainToXY : function(){
8429 var os = {top:0, left:0, bottom:0, right: 0};
8431 return function(el, local, offsets, proposedXY){
8433 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8435 var vw, vh, vx = 0, vy = 0;
8436 if(el.dom == document.body || el.dom == document){
8437 vw = Roo.lib.Dom.getViewWidth();
8438 vh = Roo.lib.Dom.getViewHeight();
8440 vw = el.dom.clientWidth;
8441 vh = el.dom.clientHeight;
8443 var vxy = el.getXY();
8449 var s = el.getScroll();
8451 vx += offsets.left + s.left;
8452 vy += offsets.top + s.top;
8454 vw -= offsets.right;
8455 vh -= offsets.bottom;
8460 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8461 var x = xy[0], y = xy[1];
8462 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8464 // only move it if it needs it
8467 // first validate right/bottom
8476 // then make sure top/left isn't negative
8485 return moved ? [x, y] : false;
8490 adjustForConstraints : function(xy, parent, offsets){
8491 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8495 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8496 * document it aligns it to the viewport.
8497 * The position parameter is optional, and can be specified in any one of the following formats:
8499 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8500 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8501 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8502 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8503 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8504 * element's anchor point, and the second value is used as the target's anchor point.</li>
8506 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8507 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8508 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8509 * that specified in order to enforce the viewport constraints.
8510 * Following are all of the supported anchor positions:
8513 ----- -----------------------------
8514 tl The top left corner (default)
8515 t The center of the top edge
8516 tr The top right corner
8517 l The center of the left edge
8518 c In the center of the element
8519 r The center of the right edge
8520 bl The bottom left corner
8521 b The center of the bottom edge
8522 br The bottom right corner
8526 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8527 el.alignTo("other-el");
8529 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8530 el.alignTo("other-el", "tr?");
8532 // align the bottom right corner of el with the center left edge of other-el
8533 el.alignTo("other-el", "br-l?");
8535 // align the center of el with the bottom left corner of other-el and
8536 // adjust the x position by -6 pixels (and the y position by 0)
8537 el.alignTo("other-el", "c-bl", [-6, 0]);
8539 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8540 * @param {String} position The position to align to.
8541 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8542 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8543 * @return {Roo.Element} this
8545 alignTo : function(element, position, offsets, animate){
8546 var xy = this.getAlignToXY(element, position, offsets);
8547 this.setXY(xy, this.preanim(arguments, 3));
8552 * Anchors an element to another element and realigns it when the window is resized.
8553 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8554 * @param {String} position The position to align to.
8555 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8556 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8557 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8558 * is a number, it is used as the buffer delay (defaults to 50ms).
8559 * @param {Function} callback The function to call after the animation finishes
8560 * @return {Roo.Element} this
8562 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8563 var action = function(){
8564 this.alignTo(el, alignment, offsets, animate);
8565 Roo.callback(callback, this);
8567 Roo.EventManager.onWindowResize(action, this);
8568 var tm = typeof monitorScroll;
8569 if(tm != 'undefined'){
8570 Roo.EventManager.on(window, 'scroll', action, this,
8571 {buffer: tm == 'number' ? monitorScroll : 50});
8573 action.call(this); // align immediately
8577 * Clears any opacity settings from this element. Required in some cases for IE.
8578 * @return {Roo.Element} this
8580 clearOpacity : function(){
8581 if (window.ActiveXObject) {
8582 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8583 this.dom.style.filter = "";
8586 this.dom.style.opacity = "";
8587 this.dom.style["-moz-opacity"] = "";
8588 this.dom.style["-khtml-opacity"] = "";
8594 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8595 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8596 * @return {Roo.Element} this
8598 hide : function(animate){
8599 this.setVisible(false, this.preanim(arguments, 0));
8604 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8605 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8606 * @return {Roo.Element} this
8608 show : function(animate){
8609 this.setVisible(true, this.preanim(arguments, 0));
8614 * @private Test if size has a unit, otherwise appends the default
8616 addUnits : function(size){
8617 return Roo.Element.addUnits(size, this.defaultUnit);
8621 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8622 * @return {Roo.Element} this
8624 beginMeasure : function(){
8626 if(el.offsetWidth || el.offsetHeight){
8627 return this; // offsets work already
8630 var p = this.dom, b = document.body; // start with this element
8631 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8632 var pe = Roo.get(p);
8633 if(pe.getStyle('display') == 'none'){
8634 changed.push({el: p, visibility: pe.getStyle("visibility")});
8635 p.style.visibility = "hidden";
8636 p.style.display = "block";
8640 this._measureChanged = changed;
8646 * Restores displays to before beginMeasure was called
8647 * @return {Roo.Element} this
8649 endMeasure : function(){
8650 var changed = this._measureChanged;
8652 for(var i = 0, len = changed.length; i < len; i++) {
8654 r.el.style.visibility = r.visibility;
8655 r.el.style.display = "none";
8657 this._measureChanged = null;
8663 * Update the innerHTML of this element, optionally searching for and processing scripts
8664 * @param {String} html The new HTML
8665 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8666 * @param {Function} callback For async script loading you can be noticed when the update completes
8667 * @return {Roo.Element} this
8669 update : function(html, loadScripts, callback){
8670 if(typeof html == "undefined"){
8673 if(loadScripts !== true){
8674 this.dom.innerHTML = html;
8675 if(typeof callback == "function"){
8683 html += '<span id="' + id + '"></span>';
8685 E.onAvailable(id, function(){
8686 var hd = document.getElementsByTagName("head")[0];
8687 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8688 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8689 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8692 while(match = re.exec(html)){
8693 var attrs = match[1];
8694 var srcMatch = attrs ? attrs.match(srcRe) : false;
8695 if(srcMatch && srcMatch[2]){
8696 var s = document.createElement("script");
8697 s.src = srcMatch[2];
8698 var typeMatch = attrs.match(typeRe);
8699 if(typeMatch && typeMatch[2]){
8700 s.type = typeMatch[2];
8703 }else if(match[2] && match[2].length > 0){
8704 if(window.execScript) {
8705 window.execScript(match[2]);
8713 window.eval(match[2]);
8717 var el = document.getElementById(id);
8718 if(el){el.parentNode.removeChild(el);}
8719 if(typeof callback == "function"){
8723 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8728 * Direct access to the UpdateManager update() method (takes the same parameters).
8729 * @param {String/Function} url The url for this request or a function to call to get the url
8730 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8731 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8732 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8733 * @return {Roo.Element} this
8736 var um = this.getUpdateManager();
8737 um.update.apply(um, arguments);
8742 * Gets this element's UpdateManager
8743 * @return {Roo.UpdateManager} The UpdateManager
8745 getUpdateManager : function(){
8746 if(!this.updateManager){
8747 this.updateManager = new Roo.UpdateManager(this);
8749 return this.updateManager;
8753 * Disables text selection for this element (normalized across browsers)
8754 * @return {Roo.Element} this
8756 unselectable : function(){
8757 this.dom.unselectable = "on";
8758 this.swallowEvent("selectstart", true);
8759 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8760 this.addClass("x-unselectable");
8765 * Calculates the x, y to center this element on the screen
8766 * @return {Array} The x, y values [x, y]
8768 getCenterXY : function(){
8769 return this.getAlignToXY(document, 'c-c');
8773 * Centers the Element in either the viewport, or another Element.
8774 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8776 center : function(centerIn){
8777 this.alignTo(centerIn || document, 'c-c');
8782 * Tests various css rules/browsers to determine if this element uses a border box
8785 isBorderBox : function(){
8786 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8790 * Return a box {x, y, width, height} that can be used to set another elements
8791 * size/location to match this element.
8792 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8793 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8794 * @return {Object} box An object in the format {x, y, width, height}
8796 getBox : function(contentBox, local){
8801 var left = parseInt(this.getStyle("left"), 10) || 0;
8802 var top = parseInt(this.getStyle("top"), 10) || 0;
8805 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8807 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8809 var l = this.getBorderWidth("l")+this.getPadding("l");
8810 var r = this.getBorderWidth("r")+this.getPadding("r");
8811 var t = this.getBorderWidth("t")+this.getPadding("t");
8812 var b = this.getBorderWidth("b")+this.getPadding("b");
8813 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8815 bx.right = bx.x + bx.width;
8816 bx.bottom = bx.y + bx.height;
8821 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8822 for more information about the sides.
8823 * @param {String} sides
8826 getFrameWidth : function(sides, onlyContentBox){
8827 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8831 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8832 * @param {Object} box The box to fill {x, y, width, height}
8833 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8834 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8835 * @return {Roo.Element} this
8837 setBox : function(box, adjust, animate){
8838 var w = box.width, h = box.height;
8839 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8840 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8841 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8843 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8848 * Forces the browser to repaint this element
8849 * @return {Roo.Element} this
8851 repaint : function(){
8853 this.addClass("x-repaint");
8854 setTimeout(function(){
8855 Roo.get(dom).removeClass("x-repaint");
8861 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8862 * then it returns the calculated width of the sides (see getPadding)
8863 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8864 * @return {Object/Number}
8866 getMargins : function(side){
8869 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8870 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8871 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8872 right: parseInt(this.getStyle("margin-right"), 10) || 0
8875 return this.addStyles(side, El.margins);
8880 addStyles : function(sides, styles){
8882 for(var i = 0, len = sides.length; i < len; i++){
8883 v = this.getStyle(styles[sides.charAt(i)]);
8885 w = parseInt(v, 10);
8893 * Creates a proxy element of this element
8894 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8895 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8896 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8897 * @return {Roo.Element} The new proxy element
8899 createProxy : function(config, renderTo, matchBox){
8901 renderTo = Roo.getDom(renderTo);
8903 renderTo = document.body;
8905 config = typeof config == "object" ?
8906 config : {tag : "div", cls: config};
8907 var proxy = Roo.DomHelper.append(renderTo, config, true);
8909 proxy.setBox(this.getBox());
8915 * Puts a mask over this element to disable user interaction. Requires core.css.
8916 * This method can only be applied to elements which accept child nodes.
8917 * @param {String} msg (optional) A message to display in the mask
8918 * @param {String} msgCls (optional) A css class to apply to the msg element
8919 * @return {Element} The mask element
8921 mask : function(msg, msgCls)
8923 if(this.getStyle("position") == "static"){
8924 this.setStyle("position", "relative");
8927 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8929 this.addClass("x-masked");
8930 this._mask.setDisplayed(true);
8935 while (dom && dom.style) {
8936 if (!isNaN(parseInt(dom.style.zIndex))) {
8937 z = Math.max(z, parseInt(dom.style.zIndex));
8939 dom = dom.parentNode;
8941 // if we are masking the body - then it hides everything..
8942 if (this.dom == document.body) {
8944 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8945 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8948 if(typeof msg == 'string'){
8950 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8952 var mm = this._maskMsg;
8953 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8954 mm.dom.firstChild.innerHTML = msg;
8955 mm.setDisplayed(true);
8957 mm.setStyle('z-index', z + 102);
8959 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8960 this._mask.setHeight(this.getHeight());
8962 this._mask.setStyle('z-index', z + 100);
8968 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8969 * it is cached for reuse.
8971 unmask : function(removeEl){
8973 if(removeEl === true){
8974 this._mask.remove();
8977 this._maskMsg.remove();
8978 delete this._maskMsg;
8981 this._mask.setDisplayed(false);
8983 this._maskMsg.setDisplayed(false);
8987 this.removeClass("x-masked");
8991 * Returns true if this element is masked
8994 isMasked : function(){
8995 return this._mask && this._mask.isVisible();
8999 * Creates an iframe shim for this element to keep selects and other windowed objects from
9001 * @return {Roo.Element} The new shim element
9003 createShim : function(){
9004 var el = document.createElement('iframe');
9005 el.frameBorder = 'no';
9006 el.className = 'roo-shim';
9007 if(Roo.isIE && Roo.isSecure){
9008 el.src = Roo.SSL_SECURE_URL;
9010 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9011 shim.autoBoxAdjust = false;
9016 * Removes this element from the DOM and deletes it from the cache
9018 remove : function(){
9019 if(this.dom.parentNode){
9020 this.dom.parentNode.removeChild(this.dom);
9022 delete El.cache[this.dom.id];
9026 * Sets up event handlers to add and remove a css class when the mouse is over this element
9027 * @param {String} className
9028 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9029 * mouseout events for children elements
9030 * @return {Roo.Element} this
9032 addClassOnOver : function(className, preventFlicker){
9033 this.on("mouseover", function(){
9034 Roo.fly(this, '_internal').addClass(className);
9036 var removeFn = function(e){
9037 if(preventFlicker !== true || !e.within(this, true)){
9038 Roo.fly(this, '_internal').removeClass(className);
9041 this.on("mouseout", removeFn, this.dom);
9046 * Sets up event handlers to add and remove a css class when this element has the focus
9047 * @param {String} className
9048 * @return {Roo.Element} this
9050 addClassOnFocus : function(className){
9051 this.on("focus", function(){
9052 Roo.fly(this, '_internal').addClass(className);
9054 this.on("blur", function(){
9055 Roo.fly(this, '_internal').removeClass(className);
9060 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9061 * @param {String} className
9062 * @return {Roo.Element} this
9064 addClassOnClick : function(className){
9066 this.on("mousedown", function(){
9067 Roo.fly(dom, '_internal').addClass(className);
9068 var d = Roo.get(document);
9069 var fn = function(){
9070 Roo.fly(dom, '_internal').removeClass(className);
9071 d.removeListener("mouseup", fn);
9073 d.on("mouseup", fn);
9079 * Stops the specified event from bubbling and optionally prevents the default action
9080 * @param {String} eventName
9081 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9082 * @return {Roo.Element} this
9084 swallowEvent : function(eventName, preventDefault){
9085 var fn = function(e){
9086 e.stopPropagation();
9091 if(eventName instanceof Array){
9092 for(var i = 0, len = eventName.length; i < len; i++){
9093 this.on(eventName[i], fn);
9097 this.on(eventName, fn);
9104 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9107 * Sizes this element to its parent element's dimensions performing
9108 * neccessary box adjustments.
9109 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9110 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9111 * @return {Roo.Element} this
9113 fitToParent : function(monitorResize, targetParent) {
9114 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9115 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9116 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9119 var p = Roo.get(targetParent || this.dom.parentNode);
9120 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9121 if (monitorResize === true) {
9122 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9123 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9129 * Gets the next sibling, skipping text nodes
9130 * @return {HTMLElement} The next sibling or null
9132 getNextSibling : function(){
9133 var n = this.dom.nextSibling;
9134 while(n && n.nodeType != 1){
9141 * Gets the previous sibling, skipping text nodes
9142 * @return {HTMLElement} The previous sibling or null
9144 getPrevSibling : function(){
9145 var n = this.dom.previousSibling;
9146 while(n && n.nodeType != 1){
9147 n = n.previousSibling;
9154 * Appends the passed element(s) to this element
9155 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9156 * @return {Roo.Element} this
9158 appendChild: function(el){
9165 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9166 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9167 * automatically generated with the specified attributes.
9168 * @param {HTMLElement} insertBefore (optional) a child element of this element
9169 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9170 * @return {Roo.Element} The new child element
9172 createChild: function(config, insertBefore, returnDom){
9173 config = config || {tag:'div'};
9175 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9177 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9181 * Appends this element to the passed element
9182 * @param {String/HTMLElement/Element} el The new parent element
9183 * @return {Roo.Element} this
9185 appendTo: function(el){
9186 el = Roo.getDom(el);
9187 el.appendChild(this.dom);
9192 * Inserts this element before the passed element in the DOM
9193 * @param {String/HTMLElement/Element} el The element to insert before
9194 * @return {Roo.Element} this
9196 insertBefore: function(el){
9197 el = Roo.getDom(el);
9198 el.parentNode.insertBefore(this.dom, el);
9203 * Inserts this element after the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert after
9205 * @return {Roo.Element} this
9207 insertAfter: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el.nextSibling);
9214 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9215 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9216 * @return {Roo.Element} The new child
9218 insertFirst: function(el, returnDom){
9220 if(typeof el == 'object' && !el.nodeType){ // dh config
9221 return this.createChild(el, this.dom.firstChild, returnDom);
9223 el = Roo.getDom(el);
9224 this.dom.insertBefore(el, this.dom.firstChild);
9225 return !returnDom ? Roo.get(el) : el;
9230 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9231 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9232 * @param {String} where (optional) 'before' or 'after' defaults to before
9233 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9234 * @return {Roo.Element} the inserted Element
9236 insertSibling: function(el, where, returnDom){
9237 where = where ? where.toLowerCase() : 'before';
9239 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9241 if(typeof el == 'object' && !el.nodeType){ // dh config
9242 if(where == 'after' && !this.dom.nextSibling){
9243 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9245 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9249 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9250 where == 'before' ? this.dom : this.dom.nextSibling);
9259 * Creates and wraps this element with another element
9260 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9261 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9262 * @return {HTMLElement/Element} The newly created wrapper element
9264 wrap: function(config, returnDom){
9266 config = {tag: "div"};
9268 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9269 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9274 * Replaces the passed element with this element
9275 * @param {String/HTMLElement/Element} el The element to replace
9276 * @return {Roo.Element} this
9278 replace: function(el){
9280 this.insertBefore(el);
9286 * Inserts an html fragment into this element
9287 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9288 * @param {String} html The HTML fragment
9289 * @param {Boolean} returnEl True to return an Roo.Element
9290 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9292 insertHtml : function(where, html, returnEl){
9293 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9294 return returnEl ? Roo.get(el) : el;
9298 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9299 * @param {Object} o The object with the attributes
9300 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9301 * @return {Roo.Element} this
9303 set : function(o, useSet){
9305 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9307 if(attr == "style" || typeof o[attr] == "function") continue;
9309 el.className = o["cls"];
9311 if(useSet) el.setAttribute(attr, o[attr]);
9312 else el[attr] = o[attr];
9316 Roo.DomHelper.applyStyles(el, o.style);
9322 * Convenience method for constructing a KeyMap
9323 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9324 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9325 * @param {Function} fn The function to call
9326 * @param {Object} scope (optional) The scope of the function
9327 * @return {Roo.KeyMap} The KeyMap created
9329 addKeyListener : function(key, fn, scope){
9331 if(typeof key != "object" || key instanceof Array){
9347 return new Roo.KeyMap(this, config);
9351 * Creates a KeyMap for this element
9352 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9353 * @return {Roo.KeyMap} The KeyMap created
9355 addKeyMap : function(config){
9356 return new Roo.KeyMap(this, config);
9360 * Returns true if this element is scrollable.
9363 isScrollable : function(){
9365 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9369 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9370 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9371 * @param {Number} value The new scroll value
9372 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9373 * @return {Element} this
9376 scrollTo : function(side, value, animate){
9377 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9379 this.dom[prop] = value;
9381 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9382 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9388 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9389 * within this element's scrollable range.
9390 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9391 * @param {Number} distance How far to scroll the element in pixels
9392 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9393 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9394 * was scrolled as far as it could go.
9396 scroll : function(direction, distance, animate){
9397 if(!this.isScrollable()){
9401 var l = el.scrollLeft, t = el.scrollTop;
9402 var w = el.scrollWidth, h = el.scrollHeight;
9403 var cw = el.clientWidth, ch = el.clientHeight;
9404 direction = direction.toLowerCase();
9405 var scrolled = false;
9406 var a = this.preanim(arguments, 2);
9411 var v = Math.min(l + distance, w-cw);
9412 this.scrollTo("left", v, a);
9419 var v = Math.max(l - distance, 0);
9420 this.scrollTo("left", v, a);
9428 var v = Math.max(t - distance, 0);
9429 this.scrollTo("top", v, a);
9437 var v = Math.min(t + distance, h-ch);
9438 this.scrollTo("top", v, a);
9447 * Translates the passed page coordinates into left/top css values for this element
9448 * @param {Number/Array} x The page x or an array containing [x, y]
9449 * @param {Number} y The page y
9450 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9452 translatePoints : function(x, y){
9453 if(typeof x == 'object' || x instanceof Array){
9456 var p = this.getStyle('position');
9457 var o = this.getXY();
9459 var l = parseInt(this.getStyle('left'), 10);
9460 var t = parseInt(this.getStyle('top'), 10);
9463 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9466 t = (p == "relative") ? 0 : this.dom.offsetTop;
9469 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9473 * Returns the current scroll position of the element.
9474 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9476 getScroll : function(){
9477 var d = this.dom, doc = document;
9478 if(d == doc || d == doc.body){
9479 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9480 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9481 return {left: l, top: t};
9483 return {left: d.scrollLeft, top: d.scrollTop};
9488 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9489 * are convert to standard 6 digit hex color.
9490 * @param {String} attr The css attribute
9491 * @param {String} defaultValue The default value to use when a valid color isn't found
9492 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9495 getColor : function(attr, defaultValue, prefix){
9496 var v = this.getStyle(attr);
9497 if(!v || v == "transparent" || v == "inherit") {
9498 return defaultValue;
9500 var color = typeof prefix == "undefined" ? "#" : prefix;
9501 if(v.substr(0, 4) == "rgb("){
9502 var rvs = v.slice(4, v.length -1).split(",");
9503 for(var i = 0; i < 3; i++){
9504 var h = parseInt(rvs[i]).toString(16);
9511 if(v.substr(0, 1) == "#"){
9513 for(var i = 1; i < 4; i++){
9514 var c = v.charAt(i);
9517 }else if(v.length == 7){
9518 color += v.substr(1);
9522 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9526 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9527 * gradient background, rounded corners and a 4-way shadow.
9528 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9529 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9530 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9531 * @return {Roo.Element} this
9533 boxWrap : function(cls){
9534 cls = cls || 'x-box';
9535 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9536 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9541 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9542 * @param {String} namespace The namespace in which to look for the attribute
9543 * @param {String} name The attribute name
9544 * @return {String} The attribute value
9546 getAttributeNS : Roo.isIE ? function(ns, name){
9548 var type = typeof d[ns+":"+name];
9549 if(type != 'undefined' && type != 'unknown'){
9550 return d[ns+":"+name];
9553 } : function(ns, name){
9555 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9559 var ep = El.prototype;
9562 * Appends an event handler (Shorthand for addListener)
9563 * @param {String} eventName The type of event to append
9564 * @param {Function} fn The method the event invokes
9565 * @param {Object} scope (optional) The scope (this object) of the fn
9566 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9569 ep.on = ep.addListener;
9571 ep.mon = ep.addListener;
9574 * Removes an event handler from this element (shorthand for removeListener)
9575 * @param {String} eventName the type of event to remove
9576 * @param {Function} fn the method the event invokes
9577 * @return {Roo.Element} this
9580 ep.un = ep.removeListener;
9583 * true to automatically adjust width and height settings for box-model issues (default to true)
9585 ep.autoBoxAdjust = true;
9588 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9591 El.addUnits = function(v, defaultUnit){
9592 if(v === "" || v == "auto"){
9595 if(v === undefined){
9598 if(typeof v == "number" || !El.unitPattern.test(v)){
9599 return v + (defaultUnit || 'px');
9604 // special markup used throughout Roo when box wrapping elements
9605 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9607 * Visibility mode constant - Use visibility to hide element
9613 * Visibility mode constant - Use display to hide element
9619 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9620 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9621 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9633 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9634 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9635 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9636 * @return {Element} The Element object
9639 El.get = function(el){
9641 if(!el){ return null; }
9642 if(typeof el == "string"){ // element id
9643 if(!(elm = document.getElementById(el))){
9646 if(ex = El.cache[el]){
9649 ex = El.cache[el] = new El(elm);
9652 }else if(el.tagName){ // dom element
9656 if(ex = El.cache[id]){
9659 ex = El.cache[id] = new El(el);
9662 }else if(el instanceof El){
9664 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9665 // catch case where it hasn't been appended
9666 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9669 }else if(el.isComposite){
9671 }else if(el instanceof Array){
9672 return El.select(el);
9673 }else if(el == document){
9674 // create a bogus element object representing the document object
9676 var f = function(){};
9677 f.prototype = El.prototype;
9679 docEl.dom = document;
9687 El.uncache = function(el){
9688 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9690 delete El.cache[a[i].id || a[i]];
9696 // Garbage collection - uncache elements/purge listeners on orphaned elements
9697 // so we don't hold a reference and cause the browser to retain them
9698 El.garbageCollect = function(){
9699 if(!Roo.enableGarbageCollector){
9700 clearInterval(El.collectorThread);
9703 for(var eid in El.cache){
9704 var el = El.cache[eid], d = el.dom;
9705 // -------------------------------------------------------
9706 // Determining what is garbage:
9707 // -------------------------------------------------------
9709 // dom node is null, definitely garbage
9710 // -------------------------------------------------------
9712 // no parentNode == direct orphan, definitely garbage
9713 // -------------------------------------------------------
9714 // !d.offsetParent && !document.getElementById(eid)
9715 // display none elements have no offsetParent so we will
9716 // also try to look it up by it's id. However, check
9717 // offsetParent first so we don't do unneeded lookups.
9718 // This enables collection of elements that are not orphans
9719 // directly, but somewhere up the line they have an orphan
9721 // -------------------------------------------------------
9722 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9723 delete El.cache[eid];
9724 if(d && Roo.enableListenerCollection){
9730 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9734 El.Flyweight = function(dom){
9737 El.Flyweight.prototype = El.prototype;
9739 El._flyweights = {};
9741 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9742 * the dom node can be overwritten by other code.
9743 * @param {String/HTMLElement} el The dom node or id
9744 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9745 * prevent conflicts (e.g. internally Roo uses "_internal")
9747 * @return {Element} The shared Element object
9749 El.fly = function(el, named){
9750 named = named || '_global';
9751 el = Roo.getDom(el);
9755 if(!El._flyweights[named]){
9756 El._flyweights[named] = new El.Flyweight();
9758 El._flyweights[named].dom = el;
9759 return El._flyweights[named];
9763 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9764 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9765 * Shorthand of {@link Roo.Element#get}
9766 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9767 * @return {Element} The Element object
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * Shorthand of {@link Roo.Element#fly}
9776 * @param {String/HTMLElement} el The dom node or id
9777 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9778 * prevent conflicts (e.g. internally Roo uses "_internal")
9780 * @return {Element} The shared Element object
9786 // speedy lookup for elements never to box adjust
9787 var noBoxAdjust = Roo.isStrict ? {
9790 input:1, select:1, textarea:1
9792 if(Roo.isIE || Roo.isGecko){
9793 noBoxAdjust['button'] = 1;
9797 Roo.EventManager.on(window, 'unload', function(){
9799 delete El._flyweights;
9807 Roo.Element.selectorFunction = Roo.DomQuery.select;
9810 Roo.Element.select = function(selector, unique, root){
9812 if(typeof selector == "string"){
9813 els = Roo.Element.selectorFunction(selector, root);
9814 }else if(selector.length !== undefined){
9817 throw "Invalid selector";
9819 if(unique === true){
9820 return new Roo.CompositeElement(els);
9822 return new Roo.CompositeElementLite(els);
9826 * Selects elements based on the passed CSS selector to enable working on them as 1.
9827 * @param {String/Array} selector The CSS selector or an array of elements
9828 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9829 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9830 * @return {CompositeElementLite/CompositeElement}
9834 Roo.select = Roo.Element.select;
9851 * Ext JS Library 1.1.1
9852 * Copyright(c) 2006-2007, Ext JS, LLC.
9854 * Originally Released Under LGPL - original licence link has changed is not relivant.
9857 * <script type="text/javascript">
9862 //Notifies Element that fx methods are available
9863 Roo.enableFx = true;
9867 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9868 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9869 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9870 * Element effects to work.</p><br/>
9872 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9873 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9874 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9875 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9876 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9877 * expected results and should be done with care.</p><br/>
9879 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9880 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9883 ----- -----------------------------
9884 tl The top left corner
9885 t The center of the top edge
9886 tr The top right corner
9887 l The center of the left edge
9888 r The center of the right edge
9889 bl The bottom left corner
9890 b The center of the bottom edge
9891 br The bottom right corner
9893 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9894 * below are common options that can be passed to any Fx method.</b>
9895 * @cfg {Function} callback A function called when the effect is finished
9896 * @cfg {Object} scope The scope of the effect function
9897 * @cfg {String} easing A valid Easing value for the effect
9898 * @cfg {String} afterCls A css class to apply after the effect
9899 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9900 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9901 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9902 * effects that end with the element being visually hidden, ignored otherwise)
9903 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9904 * a function which returns such a specification that will be applied to the Element after the effect finishes
9905 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9906 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9907 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9911 * Slides the element into view. An anchor point can be optionally passed to set the point of
9912 * origin for the slide effect. This function automatically handles wrapping the element with
9913 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9916 // default: slide the element in from the top
9919 // custom: slide the element in from the right with a 2-second duration
9920 el.slideIn('r', { duration: 2 });
9922 // common config options shown with default values
9928 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9929 * @param {Object} options (optional) Object literal with any of the Fx config options
9930 * @return {Roo.Element} The Element
9932 slideIn : function(anchor, o){
9933 var el = this.getFxEl();
9936 el.queueFx(o, function(){
9938 anchor = anchor || "t";
9940 // fix display to visibility
9943 // restore values after effect
9944 var r = this.getFxRestore();
9945 var b = this.getBox();
9946 // fixed size for slide
9950 var wrap = this.fxWrap(r.pos, o, "hidden");
9952 var st = this.dom.style;
9953 st.visibility = "visible";
9954 st.position = "absolute";
9956 // clear out temp styles after slide and unwrap
9957 var after = function(){
9958 el.fxUnwrap(wrap, r.pos, o);
9960 st.height = r.height;
9963 // time to calc the positions
9964 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9966 switch(anchor.toLowerCase()){
9968 wrap.setSize(b.width, 0);
9969 st.left = st.bottom = "0";
9973 wrap.setSize(0, b.height);
9974 st.right = st.top = "0";
9978 wrap.setSize(0, b.height);
9980 st.left = st.top = "0";
9981 a = {width: bw, points: pt};
9984 wrap.setSize(b.width, 0);
9985 wrap.setY(b.bottom);
9986 st.left = st.top = "0";
9987 a = {height: bh, points: pt};
9991 st.right = st.bottom = "0";
9992 a = {width: bw, height: bh};
9996 wrap.setY(b.y+b.height);
9997 st.right = st.top = "0";
9998 a = {width: bw, height: bh, points: pt};
10001 wrap.setSize(0, 0);
10002 wrap.setXY([b.right, b.bottom]);
10003 st.left = st.top = "0";
10004 a = {width: bw, height: bh, points: pt};
10007 wrap.setSize(0, 0);
10008 wrap.setX(b.x+b.width);
10009 st.left = st.bottom = "0";
10010 a = {width: bw, height: bh, points: pt};
10013 this.dom.style.visibility = "visible";
10016 arguments.callee.anim = wrap.fxanim(a,
10026 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10027 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10028 * 'hidden') but block elements will still take up space in the document. The element must be removed
10029 * from the DOM using the 'remove' config option if desired. This function automatically handles
10030 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10033 // default: slide the element out to the top
10036 // custom: slide the element out to the right with a 2-second duration
10037 el.slideOut('r', { duration: 2 });
10039 // common config options shown with default values
10047 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10048 * @param {Object} options (optional) Object literal with any of the Fx config options
10049 * @return {Roo.Element} The Element
10051 slideOut : function(anchor, o){
10052 var el = this.getFxEl();
10055 el.queueFx(o, function(){
10057 anchor = anchor || "t";
10059 // restore values after effect
10060 var r = this.getFxRestore();
10062 var b = this.getBox();
10063 // fixed size for slide
10067 var wrap = this.fxWrap(r.pos, o, "visible");
10069 var st = this.dom.style;
10070 st.visibility = "visible";
10071 st.position = "absolute";
10075 var after = function(){
10077 el.setDisplayed(false);
10082 el.fxUnwrap(wrap, r.pos, o);
10084 st.width = r.width;
10085 st.height = r.height;
10090 var a, zero = {to: 0};
10091 switch(anchor.toLowerCase()){
10093 st.left = st.bottom = "0";
10094 a = {height: zero};
10097 st.right = st.top = "0";
10101 st.left = st.top = "0";
10102 a = {width: zero, points: {to:[b.right, b.y]}};
10105 st.left = st.top = "0";
10106 a = {height: zero, points: {to:[b.x, b.bottom]}};
10109 st.right = st.bottom = "0";
10110 a = {width: zero, height: zero};
10113 st.right = st.top = "0";
10114 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10117 st.left = st.top = "0";
10118 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10121 st.left = st.bottom = "0";
10122 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10126 arguments.callee.anim = wrap.fxanim(a,
10136 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10137 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10138 * The element must be removed from the DOM using the 'remove' config option if desired.
10144 // common config options shown with default values
10152 * @param {Object} options (optional) Object literal with any of the Fx config options
10153 * @return {Roo.Element} The Element
10155 puff : function(o){
10156 var el = this.getFxEl();
10159 el.queueFx(o, function(){
10160 this.clearOpacity();
10163 // restore values after effect
10164 var r = this.getFxRestore();
10165 var st = this.dom.style;
10167 var after = function(){
10169 el.setDisplayed(false);
10176 el.setPositioning(r.pos);
10177 st.width = r.width;
10178 st.height = r.height;
10183 var width = this.getWidth();
10184 var height = this.getHeight();
10186 arguments.callee.anim = this.fxanim({
10187 width : {to: this.adjustWidth(width * 2)},
10188 height : {to: this.adjustHeight(height * 2)},
10189 points : {by: [-(width * .5), -(height * .5)]},
10191 fontSize: {to:200, unit: "%"}
10202 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10203 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10204 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10210 // all config options shown with default values
10218 * @param {Object} options (optional) Object literal with any of the Fx config options
10219 * @return {Roo.Element} The Element
10221 switchOff : function(o){
10222 var el = this.getFxEl();
10225 el.queueFx(o, function(){
10226 this.clearOpacity();
10229 // restore values after effect
10230 var r = this.getFxRestore();
10231 var st = this.dom.style;
10233 var after = function(){
10235 el.setDisplayed(false);
10241 el.setPositioning(r.pos);
10242 st.width = r.width;
10243 st.height = r.height;
10248 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10249 this.clearOpacity();
10253 points:{by:[0, this.getHeight() * .5]}
10254 }, o, 'motion', 0.3, 'easeIn', after);
10255 }).defer(100, this);
10262 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10263 * changed using the "attr" config option) and then fading back to the original color. If no original
10264 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10267 // default: highlight background to yellow
10270 // custom: highlight foreground text to blue for 2 seconds
10271 el.highlight("0000ff", { attr: 'color', duration: 2 });
10273 // common config options shown with default values
10274 el.highlight("ffff9c", {
10275 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10276 endColor: (current color) or "ffffff",
10281 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10282 * @param {Object} options (optional) Object literal with any of the Fx config options
10283 * @return {Roo.Element} The Element
10285 highlight : function(color, o){
10286 var el = this.getFxEl();
10289 el.queueFx(o, function(){
10290 color = color || "ffff9c";
10291 attr = o.attr || "backgroundColor";
10293 this.clearOpacity();
10296 var origColor = this.getColor(attr);
10297 var restoreColor = this.dom.style[attr];
10298 endColor = (o.endColor || origColor) || "ffffff";
10300 var after = function(){
10301 el.dom.style[attr] = restoreColor;
10306 a[attr] = {from: color, to: endColor};
10307 arguments.callee.anim = this.fxanim(a,
10317 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10320 // default: a single light blue ripple
10323 // custom: 3 red ripples lasting 3 seconds total
10324 el.frame("ff0000", 3, { duration: 3 });
10326 // common config options shown with default values
10327 el.frame("C3DAF9", 1, {
10328 duration: 1 //duration of entire animation (not each individual ripple)
10329 // Note: Easing is not configurable and will be ignored if included
10332 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10333 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10334 * @param {Object} options (optional) Object literal with any of the Fx config options
10335 * @return {Roo.Element} The Element
10337 frame : function(color, count, o){
10338 var el = this.getFxEl();
10341 el.queueFx(o, function(){
10342 color = color || "#C3DAF9";
10343 if(color.length == 6){
10344 color = "#" + color;
10346 count = count || 1;
10347 duration = o.duration || 1;
10350 var b = this.getBox();
10351 var animFn = function(){
10352 var proxy = this.createProxy({
10355 visbility:"hidden",
10356 position:"absolute",
10357 "z-index":"35000", // yee haw
10358 border:"0px solid " + color
10361 var scale = Roo.isBorderBox ? 2 : 1;
10363 top:{from:b.y, to:b.y - 20},
10364 left:{from:b.x, to:b.x - 20},
10365 borderWidth:{from:0, to:10},
10366 opacity:{from:1, to:0},
10367 height:{from:b.height, to:(b.height + (20*scale))},
10368 width:{from:b.width, to:(b.width + (20*scale))}
10369 }, duration, function(){
10373 animFn.defer((duration/2)*1000, this);
10384 * Creates a pause before any subsequent queued effects begin. If there are
10385 * no effects queued after the pause it will have no effect.
10390 * @param {Number} seconds The length of time to pause (in seconds)
10391 * @return {Roo.Element} The Element
10393 pause : function(seconds){
10394 var el = this.getFxEl();
10397 el.queueFx(o, function(){
10398 setTimeout(function(){
10400 }, seconds * 1000);
10406 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10407 * using the "endOpacity" config option.
10410 // default: fade in from opacity 0 to 100%
10413 // custom: fade in from opacity 0 to 75% over 2 seconds
10414 el.fadeIn({ endOpacity: .75, duration: 2});
10416 // common config options shown with default values
10418 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10423 * @param {Object} options (optional) Object literal with any of the Fx config options
10424 * @return {Roo.Element} The Element
10426 fadeIn : function(o){
10427 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 this.setOpacity(0);
10432 this.dom.style.visibility = 'visible';
10433 var to = o.endOpacity || 1;
10434 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10435 o, null, .5, "easeOut", function(){
10437 this.clearOpacity();
10446 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade out from the element's current opacity to 0
10453 // custom: fade out from the element's current opacity to 25% over 2 seconds
10454 el.fadeOut({ endOpacity: .25, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10465 * @param {Object} options (optional) Object literal with any of the Fx config options
10466 * @return {Roo.Element} The Element
10468 fadeOut : function(o){
10469 var el = this.getFxEl();
10471 el.queueFx(o, function(){
10472 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10473 o, null, .5, "easeOut", function(){
10474 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10475 this.dom.style.display = "none";
10477 this.dom.style.visibility = "hidden";
10479 this.clearOpacity();
10487 * Animates the transition of an element's dimensions from a starting height/width
10488 * to an ending height/width.
10491 // change height and width to 100x100 pixels
10492 el.scale(100, 100);
10494 // common config options shown with default values. The height and width will default to
10495 // the element's existing values if passed as null.
10498 [element's height], {
10503 * @param {Number} width The new width (pass undefined to keep the original width)
10504 * @param {Number} height The new height (pass undefined to keep the original height)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 scale : function(w, h, o){
10509 this.shift(Roo.apply({}, o, {
10517 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10518 * Any of these properties not specified in the config object will not be changed. This effect
10519 * requires that at least one new dimension, position or opacity setting must be passed in on
10520 * the config object in order for the function to have any effect.
10523 // slide the element horizontally to x position 200 while changing the height and opacity
10524 el.shift({ x: 200, height: 50, opacity: .8 });
10526 // common config options shown with default values.
10528 width: [element's width],
10529 height: [element's height],
10530 x: [element's x position],
10531 y: [element's y position],
10532 opacity: [element's opacity],
10537 * @param {Object} options Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 shift : function(o){
10541 var el = this.getFxEl();
10543 el.queueFx(o, function(){
10544 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10545 if(w !== undefined){
10546 a.width = {to: this.adjustWidth(w)};
10548 if(h !== undefined){
10549 a.height = {to: this.adjustHeight(h)};
10551 if(x !== undefined || y !== undefined){
10553 x !== undefined ? x : this.getX(),
10554 y !== undefined ? y : this.getY()
10557 if(op !== undefined){
10558 a.opacity = {to: op};
10560 if(o.xy !== undefined){
10561 a.points = {to: o.xy};
10563 arguments.callee.anim = this.fxanim(a,
10564 o, 'motion', .35, "easeOut", function(){
10572 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10573 * ending point of the effect.
10576 // default: slide the element downward while fading out
10579 // custom: slide the element out to the right with a 2-second duration
10580 el.ghost('r', { duration: 2 });
10582 // common config options shown with default values
10590 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10591 * @param {Object} options (optional) Object literal with any of the Fx config options
10592 * @return {Roo.Element} The Element
10594 ghost : function(anchor, o){
10595 var el = this.getFxEl();
10598 el.queueFx(o, function(){
10599 anchor = anchor || "b";
10601 // restore values after effect
10602 var r = this.getFxRestore();
10603 var w = this.getWidth(),
10604 h = this.getHeight();
10606 var st = this.dom.style;
10608 var after = function(){
10610 el.setDisplayed(false);
10616 el.setPositioning(r.pos);
10617 st.width = r.width;
10618 st.height = r.height;
10623 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10624 switch(anchor.toLowerCase()){
10651 arguments.callee.anim = this.fxanim(a,
10661 * Ensures that all effects queued after syncFx is called on the element are
10662 * run concurrently. This is the opposite of {@link #sequenceFx}.
10663 * @return {Roo.Element} The Element
10665 syncFx : function(){
10666 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10675 * Ensures that all effects queued after sequenceFx is called on the element are
10676 * run in sequence. This is the opposite of {@link #syncFx}.
10677 * @return {Roo.Element} The Element
10679 sequenceFx : function(){
10680 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10682 concurrent : false,
10689 nextFx : function(){
10690 var ef = this.fxQueue[0];
10697 * Returns true if the element has any effects actively running or queued, else returns false.
10698 * @return {Boolean} True if element has active effects, else false
10700 hasActiveFx : function(){
10701 return this.fxQueue && this.fxQueue[0];
10705 * Stops any running effects and clears the element's internal effects queue if it contains
10706 * any additional effects that haven't started yet.
10707 * @return {Roo.Element} The Element
10709 stopFx : function(){
10710 if(this.hasActiveFx()){
10711 var cur = this.fxQueue[0];
10712 if(cur && cur.anim && cur.anim.isAnimated()){
10713 this.fxQueue = [cur]; // clear out others
10714 cur.anim.stop(true);
10721 beforeFx : function(o){
10722 if(this.hasActiveFx() && !o.concurrent){
10733 * Returns true if the element is currently blocking so that no other effect can be queued
10734 * until this effect is finished, else returns false if blocking is not set. This is commonly
10735 * used to ensure that an effect initiated by a user action runs to completion prior to the
10736 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10737 * @return {Boolean} True if blocking, else false
10739 hasFxBlock : function(){
10740 var q = this.fxQueue;
10741 return q && q[0] && q[0].block;
10745 queueFx : function(o, fn){
10749 if(!this.hasFxBlock()){
10750 Roo.applyIf(o, this.fxDefaults);
10752 var run = this.beforeFx(o);
10753 fn.block = o.block;
10754 this.fxQueue.push(fn);
10766 fxWrap : function(pos, o, vis){
10768 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10771 wrapXY = this.getXY();
10773 var div = document.createElement("div");
10774 div.style.visibility = vis;
10775 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10776 wrap.setPositioning(pos);
10777 if(wrap.getStyle("position") == "static"){
10778 wrap.position("relative");
10780 this.clearPositioning('auto');
10782 wrap.dom.appendChild(this.dom);
10784 wrap.setXY(wrapXY);
10791 fxUnwrap : function(wrap, pos, o){
10792 this.clearPositioning();
10793 this.setPositioning(pos);
10795 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10801 getFxRestore : function(){
10802 var st = this.dom.style;
10803 return {pos: this.getPositioning(), width: st.width, height : st.height};
10807 afterFx : function(o){
10809 this.applyStyles(o.afterStyle);
10812 this.addClass(o.afterCls);
10814 if(o.remove === true){
10817 Roo.callback(o.callback, o.scope, [this]);
10819 this.fxQueue.shift();
10825 getFxEl : function(){ // support for composite element fx
10826 return Roo.get(this.dom);
10830 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10831 animType = animType || 'run';
10833 var anim = Roo.lib.Anim[animType](
10835 (opt.duration || defaultDur) || .35,
10836 (opt.easing || defaultEase) || 'easeOut',
10838 Roo.callback(cb, this);
10847 // backwords compat
10848 Roo.Fx.resize = Roo.Fx.scale;
10850 //When included, Roo.Fx is automatically applied to Element so that all basic
10851 //effects are available directly via the Element API
10852 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10854 * Ext JS Library 1.1.1
10855 * Copyright(c) 2006-2007, Ext JS, LLC.
10857 * Originally Released Under LGPL - original licence link has changed is not relivant.
10860 * <script type="text/javascript">
10865 * @class Roo.CompositeElement
10866 * Standard composite class. Creates a Roo.Element for every element in the collection.
10868 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10869 * actions will be performed on all the elements in this collection.</b>
10871 * All methods return <i>this</i> and can be chained.
10873 var els = Roo.select("#some-el div.some-class", true);
10874 // or select directly from an existing element
10875 var el = Roo.get('some-el');
10876 el.select('div.some-class', true);
10878 els.setWidth(100); // all elements become 100 width
10879 els.hide(true); // all elements fade out and hide
10881 els.setWidth(100).hide(true);
10884 Roo.CompositeElement = function(els){
10885 this.elements = [];
10886 this.addElements(els);
10888 Roo.CompositeElement.prototype = {
10890 addElements : function(els){
10891 if(!els) return this;
10892 if(typeof els == "string"){
10893 els = Roo.Element.selectorFunction(els);
10895 var yels = this.elements;
10896 var index = yels.length-1;
10897 for(var i = 0, len = els.length; i < len; i++) {
10898 yels[++index] = Roo.get(els[i]);
10904 * Clears this composite and adds the elements returned by the passed selector.
10905 * @param {String/Array} els A string CSS selector, an array of elements or an element
10906 * @return {CompositeElement} this
10908 fill : function(els){
10909 this.elements = [];
10915 * Filters this composite to only elements that match the passed selector.
10916 * @param {String} selector A string CSS selector
10917 * @return {CompositeElement} this
10919 filter : function(selector){
10921 this.each(function(el){
10922 if(el.is(selector)){
10923 els[els.length] = el.dom;
10930 invoke : function(fn, args){
10931 var els = this.elements;
10932 for(var i = 0, len = els.length; i < len; i++) {
10933 Roo.Element.prototype[fn].apply(els[i], args);
10938 * Adds elements to this composite.
10939 * @param {String/Array} els A string CSS selector, an array of elements or an element
10940 * @return {CompositeElement} this
10942 add : function(els){
10943 if(typeof els == "string"){
10944 this.addElements(Roo.Element.selectorFunction(els));
10945 }else if(els.length !== undefined){
10946 this.addElements(els);
10948 this.addElements([els]);
10953 * Calls the passed function passing (el, this, index) for each element in this composite.
10954 * @param {Function} fn The function to call
10955 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10956 * @return {CompositeElement} this
10958 each : function(fn, scope){
10959 var els = this.elements;
10960 for(var i = 0, len = els.length; i < len; i++){
10961 if(fn.call(scope || els[i], els[i], this, i) === false) {
10969 * Returns the Element object at the specified index
10970 * @param {Number} index
10971 * @return {Roo.Element}
10973 item : function(index){
10974 return this.elements[index] || null;
10978 * Returns the first Element
10979 * @return {Roo.Element}
10981 first : function(){
10982 return this.item(0);
10986 * Returns the last Element
10987 * @return {Roo.Element}
10990 return this.item(this.elements.length-1);
10994 * Returns the number of elements in this composite
10997 getCount : function(){
10998 return this.elements.length;
11002 * Returns true if this composite contains the passed element
11005 contains : function(el){
11006 return this.indexOf(el) !== -1;
11010 * Returns true if this composite contains the passed element
11013 indexOf : function(el){
11014 return this.elements.indexOf(Roo.get(el));
11019 * Removes the specified element(s).
11020 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11021 * or an array of any of those.
11022 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11023 * @return {CompositeElement} this
11025 removeElement : function(el, removeDom){
11026 if(el instanceof Array){
11027 for(var i = 0, len = el.length; i < len; i++){
11028 this.removeElement(el[i]);
11032 var index = typeof el == 'number' ? el : this.indexOf(el);
11035 var d = this.elements[index];
11039 d.parentNode.removeChild(d);
11042 this.elements.splice(index, 1);
11048 * Replaces the specified element with the passed element.
11049 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11051 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11052 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11053 * @return {CompositeElement} this
11055 replaceElement : function(el, replacement, domReplace){
11056 var index = typeof el == 'number' ? el : this.indexOf(el);
11059 this.elements[index].replaceWith(replacement);
11061 this.elements.splice(index, 1, Roo.get(replacement))
11068 * Removes all elements.
11070 clear : function(){
11071 this.elements = [];
11075 Roo.CompositeElement.createCall = function(proto, fnName){
11076 if(!proto[fnName]){
11077 proto[fnName] = function(){
11078 return this.invoke(fnName, arguments);
11082 for(var fnName in Roo.Element.prototype){
11083 if(typeof Roo.Element.prototype[fnName] == "function"){
11084 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11090 * Ext JS Library 1.1.1
11091 * Copyright(c) 2006-2007, Ext JS, LLC.
11093 * Originally Released Under LGPL - original licence link has changed is not relivant.
11096 * <script type="text/javascript">
11100 * @class Roo.CompositeElementLite
11101 * @extends Roo.CompositeElement
11102 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11104 var els = Roo.select("#some-el div.some-class");
11105 // or select directly from an existing element
11106 var el = Roo.get('some-el');
11107 el.select('div.some-class');
11109 els.setWidth(100); // all elements become 100 width
11110 els.hide(true); // all elements fade out and hide
11112 els.setWidth(100).hide(true);
11113 </code></pre><br><br>
11114 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11115 * actions will be performed on all the elements in this collection.</b>
11117 Roo.CompositeElementLite = function(els){
11118 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11119 this.el = new Roo.Element.Flyweight();
11121 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11122 addElements : function(els){
11124 if(els instanceof Array){
11125 this.elements = this.elements.concat(els);
11127 var yels = this.elements;
11128 var index = yels.length-1;
11129 for(var i = 0, len = els.length; i < len; i++) {
11130 yels[++index] = els[i];
11136 invoke : function(fn, args){
11137 var els = this.elements;
11139 for(var i = 0, len = els.length; i < len; i++) {
11141 Roo.Element.prototype[fn].apply(el, args);
11146 * Returns a flyweight Element of the dom element object at the specified index
11147 * @param {Number} index
11148 * @return {Roo.Element}
11150 item : function(index){
11151 if(!this.elements[index]){
11154 this.el.dom = this.elements[index];
11158 // fixes scope with flyweight
11159 addListener : function(eventName, handler, scope, opt){
11160 var els = this.elements;
11161 for(var i = 0, len = els.length; i < len; i++) {
11162 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11168 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11169 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11170 * a reference to the dom node, use el.dom.</b>
11171 * @param {Function} fn The function to call
11172 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11173 * @return {CompositeElement} this
11175 each : function(fn, scope){
11176 var els = this.elements;
11178 for(var i = 0, len = els.length; i < len; i++){
11180 if(fn.call(scope || el, el, this, i) === false){
11187 indexOf : function(el){
11188 return this.elements.indexOf(Roo.getDom(el));
11191 replaceElement : function(el, replacement, domReplace){
11192 var index = typeof el == 'number' ? el : this.indexOf(el);
11194 replacement = Roo.getDom(replacement);
11196 var d = this.elements[index];
11197 d.parentNode.insertBefore(replacement, d);
11198 d.parentNode.removeChild(d);
11200 this.elements.splice(index, 1, replacement);
11205 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11209 * Ext JS Library 1.1.1
11210 * Copyright(c) 2006-2007, Ext JS, LLC.
11212 * Originally Released Under LGPL - original licence link has changed is not relivant.
11215 * <script type="text/javascript">
11221 * @class Roo.data.Connection
11222 * @extends Roo.util.Observable
11223 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11224 * either to a configured URL, or to a URL specified at request time.<br><br>
11226 * Requests made by this class are asynchronous, and will return immediately. No data from
11227 * the server will be available to the statement immediately following the {@link #request} call.
11228 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11230 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11231 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11232 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11233 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11234 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11235 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11236 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11237 * standard DOM methods.
11239 * @param {Object} config a configuration object.
11241 Roo.data.Connection = function(config){
11242 Roo.apply(this, config);
11245 * @event beforerequest
11246 * Fires before a network request is made to retrieve a data object.
11247 * @param {Connection} conn This Connection object.
11248 * @param {Object} options The options config object passed to the {@link #request} method.
11250 "beforerequest" : true,
11252 * @event requestcomplete
11253 * Fires if the request was successfully completed.
11254 * @param {Connection} conn This Connection object.
11255 * @param {Object} response The XHR object containing the response data.
11256 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11257 * @param {Object} options The options config object passed to the {@link #request} method.
11259 "requestcomplete" : true,
11261 * @event requestexception
11262 * Fires if an error HTTP status was returned from the server.
11263 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11264 * @param {Connection} conn This Connection object.
11265 * @param {Object} response The XHR object containing the response data.
11266 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11267 * @param {Object} options The options config object passed to the {@link #request} method.
11269 "requestexception" : true
11271 Roo.data.Connection.superclass.constructor.call(this);
11274 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11276 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11279 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11280 * extra parameters to each request made by this object. (defaults to undefined)
11283 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11284 * to each request made by this object. (defaults to undefined)
11287 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11290 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11294 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11300 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11303 disableCaching: true,
11306 * Sends an HTTP request to a remote server.
11307 * @param {Object} options An object which may contain the following properties:<ul>
11308 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11309 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11310 * request, a url encoded string or a function to call to get either.</li>
11311 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11312 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11313 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11314 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11315 * <li>options {Object} The parameter to the request call.</li>
11316 * <li>success {Boolean} True if the request succeeded.</li>
11317 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11319 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11320 * The callback is passed the following parameters:<ul>
11321 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11322 * <li>options {Object} The parameter to the request call.</li>
11324 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11325 * The callback is passed the following parameters:<ul>
11326 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11327 * <li>options {Object} The parameter to the request call.</li>
11329 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11330 * for the callback function. Defaults to the browser window.</li>
11331 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11332 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11333 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11334 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11335 * params for the post data. Any params will be appended to the URL.</li>
11336 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11338 * @return {Number} transactionId
11340 request : function(o){
11341 if(this.fireEvent("beforerequest", this, o) !== false){
11344 if(typeof p == "function"){
11345 p = p.call(o.scope||window, o);
11347 if(typeof p == "object"){
11348 p = Roo.urlEncode(o.params);
11350 if(this.extraParams){
11351 var extras = Roo.urlEncode(this.extraParams);
11352 p = p ? (p + '&' + extras) : extras;
11355 var url = o.url || this.url;
11356 if(typeof url == 'function'){
11357 url = url.call(o.scope||window, o);
11361 var form = Roo.getDom(o.form);
11362 url = url || form.action;
11364 var enctype = form.getAttribute("enctype");
11365 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11366 return this.doFormUpload(o, p, url);
11368 var f = Roo.lib.Ajax.serializeForm(form);
11369 p = p ? (p + '&' + f) : f;
11372 var hs = o.headers;
11373 if(this.defaultHeaders){
11374 hs = Roo.apply(hs || {}, this.defaultHeaders);
11381 success: this.handleResponse,
11382 failure: this.handleFailure,
11384 argument: {options: o},
11385 timeout : this.timeout
11388 var method = o.method||this.method||(p ? "POST" : "GET");
11390 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11391 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11394 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11398 }else if(this.autoAbort !== false){
11402 if((method == 'GET' && p) || o.xmlData){
11403 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11406 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11407 return this.transId;
11409 Roo.callback(o.callback, o.scope, [o, null, null]);
11415 * Determine whether this object has a request outstanding.
11416 * @param {Number} transactionId (Optional) defaults to the last transaction
11417 * @return {Boolean} True if there is an outstanding request.
11419 isLoading : function(transId){
11421 return Roo.lib.Ajax.isCallInProgress(transId);
11423 return this.transId ? true : false;
11428 * Aborts any outstanding request.
11429 * @param {Number} transactionId (Optional) defaults to the last transaction
11431 abort : function(transId){
11432 if(transId || this.isLoading()){
11433 Roo.lib.Ajax.abort(transId || this.transId);
11438 handleResponse : function(response){
11439 this.transId = false;
11440 var options = response.argument.options;
11441 response.argument = options ? options.argument : null;
11442 this.fireEvent("requestcomplete", this, response, options);
11443 Roo.callback(options.success, options.scope, [response, options]);
11444 Roo.callback(options.callback, options.scope, [options, true, response]);
11448 handleFailure : function(response, e){
11449 this.transId = false;
11450 var options = response.argument.options;
11451 response.argument = options ? options.argument : null;
11452 this.fireEvent("requestexception", this, response, options, e);
11453 Roo.callback(options.failure, options.scope, [response, options]);
11454 Roo.callback(options.callback, options.scope, [options, false, response]);
11458 doFormUpload : function(o, ps, url){
11460 var frame = document.createElement('iframe');
11463 frame.className = 'x-hidden';
11465 frame.src = Roo.SSL_SECURE_URL;
11467 document.body.appendChild(frame);
11470 document.frames[id].name = id;
11473 var form = Roo.getDom(o.form);
11475 form.method = 'POST';
11476 form.enctype = form.encoding = 'multipart/form-data';
11482 if(ps){ // add dynamic params
11484 ps = Roo.urlDecode(ps, false);
11486 if(ps.hasOwnProperty(k)){
11487 hd = document.createElement('input');
11488 hd.type = 'hidden';
11491 form.appendChild(hd);
11498 var r = { // bogus response object
11503 r.argument = o ? o.argument : null;
11508 doc = frame.contentWindow.document;
11510 doc = (frame.contentDocument || window.frames[id].document);
11512 if(doc && doc.body){
11513 r.responseText = doc.body.innerHTML;
11515 if(doc && doc.XMLDocument){
11516 r.responseXML = doc.XMLDocument;
11518 r.responseXML = doc;
11525 Roo.EventManager.removeListener(frame, 'load', cb, this);
11527 this.fireEvent("requestcomplete", this, r, o);
11528 Roo.callback(o.success, o.scope, [r, o]);
11529 Roo.callback(o.callback, o.scope, [o, true, r]);
11531 setTimeout(function(){document.body.removeChild(frame);}, 100);
11534 Roo.EventManager.on(frame, 'load', cb, this);
11537 if(hiddens){ // remove dynamic params
11538 for(var i = 0, len = hiddens.length; i < len; i++){
11539 form.removeChild(hiddens[i]);
11547 * @extends Roo.data.Connection
11548 * Global Ajax request class.
11552 Roo.Ajax = new Roo.data.Connection({
11555 * @cfg {String} url @hide
11558 * @cfg {Object} extraParams @hide
11561 * @cfg {Object} defaultHeaders @hide
11564 * @cfg {String} method (Optional) @hide
11567 * @cfg {Number} timeout (Optional) @hide
11570 * @cfg {Boolean} autoAbort (Optional) @hide
11574 * @cfg {Boolean} disableCaching (Optional) @hide
11578 * @property disableCaching
11579 * True to add a unique cache-buster param to GET requests. (defaults to true)
11584 * The default URL to be used for requests to the server. (defaults to undefined)
11588 * @property extraParams
11589 * An object containing properties which are used as
11590 * extra parameters to each request made by this object. (defaults to undefined)
11594 * @property defaultHeaders
11595 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11600 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11604 * @property timeout
11605 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11610 * @property autoAbort
11611 * Whether a new request should abort any pending requests. (defaults to false)
11617 * Serialize the passed form into a url encoded string
11618 * @param {String/HTMLElement} form
11621 serializeForm : function(form){
11622 return Roo.lib.Ajax.serializeForm(form);
11626 * Ext JS Library 1.1.1
11627 * Copyright(c) 2006-2007, Ext JS, LLC.
11629 * Originally Released Under LGPL - original licence link has changed is not relivant.
11632 * <script type="text/javascript">
11636 * Global Ajax request class.
11639 * @extends Roo.data.Connection
11642 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11643 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11644 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11645 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11646 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11647 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11648 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11650 Roo.Ajax = new Roo.data.Connection({
11659 * Serialize the passed form into a url encoded string
11661 * @param {String/HTMLElement} form
11664 serializeForm : function(form){
11665 return Roo.lib.Ajax.serializeForm(form);
11669 * Ext JS Library 1.1.1
11670 * Copyright(c) 2006-2007, Ext JS, LLC.
11672 * Originally Released Under LGPL - original licence link has changed is not relivant.
11675 * <script type="text/javascript">
11680 * @class Roo.UpdateManager
11681 * @extends Roo.util.Observable
11682 * Provides AJAX-style update for Element object.<br><br>
11685 * // Get it from a Roo.Element object
11686 * var el = Roo.get("foo");
11687 * var mgr = el.getUpdateManager();
11688 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11690 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11692 * // or directly (returns the same UpdateManager instance)
11693 * var mgr = new Roo.UpdateManager("myElementId");
11694 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11695 * mgr.on("update", myFcnNeedsToKnow);
11697 // short handed call directly from the element object
11698 Roo.get("foo").load({
11702 text: "Loading Foo..."
11706 * Create new UpdateManager directly.
11707 * @param {String/HTMLElement/Roo.Element} el The element to update
11708 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11710 Roo.UpdateManager = function(el, forceNew){
11712 if(!forceNew && el.updateManager){
11713 return el.updateManager;
11716 * The Element object
11717 * @type Roo.Element
11721 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11724 this.defaultUrl = null;
11728 * @event beforeupdate
11729 * Fired before an update is made, return false from your handler and the update is cancelled.
11730 * @param {Roo.Element} el
11731 * @param {String/Object/Function} url
11732 * @param {String/Object} params
11734 "beforeupdate": true,
11737 * Fired after successful update is made.
11738 * @param {Roo.Element} el
11739 * @param {Object} oResponseObject The response Object
11744 * Fired on update failure.
11745 * @param {Roo.Element} el
11746 * @param {Object} oResponseObject The response Object
11750 var d = Roo.UpdateManager.defaults;
11752 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11755 this.sslBlankUrl = d.sslBlankUrl;
11757 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11760 this.disableCaching = d.disableCaching;
11762 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11765 this.indicatorText = d.indicatorText;
11767 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11770 this.showLoadIndicator = d.showLoadIndicator;
11772 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11775 this.timeout = d.timeout;
11778 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11781 this.loadScripts = d.loadScripts;
11784 * Transaction object of current executing transaction
11786 this.transaction = null;
11791 this.autoRefreshProcId = null;
11793 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11796 this.refreshDelegate = this.refresh.createDelegate(this);
11798 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11801 this.updateDelegate = this.update.createDelegate(this);
11803 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11806 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11810 this.successDelegate = this.processSuccess.createDelegate(this);
11814 this.failureDelegate = this.processFailure.createDelegate(this);
11816 if(!this.renderer){
11818 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11820 this.renderer = new Roo.UpdateManager.BasicRenderer();
11823 Roo.UpdateManager.superclass.constructor.call(this);
11826 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11828 * Get the Element this UpdateManager is bound to
11829 * @return {Roo.Element} The element
11831 getEl : function(){
11835 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11836 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11839 url: "your-url.php",<br/>
11840 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11841 callback: yourFunction,<br/>
11842 scope: yourObject, //(optional scope) <br/>
11843 discardUrl: false, <br/>
11844 nocache: false,<br/>
11845 text: "Loading...",<br/>
11847 scripts: false<br/>
11850 * The only required property is url. The optional properties nocache, text and scripts
11851 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11852 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11853 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11854 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11856 update : function(url, params, callback, discardUrl){
11857 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11858 var method = this.method, cfg;
11859 if(typeof url == "object"){ // must be config object
11862 params = params || cfg.params;
11863 callback = callback || cfg.callback;
11864 discardUrl = discardUrl || cfg.discardUrl;
11865 if(callback && cfg.scope){
11866 callback = callback.createDelegate(cfg.scope);
11868 if(typeof cfg.method != "undefined"){method = cfg.method;};
11869 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11870 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11871 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11872 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11874 this.showLoading();
11876 this.defaultUrl = url;
11878 if(typeof url == "function"){
11879 url = url.call(this);
11882 method = method || (params ? "POST" : "GET");
11883 if(method == "GET"){
11884 url = this.prepareUrl(url);
11887 var o = Roo.apply(cfg ||{}, {
11890 success: this.successDelegate,
11891 failure: this.failureDelegate,
11892 callback: undefined,
11893 timeout: (this.timeout*1000),
11894 argument: {"url": url, "form": null, "callback": callback, "params": params}
11897 this.transaction = Roo.Ajax.request(o);
11902 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11903 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11904 * @param {String/HTMLElement} form The form Id or form element
11905 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11906 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11907 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11909 formUpdate : function(form, url, reset, callback){
11910 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11911 if(typeof url == "function"){
11912 url = url.call(this);
11914 form = Roo.getDom(form);
11915 this.transaction = Roo.Ajax.request({
11918 success: this.successDelegate,
11919 failure: this.failureDelegate,
11920 timeout: (this.timeout*1000),
11921 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11923 this.showLoading.defer(1, this);
11928 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11929 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11931 refresh : function(callback){
11932 if(this.defaultUrl == null){
11935 this.update(this.defaultUrl, null, callback, true);
11939 * Set this element to auto refresh.
11940 * @param {Number} interval How often to update (in seconds).
11941 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11942 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11943 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11944 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11946 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11948 this.update(url || this.defaultUrl, params, callback, true);
11950 if(this.autoRefreshProcId){
11951 clearInterval(this.autoRefreshProcId);
11953 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11957 * Stop auto refresh on this element.
11959 stopAutoRefresh : function(){
11960 if(this.autoRefreshProcId){
11961 clearInterval(this.autoRefreshProcId);
11962 delete this.autoRefreshProcId;
11966 isAutoRefreshing : function(){
11967 return this.autoRefreshProcId ? true : false;
11970 * Called to update the element to "Loading" state. Override to perform custom action.
11972 showLoading : function(){
11973 if(this.showLoadIndicator){
11974 this.el.update(this.indicatorText);
11979 * Adds unique parameter to query string if disableCaching = true
11982 prepareUrl : function(url){
11983 if(this.disableCaching){
11984 var append = "_dc=" + (new Date().getTime());
11985 if(url.indexOf("?") !== -1){
11986 url += "&" + append;
11988 url += "?" + append;
11997 processSuccess : function(response){
11998 this.transaction = null;
11999 if(response.argument.form && response.argument.reset){
12000 try{ // put in try/catch since some older FF releases had problems with this
12001 response.argument.form.reset();
12004 if(this.loadScripts){
12005 this.renderer.render(this.el, response, this,
12006 this.updateComplete.createDelegate(this, [response]));
12008 this.renderer.render(this.el, response, this);
12009 this.updateComplete(response);
12013 updateComplete : function(response){
12014 this.fireEvent("update", this.el, response);
12015 if(typeof response.argument.callback == "function"){
12016 response.argument.callback(this.el, true, response);
12023 processFailure : function(response){
12024 this.transaction = null;
12025 this.fireEvent("failure", this.el, response);
12026 if(typeof response.argument.callback == "function"){
12027 response.argument.callback(this.el, false, response);
12032 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12033 * @param {Object} renderer The object implementing the render() method
12035 setRenderer : function(renderer){
12036 this.renderer = renderer;
12039 getRenderer : function(){
12040 return this.renderer;
12044 * Set the defaultUrl used for updates
12045 * @param {String/Function} defaultUrl The url or a function to call to get the url
12047 setDefaultUrl : function(defaultUrl){
12048 this.defaultUrl = defaultUrl;
12052 * Aborts the executing transaction
12054 abort : function(){
12055 if(this.transaction){
12056 Roo.Ajax.abort(this.transaction);
12061 * Returns true if an update is in progress
12062 * @return {Boolean}
12064 isUpdating : function(){
12065 if(this.transaction){
12066 return Roo.Ajax.isLoading(this.transaction);
12073 * @class Roo.UpdateManager.defaults
12074 * @static (not really - but it helps the doc tool)
12075 * The defaults collection enables customizing the default properties of UpdateManager
12077 Roo.UpdateManager.defaults = {
12079 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12085 * True to process scripts by default (Defaults to false).
12088 loadScripts : false,
12091 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12094 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12096 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12099 disableCaching : false,
12101 * Whether to show indicatorText when loading (Defaults to true).
12104 showLoadIndicator : true,
12106 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12109 indicatorText : '<div class="loading-indicator">Loading...</div>'
12113 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12115 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12116 * @param {String/HTMLElement/Roo.Element} el The element to update
12117 * @param {String} url The url
12118 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12119 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12122 * @member Roo.UpdateManager
12124 Roo.UpdateManager.updateElement = function(el, url, params, options){
12125 var um = Roo.get(el, true).getUpdateManager();
12126 Roo.apply(um, options);
12127 um.update(url, params, options ? options.callback : null);
12129 // alias for backwards compat
12130 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12132 * @class Roo.UpdateManager.BasicRenderer
12133 * Default Content renderer. Updates the elements innerHTML with the responseText.
12135 Roo.UpdateManager.BasicRenderer = function(){};
12137 Roo.UpdateManager.BasicRenderer.prototype = {
12139 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12140 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12141 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12142 * @param {Roo.Element} el The element being rendered
12143 * @param {Object} response The YUI Connect response object
12144 * @param {UpdateManager} updateManager The calling update manager
12145 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12147 render : function(el, response, updateManager, callback){
12148 el.update(response.responseText, updateManager.loadScripts, callback);
12154 * (c)) Alan Knowles
12160 * @class Roo.DomTemplate
12161 * @extends Roo.Template
12162 * An effort at a dom based template engine..
12164 * Similar to XTemplate, except it uses dom parsing to create the template..
12166 * Supported features:
12171 {a_variable} - output encoded.
12172 {a_variable.format:("Y-m-d")} - call a method on the variable
12173 {a_variable:raw} - unencoded output
12174 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12175 {a_variable:this.method_on_template(...)} - call a method on the template object.
12180 <div roo-for="a_variable or condition.."></div>
12181 <div roo-if="a_variable or condition"></div>
12182 <div roo-exec="some javascript"></div>
12183 <div roo-name="named_template"></div>
12188 Roo.DomTemplate = function()
12190 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12197 Roo.extend(Roo.DomTemplate, Roo.Template, {
12199 * id counter for sub templates.
12203 * flag to indicate if dom parser is inside a pre,
12204 * it will strip whitespace if not.
12209 * The various sub templates
12217 * basic tag replacing syntax
12220 * // you can fake an object call by doing this
12224 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\}|\%7D)/g,
12225 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12227 iterChild : function (node, method) {
12229 var oldPre = this.inPre;
12230 if (node.tagName == 'PRE') {
12233 for( var i = 0; i < node.childNodes.length; i++) {
12234 method.call(this, node.childNodes[i]);
12236 this.inPre = oldPre;
12242 * compile the template
12244 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12247 compile: function()
12251 // covert the html into DOM...
12252 var doc = document.implementation.createHTMLDocument("");
12253 //doc.documentElement.innerHTML = htmlBody
12254 var div = doc.documentElement;
12255 div.innerHTML = this.html ;
12259 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12261 var tpls = this.tpls;
12263 // create a top level template from the snippet..
12265 //Roo.log(div.innerHTML);
12272 body : div.innerHTML,
12285 Roo.each(tpls, function(tp){
12286 this.compileTpl(tp);
12287 this.tpls[tp.id] = tp;
12290 this.master = tpls[0];
12296 compileNode : function(node, istop) {
12301 // skip anything not a tag..
12302 if (node.nodeType != 1) {
12303 if (node.nodeType == 3 && !this.inPre) {
12304 // reduce white space..
12305 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12328 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12329 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12330 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12331 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12337 // just itterate children..
12338 this.iterChild(node,this.compileNode);
12341 tpl.uid = this.id++;
12342 tpl.value = node.getAttribute('roo-' + tpl.attr);
12343 node.removeAttribute('roo-'+ tpl.attr);
12344 if (tpl.attr != 'name') {
12345 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12346 node.parentNode.replaceChild(placeholder, node);
12349 var placeholder = document.createElement('span');
12350 placeholder.className = 'roo-tpl-' + tpl.value;
12351 node.parentNode.replaceChild(placeholder, node);
12354 // parent now sees '{domtplXXXX}
12355 this.iterChild(node,this.compileNode);
12357 // we should now have node body...
12358 var div = document.createElement('div');
12359 div.appendChild(node);
12361 // this has the unfortunate side effect of converting tagged attributes
12362 // eg. href="{...}" into %7C...%7D
12363 // this has been fixed by searching for those combo's although it's a bit hacky..
12366 tpl.body = div.innerHTML;
12373 switch (tpl.value) {
12374 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12375 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12376 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12381 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12385 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12389 tpl.id = tpl.value; // replace non characters???
12395 this.tpls.push(tpl);
12405 * Compile a segment of the template into a 'sub-template'
12411 compileTpl : function(tpl)
12413 var fm = Roo.util.Format;
12414 var useF = this.disableFormats !== true;
12416 var sep = Roo.isGecko ? "+\n" : ",\n";
12418 var undef = function(str) {
12419 Roo.debug && Roo.log("Property not found :" + str);
12423 //Roo.log(tpl.body);
12427 var fn = function(m, lbrace, name, format, args)
12430 //Roo.log(arguments);
12431 args = args ? args.replace(/\\'/g,"'") : args;
12432 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12433 if (typeof(format) == 'undefined') {
12434 format = 'htmlEncode';
12436 if (format == 'raw' ) {
12440 if(name.substr(0, 6) == 'domtpl'){
12441 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12444 // build an array of options to determine if value is undefined..
12446 // basically get 'xxxx.yyyy' then do
12447 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12448 // (function () { Roo.log("Property not found"); return ''; })() :
12453 Roo.each(name.split('.'), function(st) {
12454 lookfor += (lookfor.length ? '.': '') + st;
12455 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12458 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12461 if(format && useF){
12463 args = args ? ',' + args : "";
12465 if(format.substr(0, 5) != "this."){
12466 format = "fm." + format + '(';
12468 format = 'this.call("'+ format.substr(5) + '", ';
12472 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12476 // called with xxyx.yuu:(test,test)
12478 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12480 // raw.. - :raw modifier..
12481 return "'"+ sep + udef_st + name + ")"+sep+"'";
12485 // branched to use + in gecko and [].join() in others
12487 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12488 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12491 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12492 body.push(tpl.body.replace(/(\r\n|\n)/g,
12493 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12494 body.push("'].join('');};};");
12495 body = body.join('');
12498 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12500 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12507 * same as applyTemplate, except it's done to one of the subTemplates
12508 * when using named templates, you can do:
12510 * var str = pl.applySubTemplate('your-name', values);
12513 * @param {Number} id of the template
12514 * @param {Object} values to apply to template
12515 * @param {Object} parent (normaly the instance of this object)
12517 applySubTemplate : function(id, values, parent)
12521 var t = this.tpls[id];
12525 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12526 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12530 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12537 if(t.execCall && t.execCall.call(this, values, parent)){
12541 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12547 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12548 parent = t.target ? values : parent;
12549 if(t.forCall && vs instanceof Array){
12551 for(var i = 0, len = vs.length; i < len; i++){
12553 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12555 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12557 //Roo.log(t.compiled);
12561 return buf.join('');
12564 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12569 return t.compiled.call(this, vs, parent);
12571 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12573 //Roo.log(t.compiled);
12581 applyTemplate : function(values){
12582 return this.master.compiled.call(this, values, {});
12583 //var s = this.subs;
12586 apply : function(){
12587 return this.applyTemplate.apply(this, arguments);
12592 Roo.DomTemplate.from = function(el){
12593 el = Roo.getDom(el);
12594 return new Roo.Domtemplate(el.value || el.innerHTML);
12597 * Ext JS Library 1.1.1
12598 * Copyright(c) 2006-2007, Ext JS, LLC.
12600 * Originally Released Under LGPL - original licence link has changed is not relivant.
12603 * <script type="text/javascript">
12607 * @class Roo.util.DelayedTask
12608 * Provides a convenient method of performing setTimeout where a new
12609 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12610 * You can use this class to buffer
12611 * the keypress events for a certain number of milliseconds, and perform only if they stop
12612 * for that amount of time.
12613 * @constructor The parameters to this constructor serve as defaults and are not required.
12614 * @param {Function} fn (optional) The default function to timeout
12615 * @param {Object} scope (optional) The default scope of that timeout
12616 * @param {Array} args (optional) The default Array of arguments
12618 Roo.util.DelayedTask = function(fn, scope, args){
12619 var id = null, d, t;
12621 var call = function(){
12622 var now = new Date().getTime();
12626 fn.apply(scope, args || []);
12630 * Cancels any pending timeout and queues a new one
12631 * @param {Number} delay The milliseconds to delay
12632 * @param {Function} newFn (optional) Overrides function passed to constructor
12633 * @param {Object} newScope (optional) Overrides scope passed to constructor
12634 * @param {Array} newArgs (optional) Overrides args passed to constructor
12636 this.delay = function(delay, newFn, newScope, newArgs){
12637 if(id && delay != d){
12641 t = new Date().getTime();
12643 scope = newScope || scope;
12644 args = newArgs || args;
12646 id = setInterval(call, d);
12651 * Cancel the last queued timeout
12653 this.cancel = function(){
12661 * Ext JS Library 1.1.1
12662 * Copyright(c) 2006-2007, Ext JS, LLC.
12664 * Originally Released Under LGPL - original licence link has changed is not relivant.
12667 * <script type="text/javascript">
12671 Roo.util.TaskRunner = function(interval){
12672 interval = interval || 10;
12673 var tasks = [], removeQueue = [];
12675 var running = false;
12677 var stopThread = function(){
12683 var startThread = function(){
12686 id = setInterval(runTasks, interval);
12690 var removeTask = function(task){
12691 removeQueue.push(task);
12697 var runTasks = function(){
12698 if(removeQueue.length > 0){
12699 for(var i = 0, len = removeQueue.length; i < len; i++){
12700 tasks.remove(removeQueue[i]);
12703 if(tasks.length < 1){
12708 var now = new Date().getTime();
12709 for(var i = 0, len = tasks.length; i < len; ++i){
12711 var itime = now - t.taskRunTime;
12712 if(t.interval <= itime){
12713 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12714 t.taskRunTime = now;
12715 if(rt === false || t.taskRunCount === t.repeat){
12720 if(t.duration && t.duration <= (now - t.taskStartTime)){
12727 * Queues a new task.
12728 * @param {Object} task
12730 this.start = function(task){
12732 task.taskStartTime = new Date().getTime();
12733 task.taskRunTime = 0;
12734 task.taskRunCount = 0;
12739 this.stop = function(task){
12744 this.stopAll = function(){
12746 for(var i = 0, len = tasks.length; i < len; i++){
12747 if(tasks[i].onStop){
12756 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12758 * Ext JS Library 1.1.1
12759 * Copyright(c) 2006-2007, Ext JS, LLC.
12761 * Originally Released Under LGPL - original licence link has changed is not relivant.
12764 * <script type="text/javascript">
12769 * @class Roo.util.MixedCollection
12770 * @extends Roo.util.Observable
12771 * A Collection class that maintains both numeric indexes and keys and exposes events.
12773 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12774 * collection (defaults to false)
12775 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12776 * and return the key value for that item. This is used when available to look up the key on items that
12777 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12778 * equivalent to providing an implementation for the {@link #getKey} method.
12780 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12788 * Fires when the collection is cleared.
12793 * Fires when an item is added to the collection.
12794 * @param {Number} index The index at which the item was added.
12795 * @param {Object} o The item added.
12796 * @param {String} key The key associated with the added item.
12801 * Fires when an item is replaced in the collection.
12802 * @param {String} key he key associated with the new added.
12803 * @param {Object} old The item being replaced.
12804 * @param {Object} new The new item.
12809 * Fires when an item is removed from the collection.
12810 * @param {Object} o The item being removed.
12811 * @param {String} key (optional) The key associated with the removed item.
12816 this.allowFunctions = allowFunctions === true;
12818 this.getKey = keyFn;
12820 Roo.util.MixedCollection.superclass.constructor.call(this);
12823 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12824 allowFunctions : false,
12827 * Adds an item to the collection.
12828 * @param {String} key The key to associate with the item
12829 * @param {Object} o The item to add.
12830 * @return {Object} The item added.
12832 add : function(key, o){
12833 if(arguments.length == 1){
12835 key = this.getKey(o);
12837 if(typeof key == "undefined" || key === null){
12839 this.items.push(o);
12840 this.keys.push(null);
12842 var old = this.map[key];
12844 return this.replace(key, o);
12847 this.items.push(o);
12849 this.keys.push(key);
12851 this.fireEvent("add", this.length-1, o, key);
12856 * MixedCollection has a generic way to fetch keys if you implement getKey.
12859 var mc = new Roo.util.MixedCollection();
12860 mc.add(someEl.dom.id, someEl);
12861 mc.add(otherEl.dom.id, otherEl);
12865 var mc = new Roo.util.MixedCollection();
12866 mc.getKey = function(el){
12872 // or via the constructor
12873 var mc = new Roo.util.MixedCollection(false, function(el){
12879 * @param o {Object} The item for which to find the key.
12880 * @return {Object} The key for the passed item.
12882 getKey : function(o){
12887 * Replaces an item in the collection.
12888 * @param {String} key The key associated with the item to replace, or the item to replace.
12889 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12890 * @return {Object} The new item.
12892 replace : function(key, o){
12893 if(arguments.length == 1){
12895 key = this.getKey(o);
12897 var old = this.item(key);
12898 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12899 return this.add(key, o);
12901 var index = this.indexOfKey(key);
12902 this.items[index] = o;
12904 this.fireEvent("replace", key, old, o);
12909 * Adds all elements of an Array or an Object to the collection.
12910 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12911 * an Array of values, each of which are added to the collection.
12913 addAll : function(objs){
12914 if(arguments.length > 1 || objs instanceof Array){
12915 var args = arguments.length > 1 ? arguments : objs;
12916 for(var i = 0, len = args.length; i < len; i++){
12920 for(var key in objs){
12921 if(this.allowFunctions || typeof objs[key] != "function"){
12922 this.add(key, objs[key]);
12929 * Executes the specified function once for every item in the collection, passing each
12930 * item as the first and only parameter. returning false from the function will stop the iteration.
12931 * @param {Function} fn The function to execute for each item.
12932 * @param {Object} scope (optional) The scope in which to execute the function.
12934 each : function(fn, scope){
12935 var items = [].concat(this.items); // each safe for removal
12936 for(var i = 0, len = items.length; i < len; i++){
12937 if(fn.call(scope || items[i], items[i], i, len) === false){
12944 * Executes the specified function once for every key in the collection, passing each
12945 * key, and its associated item as the first two parameters.
12946 * @param {Function} fn The function to execute for each item.
12947 * @param {Object} scope (optional) The scope in which to execute the function.
12949 eachKey : function(fn, scope){
12950 for(var i = 0, len = this.keys.length; i < len; i++){
12951 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12956 * Returns the first item in the collection which elicits a true return value from the
12957 * passed selection function.
12958 * @param {Function} fn The selection function to execute for each item.
12959 * @param {Object} scope (optional) The scope in which to execute the function.
12960 * @return {Object} The first item in the collection which returned true from the selection function.
12962 find : function(fn, scope){
12963 for(var i = 0, len = this.items.length; i < len; i++){
12964 if(fn.call(scope || window, this.items[i], this.keys[i])){
12965 return this.items[i];
12972 * Inserts an item at the specified index in the collection.
12973 * @param {Number} index The index to insert the item at.
12974 * @param {String} key The key to associate with the new item, or the item itself.
12975 * @param {Object} o (optional) If the second parameter was a key, the new item.
12976 * @return {Object} The item inserted.
12978 insert : function(index, key, o){
12979 if(arguments.length == 2){
12981 key = this.getKey(o);
12983 if(index >= this.length){
12984 return this.add(key, o);
12987 this.items.splice(index, 0, o);
12988 if(typeof key != "undefined" && key != null){
12991 this.keys.splice(index, 0, key);
12992 this.fireEvent("add", index, o, key);
12997 * Removed an item from the collection.
12998 * @param {Object} o The item to remove.
12999 * @return {Object} The item removed.
13001 remove : function(o){
13002 return this.removeAt(this.indexOf(o));
13006 * Remove an item from a specified index in the collection.
13007 * @param {Number} index The index within the collection of the item to remove.
13009 removeAt : function(index){
13010 if(index < this.length && index >= 0){
13012 var o = this.items[index];
13013 this.items.splice(index, 1);
13014 var key = this.keys[index];
13015 if(typeof key != "undefined"){
13016 delete this.map[key];
13018 this.keys.splice(index, 1);
13019 this.fireEvent("remove", o, key);
13024 * Removed an item associated with the passed key fom the collection.
13025 * @param {String} key The key of the item to remove.
13027 removeKey : function(key){
13028 return this.removeAt(this.indexOfKey(key));
13032 * Returns the number of items in the collection.
13033 * @return {Number} the number of items in the collection.
13035 getCount : function(){
13036 return this.length;
13040 * Returns index within the collection of the passed Object.
13041 * @param {Object} o The item to find the index of.
13042 * @return {Number} index of the item.
13044 indexOf : function(o){
13045 if(!this.items.indexOf){
13046 for(var i = 0, len = this.items.length; i < len; i++){
13047 if(this.items[i] == o) return i;
13051 return this.items.indexOf(o);
13056 * Returns index within the collection of the passed key.
13057 * @param {String} key The key to find the index of.
13058 * @return {Number} index of the key.
13060 indexOfKey : function(key){
13061 if(!this.keys.indexOf){
13062 for(var i = 0, len = this.keys.length; i < len; i++){
13063 if(this.keys[i] == key) return i;
13067 return this.keys.indexOf(key);
13072 * Returns the item associated with the passed key OR index. Key has priority over index.
13073 * @param {String/Number} key The key or index of the item.
13074 * @return {Object} The item associated with the passed key.
13076 item : function(key){
13077 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13078 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13082 * Returns the item at the specified index.
13083 * @param {Number} index The index of the item.
13086 itemAt : function(index){
13087 return this.items[index];
13091 * Returns the item associated with the passed key.
13092 * @param {String/Number} key The key of the item.
13093 * @return {Object} The item associated with the passed key.
13095 key : function(key){
13096 return this.map[key];
13100 * Returns true if the collection contains the passed Object as an item.
13101 * @param {Object} o The Object to look for in the collection.
13102 * @return {Boolean} True if the collection contains the Object as an item.
13104 contains : function(o){
13105 return this.indexOf(o) != -1;
13109 * Returns true if the collection contains the passed Object as a key.
13110 * @param {String} key The key to look for in the collection.
13111 * @return {Boolean} True if the collection contains the Object as a key.
13113 containsKey : function(key){
13114 return typeof this.map[key] != "undefined";
13118 * Removes all items from the collection.
13120 clear : function(){
13125 this.fireEvent("clear");
13129 * Returns the first item in the collection.
13130 * @return {Object} the first item in the collection..
13132 first : function(){
13133 return this.items[0];
13137 * Returns the last item in the collection.
13138 * @return {Object} the last item in the collection..
13141 return this.items[this.length-1];
13144 _sort : function(property, dir, fn){
13145 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13146 fn = fn || function(a, b){
13149 var c = [], k = this.keys, items = this.items;
13150 for(var i = 0, len = items.length; i < len; i++){
13151 c[c.length] = {key: k[i], value: items[i], index: i};
13153 c.sort(function(a, b){
13154 var v = fn(a[property], b[property]) * dsc;
13156 v = (a.index < b.index ? -1 : 1);
13160 for(var i = 0, len = c.length; i < len; i++){
13161 items[i] = c[i].value;
13164 this.fireEvent("sort", this);
13168 * Sorts this collection with the passed comparison function
13169 * @param {String} direction (optional) "ASC" or "DESC"
13170 * @param {Function} fn (optional) comparison function
13172 sort : function(dir, fn){
13173 this._sort("value", dir, fn);
13177 * Sorts this collection by keys
13178 * @param {String} direction (optional) "ASC" or "DESC"
13179 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13181 keySort : function(dir, fn){
13182 this._sort("key", dir, fn || function(a, b){
13183 return String(a).toUpperCase()-String(b).toUpperCase();
13188 * Returns a range of items in this collection
13189 * @param {Number} startIndex (optional) defaults to 0
13190 * @param {Number} endIndex (optional) default to the last item
13191 * @return {Array} An array of items
13193 getRange : function(start, end){
13194 var items = this.items;
13195 if(items.length < 1){
13198 start = start || 0;
13199 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13202 for(var i = start; i <= end; i++) {
13203 r[r.length] = items[i];
13206 for(var i = start; i >= end; i--) {
13207 r[r.length] = items[i];
13214 * Filter the <i>objects</i> in this collection by a specific property.
13215 * Returns a new collection that has been filtered.
13216 * @param {String} property A property on your objects
13217 * @param {String/RegExp} value Either string that the property values
13218 * should start with or a RegExp to test against the property
13219 * @return {MixedCollection} The new filtered collection
13221 filter : function(property, value){
13222 if(!value.exec){ // not a regex
13223 value = String(value);
13224 if(value.length == 0){
13225 return this.clone();
13227 value = new RegExp("^" + Roo.escapeRe(value), "i");
13229 return this.filterBy(function(o){
13230 return o && value.test(o[property]);
13235 * Filter by a function. * Returns a new collection that has been filtered.
13236 * The passed function will be called with each
13237 * object in the collection. If the function returns true, the value is included
13238 * otherwise it is filtered.
13239 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13240 * @param {Object} scope (optional) The scope of the function (defaults to this)
13241 * @return {MixedCollection} The new filtered collection
13243 filterBy : function(fn, scope){
13244 var r = new Roo.util.MixedCollection();
13245 r.getKey = this.getKey;
13246 var k = this.keys, it = this.items;
13247 for(var i = 0, len = it.length; i < len; i++){
13248 if(fn.call(scope||this, it[i], k[i])){
13249 r.add(k[i], it[i]);
13256 * Creates a duplicate of this collection
13257 * @return {MixedCollection}
13259 clone : function(){
13260 var r = new Roo.util.MixedCollection();
13261 var k = this.keys, it = this.items;
13262 for(var i = 0, len = it.length; i < len; i++){
13263 r.add(k[i], it[i]);
13265 r.getKey = this.getKey;
13270 * Returns the item associated with the passed key or index.
13272 * @param {String/Number} key The key or index of the item.
13273 * @return {Object} The item associated with the passed key.
13275 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13277 * Ext JS Library 1.1.1
13278 * Copyright(c) 2006-2007, Ext JS, LLC.
13280 * Originally Released Under LGPL - original licence link has changed is not relivant.
13283 * <script type="text/javascript">
13286 * @class Roo.util.JSON
13287 * Modified version of Douglas Crockford"s json.js that doesn"t
13288 * mess with the Object prototype
13289 * http://www.json.org/js.html
13292 Roo.util.JSON = new (function(){
13293 var useHasOwn = {}.hasOwnProperty ? true : false;
13295 // crashes Safari in some instances
13296 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13298 var pad = function(n) {
13299 return n < 10 ? "0" + n : n;
13312 var encodeString = function(s){
13313 if (/["\\\x00-\x1f]/.test(s)) {
13314 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13319 c = b.charCodeAt();
13321 Math.floor(c / 16).toString(16) +
13322 (c % 16).toString(16);
13325 return '"' + s + '"';
13328 var encodeArray = function(o){
13329 var a = ["["], b, i, l = o.length, v;
13330 for (i = 0; i < l; i += 1) {
13332 switch (typeof v) {
13341 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13349 var encodeDate = function(o){
13350 return '"' + o.getFullYear() + "-" +
13351 pad(o.getMonth() + 1) + "-" +
13352 pad(o.getDate()) + "T" +
13353 pad(o.getHours()) + ":" +
13354 pad(o.getMinutes()) + ":" +
13355 pad(o.getSeconds()) + '"';
13359 * Encodes an Object, Array or other value
13360 * @param {Mixed} o The variable to encode
13361 * @return {String} The JSON string
13363 this.encode = function(o)
13365 // should this be extended to fully wrap stringify..
13367 if(typeof o == "undefined" || o === null){
13369 }else if(o instanceof Array){
13370 return encodeArray(o);
13371 }else if(o instanceof Date){
13372 return encodeDate(o);
13373 }else if(typeof o == "string"){
13374 return encodeString(o);
13375 }else if(typeof o == "number"){
13376 return isFinite(o) ? String(o) : "null";
13377 }else if(typeof o == "boolean"){
13380 var a = ["{"], b, i, v;
13382 if(!useHasOwn || o.hasOwnProperty(i)) {
13384 switch (typeof v) {
13393 a.push(this.encode(i), ":",
13394 v === null ? "null" : this.encode(v));
13405 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13406 * @param {String} json The JSON string
13407 * @return {Object} The resulting object
13409 this.decode = function(json){
13411 return /** eval:var:json */ eval("(" + json + ')');
13415 * Shorthand for {@link Roo.util.JSON#encode}
13416 * @member Roo encode
13418 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13420 * Shorthand for {@link Roo.util.JSON#decode}
13421 * @member Roo decode
13423 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13426 * Ext JS Library 1.1.1
13427 * Copyright(c) 2006-2007, Ext JS, LLC.
13429 * Originally Released Under LGPL - original licence link has changed is not relivant.
13432 * <script type="text/javascript">
13436 * @class Roo.util.Format
13437 * Reusable data formatting functions
13440 Roo.util.Format = function(){
13441 var trimRe = /^\s+|\s+$/g;
13444 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13445 * @param {String} value The string to truncate
13446 * @param {Number} length The maximum length to allow before truncating
13447 * @return {String} The converted text
13449 ellipsis : function(value, len){
13450 if(value && value.length > len){
13451 return value.substr(0, len-3)+"...";
13457 * Checks a reference and converts it to empty string if it is undefined
13458 * @param {Mixed} value Reference to check
13459 * @return {Mixed} Empty string if converted, otherwise the original value
13461 undef : function(value){
13462 return typeof value != "undefined" ? value : "";
13466 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13467 * @param {String} value The string to encode
13468 * @return {String} The encoded text
13470 htmlEncode : function(value){
13471 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13475 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13476 * @param {String} value The string to decode
13477 * @return {String} The decoded text
13479 htmlDecode : function(value){
13480 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13484 * Trims any whitespace from either side of a string
13485 * @param {String} value The text to trim
13486 * @return {String} The trimmed text
13488 trim : function(value){
13489 return String(value).replace(trimRe, "");
13493 * Returns a substring from within an original string
13494 * @param {String} value The original text
13495 * @param {Number} start The start index of the substring
13496 * @param {Number} length The length of the substring
13497 * @return {String} The substring
13499 substr : function(value, start, length){
13500 return String(value).substr(start, length);
13504 * Converts a string to all lower case letters
13505 * @param {String} value The text to convert
13506 * @return {String} The converted text
13508 lowercase : function(value){
13509 return String(value).toLowerCase();
13513 * Converts a string to all upper case letters
13514 * @param {String} value The text to convert
13515 * @return {String} The converted text
13517 uppercase : function(value){
13518 return String(value).toUpperCase();
13522 * Converts the first character only of a string to upper case
13523 * @param {String} value The text to convert
13524 * @return {String} The converted text
13526 capitalize : function(value){
13527 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13531 call : function(value, fn){
13532 if(arguments.length > 2){
13533 var args = Array.prototype.slice.call(arguments, 2);
13534 args.unshift(value);
13536 return /** eval:var:value */ eval(fn).apply(window, args);
13538 /** eval:var:value */
13539 return /** eval:var:value */ eval(fn).call(window, value);
13545 * safer version of Math.toFixed..??/
13546 * @param {Number/String} value The numeric value to format
13547 * @param {Number/String} value Decimal places
13548 * @return {String} The formatted currency string
13550 toFixed : function(v, n)
13552 // why not use to fixed - precision is buggered???
13554 return Math.round(v-0);
13556 var fact = Math.pow(10,n+1);
13557 v = (Math.round((v-0)*fact))/fact;
13558 var z = (''+fact).substring(2);
13559 if (v == Math.floor(v)) {
13560 return Math.floor(v) + '.' + z;
13563 // now just padd decimals..
13564 var ps = String(v).split('.');
13565 var fd = (ps[1] + z);
13566 var r = fd.substring(0,n);
13567 var rm = fd.substring(n);
13569 return ps[0] + '.' + r;
13571 r*=1; // turn it into a number;
13573 if (String(r).length != n) {
13576 r = String(r).substring(1); // chop the end off.
13579 return ps[0] + '.' + r;
13584 * Format a number as US currency
13585 * @param {Number/String} value The numeric value to format
13586 * @return {String} The formatted currency string
13588 usMoney : function(v){
13589 return '$' + Roo.util.Format.number(v);
13594 * eventually this should probably emulate php's number_format
13595 * @param {Number/String} value The numeric value to format
13596 * @param {Number} decimals number of decimal places
13597 * @return {String} The formatted currency string
13599 number : function(v,decimals)
13601 // multiply and round.
13602 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13603 var mul = Math.pow(10, decimals);
13604 var zero = String(mul).substring(1);
13605 v = (Math.round((v-0)*mul))/mul;
13607 // if it's '0' number.. then
13609 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13611 var ps = v.split('.');
13615 var r = /(\d+)(\d{3})/;
13617 while (r.test(whole)) {
13618 whole = whole.replace(r, '$1' + ',' + '$2');
13624 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13625 // does not have decimals
13626 (decimals ? ('.' + zero) : '');
13629 return whole + sub ;
13633 * Parse a value into a formatted date using the specified format pattern.
13634 * @param {Mixed} value The value to format
13635 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13636 * @return {String} The formatted date string
13638 date : function(v, format){
13642 if(!(v instanceof Date)){
13643 v = new Date(Date.parse(v));
13645 return v.dateFormat(format || "m/d/Y");
13649 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13650 * @param {String} format Any valid date format string
13651 * @return {Function} The date formatting function
13653 dateRenderer : function(format){
13654 return function(v){
13655 return Roo.util.Format.date(v, format);
13660 stripTagsRE : /<\/?[^>]+>/gi,
13663 * Strips all HTML tags
13664 * @param {Mixed} value The text from which to strip tags
13665 * @return {String} The stripped text
13667 stripTags : function(v){
13668 return !v ? v : String(v).replace(this.stripTagsRE, "");
13673 * Ext JS Library 1.1.1
13674 * Copyright(c) 2006-2007, Ext JS, LLC.
13676 * Originally Released Under LGPL - original licence link has changed is not relivant.
13679 * <script type="text/javascript">
13686 * @class Roo.MasterTemplate
13687 * @extends Roo.Template
13688 * Provides a template that can have child templates. The syntax is:
13690 var t = new Roo.MasterTemplate(
13691 '<select name="{name}">',
13692 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13695 t.add('options', {value: 'foo', text: 'bar'});
13696 // or you can add multiple child elements in one shot
13697 t.addAll('options', [
13698 {value: 'foo', text: 'bar'},
13699 {value: 'foo2', text: 'bar2'},
13700 {value: 'foo3', text: 'bar3'}
13702 // then append, applying the master template values
13703 t.append('my-form', {name: 'my-select'});
13705 * A name attribute for the child template is not required if you have only one child
13706 * template or you want to refer to them by index.
13708 Roo.MasterTemplate = function(){
13709 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13710 this.originalHtml = this.html;
13712 var m, re = this.subTemplateRe;
13715 while(m = re.exec(this.html)){
13716 var name = m[1], content = m[2];
13721 tpl : new Roo.Template(content)
13724 st[name] = st[subIndex];
13726 st[subIndex].tpl.compile();
13727 st[subIndex].tpl.call = this.call.createDelegate(this);
13730 this.subCount = subIndex;
13733 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13735 * The regular expression used to match sub templates
13739 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13742 * Applies the passed values to a child template.
13743 * @param {String/Number} name (optional) The name or index of the child template
13744 * @param {Array/Object} values The values to be applied to the template
13745 * @return {MasterTemplate} this
13747 add : function(name, values){
13748 if(arguments.length == 1){
13749 values = arguments[0];
13752 var s = this.subs[name];
13753 s.buffer[s.buffer.length] = s.tpl.apply(values);
13758 * Applies all the passed values to a child template.
13759 * @param {String/Number} name (optional) The name or index of the child template
13760 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13761 * @param {Boolean} reset (optional) True to reset the template first
13762 * @return {MasterTemplate} this
13764 fill : function(name, values, reset){
13766 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13774 for(var i = 0, len = values.length; i < len; i++){
13775 this.add(name, values[i]);
13781 * Resets the template for reuse
13782 * @return {MasterTemplate} this
13784 reset : function(){
13786 for(var i = 0; i < this.subCount; i++){
13792 applyTemplate : function(values){
13794 var replaceIndex = -1;
13795 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13796 return s[++replaceIndex].buffer.join("");
13798 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13801 apply : function(){
13802 return this.applyTemplate.apply(this, arguments);
13805 compile : function(){return this;}
13809 * Alias for fill().
13812 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13814 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13815 * var tpl = Roo.MasterTemplate.from('element-id');
13816 * @param {String/HTMLElement} el
13817 * @param {Object} config
13820 Roo.MasterTemplate.from = function(el, config){
13821 el = Roo.getDom(el);
13822 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13825 * Ext JS Library 1.1.1
13826 * Copyright(c) 2006-2007, Ext JS, LLC.
13828 * Originally Released Under LGPL - original licence link has changed is not relivant.
13831 * <script type="text/javascript">
13836 * @class Roo.util.CSS
13837 * Utility class for manipulating CSS rules
13840 Roo.util.CSS = function(){
13842 var doc = document;
13844 var camelRe = /(-[a-z])/gi;
13845 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13849 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13850 * tag and appended to the HEAD of the document.
13851 * @param {String|Object} cssText The text containing the css rules
13852 * @param {String} id An id to add to the stylesheet for later removal
13853 * @return {StyleSheet}
13855 createStyleSheet : function(cssText, id){
13857 var head = doc.getElementsByTagName("head")[0];
13858 var nrules = doc.createElement("style");
13859 nrules.setAttribute("type", "text/css");
13861 nrules.setAttribute("id", id);
13863 if (typeof(cssText) != 'string') {
13864 // support object maps..
13865 // not sure if this a good idea..
13866 // perhaps it should be merged with the general css handling
13867 // and handle js style props.
13868 var cssTextNew = [];
13869 for(var n in cssText) {
13871 for(var k in cssText[n]) {
13872 citems.push( k + ' : ' +cssText[n][k] + ';' );
13874 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13877 cssText = cssTextNew.join("\n");
13883 head.appendChild(nrules);
13884 ss = nrules.styleSheet;
13885 ss.cssText = cssText;
13888 nrules.appendChild(doc.createTextNode(cssText));
13890 nrules.cssText = cssText;
13892 head.appendChild(nrules);
13893 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13895 this.cacheStyleSheet(ss);
13900 * Removes a style or link tag by id
13901 * @param {String} id The id of the tag
13903 removeStyleSheet : function(id){
13904 var existing = doc.getElementById(id);
13906 existing.parentNode.removeChild(existing);
13911 * Dynamically swaps an existing stylesheet reference for a new one
13912 * @param {String} id The id of an existing link tag to remove
13913 * @param {String} url The href of the new stylesheet to include
13915 swapStyleSheet : function(id, url){
13916 this.removeStyleSheet(id);
13917 var ss = doc.createElement("link");
13918 ss.setAttribute("rel", "stylesheet");
13919 ss.setAttribute("type", "text/css");
13920 ss.setAttribute("id", id);
13921 ss.setAttribute("href", url);
13922 doc.getElementsByTagName("head")[0].appendChild(ss);
13926 * Refresh the rule cache if you have dynamically added stylesheets
13927 * @return {Object} An object (hash) of rules indexed by selector
13929 refreshCache : function(){
13930 return this.getRules(true);
13934 cacheStyleSheet : function(stylesheet){
13938 try{// try catch for cross domain access issue
13939 var ssRules = stylesheet.cssRules || stylesheet.rules;
13940 for(var j = ssRules.length-1; j >= 0; --j){
13941 rules[ssRules[j].selectorText] = ssRules[j];
13947 * Gets all css rules for the document
13948 * @param {Boolean} refreshCache true to refresh the internal cache
13949 * @return {Object} An object (hash) of rules indexed by selector
13951 getRules : function(refreshCache){
13952 if(rules == null || refreshCache){
13954 var ds = doc.styleSheets;
13955 for(var i =0, len = ds.length; i < len; i++){
13957 this.cacheStyleSheet(ds[i]);
13965 * Gets an an individual CSS rule by selector(s)
13966 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13967 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13968 * @return {CSSRule} The CSS rule or null if one is not found
13970 getRule : function(selector, refreshCache){
13971 var rs = this.getRules(refreshCache);
13972 if(!(selector instanceof Array)){
13973 return rs[selector];
13975 for(var i = 0; i < selector.length; i++){
13976 if(rs[selector[i]]){
13977 return rs[selector[i]];
13985 * Updates a rule property
13986 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13987 * @param {String} property The css property
13988 * @param {String} value The new value for the property
13989 * @return {Boolean} true If a rule was found and updated
13991 updateRule : function(selector, property, value){
13992 if(!(selector instanceof Array)){
13993 var rule = this.getRule(selector);
13995 rule.style[property.replace(camelRe, camelFn)] = value;
13999 for(var i = 0; i < selector.length; i++){
14000 if(this.updateRule(selector[i], property, value)){
14010 * Ext JS Library 1.1.1
14011 * Copyright(c) 2006-2007, Ext JS, LLC.
14013 * Originally Released Under LGPL - original licence link has changed is not relivant.
14016 * <script type="text/javascript">
14022 * @class Roo.util.ClickRepeater
14023 * @extends Roo.util.Observable
14025 * A wrapper class which can be applied to any element. Fires a "click" event while the
14026 * mouse is pressed. The interval between firings may be specified in the config but
14027 * defaults to 10 milliseconds.
14029 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14031 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14032 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14033 * Similar to an autorepeat key delay.
14034 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14035 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14036 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14037 * "interval" and "delay" are ignored. "immediate" is honored.
14038 * @cfg {Boolean} preventDefault True to prevent the default click event
14039 * @cfg {Boolean} stopDefault True to stop the default click event
14042 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14043 * 2007-02-02 jvs Renamed to ClickRepeater
14044 * 2007-02-03 jvs Modifications for FF Mac and Safari
14047 * @param {String/HTMLElement/Element} el The element to listen on
14048 * @param {Object} config
14050 Roo.util.ClickRepeater = function(el, config)
14052 this.el = Roo.get(el);
14053 this.el.unselectable();
14055 Roo.apply(this, config);
14060 * Fires when the mouse button is depressed.
14061 * @param {Roo.util.ClickRepeater} this
14063 "mousedown" : true,
14066 * Fires on a specified interval during the time the element is pressed.
14067 * @param {Roo.util.ClickRepeater} this
14072 * Fires when the mouse key is released.
14073 * @param {Roo.util.ClickRepeater} this
14078 this.el.on("mousedown", this.handleMouseDown, this);
14079 if(this.preventDefault || this.stopDefault){
14080 this.el.on("click", function(e){
14081 if(this.preventDefault){
14082 e.preventDefault();
14084 if(this.stopDefault){
14090 // allow inline handler
14092 this.on("click", this.handler, this.scope || this);
14095 Roo.util.ClickRepeater.superclass.constructor.call(this);
14098 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14101 preventDefault : true,
14102 stopDefault : false,
14106 handleMouseDown : function(){
14107 clearTimeout(this.timer);
14109 if(this.pressClass){
14110 this.el.addClass(this.pressClass);
14112 this.mousedownTime = new Date();
14114 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14115 this.el.on("mouseout", this.handleMouseOut, this);
14117 this.fireEvent("mousedown", this);
14118 this.fireEvent("click", this);
14120 this.timer = this.click.defer(this.delay || this.interval, this);
14124 click : function(){
14125 this.fireEvent("click", this);
14126 this.timer = this.click.defer(this.getInterval(), this);
14130 getInterval: function(){
14131 if(!this.accelerate){
14132 return this.interval;
14134 var pressTime = this.mousedownTime.getElapsed();
14135 if(pressTime < 500){
14137 }else if(pressTime < 1700){
14139 }else if(pressTime < 2600){
14141 }else if(pressTime < 3500){
14143 }else if(pressTime < 4400){
14145 }else if(pressTime < 5300){
14147 }else if(pressTime < 6200){
14155 handleMouseOut : function(){
14156 clearTimeout(this.timer);
14157 if(this.pressClass){
14158 this.el.removeClass(this.pressClass);
14160 this.el.on("mouseover", this.handleMouseReturn, this);
14164 handleMouseReturn : function(){
14165 this.el.un("mouseover", this.handleMouseReturn);
14166 if(this.pressClass){
14167 this.el.addClass(this.pressClass);
14173 handleMouseUp : function(){
14174 clearTimeout(this.timer);
14175 this.el.un("mouseover", this.handleMouseReturn);
14176 this.el.un("mouseout", this.handleMouseOut);
14177 Roo.get(document).un("mouseup", this.handleMouseUp);
14178 this.el.removeClass(this.pressClass);
14179 this.fireEvent("mouseup", this);
14183 * Ext JS Library 1.1.1
14184 * Copyright(c) 2006-2007, Ext JS, LLC.
14186 * Originally Released Under LGPL - original licence link has changed is not relivant.
14189 * <script type="text/javascript">
14194 * @class Roo.KeyNav
14195 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14196 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14197 * way to implement custom navigation schemes for any UI component.</p>
14198 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14199 * pageUp, pageDown, del, home, end. Usage:</p>
14201 var nav = new Roo.KeyNav("my-element", {
14202 "left" : function(e){
14203 this.moveLeft(e.ctrlKey);
14205 "right" : function(e){
14206 this.moveRight(e.ctrlKey);
14208 "enter" : function(e){
14215 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14216 * @param {Object} config The config
14218 Roo.KeyNav = function(el, config){
14219 this.el = Roo.get(el);
14220 Roo.apply(this, config);
14221 if(!this.disabled){
14222 this.disabled = true;
14227 Roo.KeyNav.prototype = {
14229 * @cfg {Boolean} disabled
14230 * True to disable this KeyNav instance (defaults to false)
14234 * @cfg {String} defaultEventAction
14235 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14236 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14237 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14239 defaultEventAction: "stopEvent",
14241 * @cfg {Boolean} forceKeyDown
14242 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14243 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14244 * handle keydown instead of keypress.
14246 forceKeyDown : false,
14249 prepareEvent : function(e){
14250 var k = e.getKey();
14251 var h = this.keyToHandler[k];
14252 //if(h && this[h]){
14253 // e.stopPropagation();
14255 if(Roo.isSafari && h && k >= 37 && k <= 40){
14261 relay : function(e){
14262 var k = e.getKey();
14263 var h = this.keyToHandler[k];
14265 if(this.doRelay(e, this[h], h) !== true){
14266 e[this.defaultEventAction]();
14272 doRelay : function(e, h, hname){
14273 return h.call(this.scope || this, e);
14276 // possible handlers
14290 // quick lookup hash
14307 * Enable this KeyNav
14309 enable: function(){
14311 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14312 // the EventObject will normalize Safari automatically
14313 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14314 this.el.on("keydown", this.relay, this);
14316 this.el.on("keydown", this.prepareEvent, this);
14317 this.el.on("keypress", this.relay, this);
14319 this.disabled = false;
14324 * Disable this KeyNav
14326 disable: function(){
14327 if(!this.disabled){
14328 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14329 this.el.un("keydown", this.relay);
14331 this.el.un("keydown", this.prepareEvent);
14332 this.el.un("keypress", this.relay);
14334 this.disabled = true;
14339 * Ext JS Library 1.1.1
14340 * Copyright(c) 2006-2007, Ext JS, LLC.
14342 * Originally Released Under LGPL - original licence link has changed is not relivant.
14345 * <script type="text/javascript">
14350 * @class Roo.KeyMap
14351 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14352 * The constructor accepts the same config object as defined by {@link #addBinding}.
14353 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14354 * combination it will call the function with this signature (if the match is a multi-key
14355 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14356 * A KeyMap can also handle a string representation of keys.<br />
14359 // map one key by key code
14360 var map = new Roo.KeyMap("my-element", {
14361 key: 13, // or Roo.EventObject.ENTER
14366 // map multiple keys to one action by string
14367 var map = new Roo.KeyMap("my-element", {
14373 // map multiple keys to multiple actions by strings and array of codes
14374 var map = new Roo.KeyMap("my-element", [
14377 fn: function(){ alert("Return was pressed"); }
14380 fn: function(){ alert('a, b or c was pressed'); }
14385 fn: function(){ alert('Control + shift + tab was pressed.'); }
14389 * <b>Note: A KeyMap starts enabled</b>
14391 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14392 * @param {Object} config The config (see {@link #addBinding})
14393 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14395 Roo.KeyMap = function(el, config, eventName){
14396 this.el = Roo.get(el);
14397 this.eventName = eventName || "keydown";
14398 this.bindings = [];
14400 this.addBinding(config);
14405 Roo.KeyMap.prototype = {
14407 * True to stop the event from bubbling and prevent the default browser action if the
14408 * key was handled by the KeyMap (defaults to false)
14414 * Add a new binding to this KeyMap. The following config object properties are supported:
14416 Property Type Description
14417 ---------- --------------- ----------------------------------------------------------------------
14418 key String/Array A single keycode or an array of keycodes to handle
14419 shift Boolean True to handle key only when shift is pressed (defaults to false)
14420 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14421 alt Boolean True to handle key only when alt is pressed (defaults to false)
14422 fn Function The function to call when KeyMap finds the expected key combination
14423 scope Object The scope of the callback function
14429 var map = new Roo.KeyMap(document, {
14430 key: Roo.EventObject.ENTER,
14435 //Add a new binding to the existing KeyMap later
14443 * @param {Object/Array} config A single KeyMap config or an array of configs
14445 addBinding : function(config){
14446 if(config instanceof Array){
14447 for(var i = 0, len = config.length; i < len; i++){
14448 this.addBinding(config[i]);
14452 var keyCode = config.key,
14453 shift = config.shift,
14454 ctrl = config.ctrl,
14457 scope = config.scope;
14458 if(typeof keyCode == "string"){
14460 var keyString = keyCode.toUpperCase();
14461 for(var j = 0, len = keyString.length; j < len; j++){
14462 ks.push(keyString.charCodeAt(j));
14466 var keyArray = keyCode instanceof Array;
14467 var handler = function(e){
14468 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14469 var k = e.getKey();
14471 for(var i = 0, len = keyCode.length; i < len; i++){
14472 if(keyCode[i] == k){
14473 if(this.stopEvent){
14476 fn.call(scope || window, k, e);
14482 if(this.stopEvent){
14485 fn.call(scope || window, k, e);
14490 this.bindings.push(handler);
14494 * Shorthand for adding a single key listener
14495 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14496 * following options:
14497 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14498 * @param {Function} fn The function to call
14499 * @param {Object} scope (optional) The scope of the function
14501 on : function(key, fn, scope){
14502 var keyCode, shift, ctrl, alt;
14503 if(typeof key == "object" && !(key instanceof Array)){
14522 handleKeyDown : function(e){
14523 if(this.enabled){ //just in case
14524 var b = this.bindings;
14525 for(var i = 0, len = b.length; i < len; i++){
14526 b[i].call(this, e);
14532 * Returns true if this KeyMap is enabled
14533 * @return {Boolean}
14535 isEnabled : function(){
14536 return this.enabled;
14540 * Enables this KeyMap
14542 enable: function(){
14544 this.el.on(this.eventName, this.handleKeyDown, this);
14545 this.enabled = true;
14550 * Disable this KeyMap
14552 disable: function(){
14554 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14555 this.enabled = false;
14560 * Ext JS Library 1.1.1
14561 * Copyright(c) 2006-2007, Ext JS, LLC.
14563 * Originally Released Under LGPL - original licence link has changed is not relivant.
14566 * <script type="text/javascript">
14571 * @class Roo.util.TextMetrics
14572 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14573 * wide, in pixels, a given block of text will be.
14576 Roo.util.TextMetrics = function(){
14580 * Measures the size of the specified text
14581 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14582 * that can affect the size of the rendered text
14583 * @param {String} text The text to measure
14584 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14585 * in order to accurately measure the text height
14586 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14588 measure : function(el, text, fixedWidth){
14590 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14593 shared.setFixedWidth(fixedWidth || 'auto');
14594 return shared.getSize(text);
14598 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14599 * the overhead of multiple calls to initialize the style properties on each measurement.
14600 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14601 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14602 * in order to accurately measure the text height
14603 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14605 createInstance : function(el, fixedWidth){
14606 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14613 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14614 var ml = new Roo.Element(document.createElement('div'));
14615 document.body.appendChild(ml.dom);
14616 ml.position('absolute');
14617 ml.setLeftTop(-1000, -1000);
14621 ml.setWidth(fixedWidth);
14626 * Returns the size of the specified text based on the internal element's style and width properties
14627 * @memberOf Roo.util.TextMetrics.Instance#
14628 * @param {String} text The text to measure
14629 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14631 getSize : function(text){
14633 var s = ml.getSize();
14639 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14640 * that can affect the size of the rendered text
14641 * @memberOf Roo.util.TextMetrics.Instance#
14642 * @param {String/HTMLElement} el The element, dom node or id
14644 bind : function(el){
14646 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14651 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14652 * to set a fixed width in order to accurately measure the text height.
14653 * @memberOf Roo.util.TextMetrics.Instance#
14654 * @param {Number} width The width to set on the element
14656 setFixedWidth : function(width){
14657 ml.setWidth(width);
14661 * Returns the measured width of the specified text
14662 * @memberOf Roo.util.TextMetrics.Instance#
14663 * @param {String} text The text to measure
14664 * @return {Number} width The width in pixels
14666 getWidth : function(text){
14667 ml.dom.style.width = 'auto';
14668 return this.getSize(text).width;
14672 * Returns the measured height of the specified text. For multiline text, be sure to call
14673 * {@link #setFixedWidth} if necessary.
14674 * @memberOf Roo.util.TextMetrics.Instance#
14675 * @param {String} text The text to measure
14676 * @return {Number} height The height in pixels
14678 getHeight : function(text){
14679 return this.getSize(text).height;
14683 instance.bind(bindTo);
14688 // backwards compat
14689 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14691 * Ext JS Library 1.1.1
14692 * Copyright(c) 2006-2007, Ext JS, LLC.
14694 * Originally Released Under LGPL - original licence link has changed is not relivant.
14697 * <script type="text/javascript">
14701 * @class Roo.state.Provider
14702 * Abstract base class for state provider implementations. This class provides methods
14703 * for encoding and decoding <b>typed</b> variables including dates and defines the
14704 * Provider interface.
14706 Roo.state.Provider = function(){
14708 * @event statechange
14709 * Fires when a state change occurs.
14710 * @param {Provider} this This state provider
14711 * @param {String} key The state key which was changed
14712 * @param {String} value The encoded value for the state
14715 "statechange": true
14718 Roo.state.Provider.superclass.constructor.call(this);
14720 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14722 * Returns the current value for a key
14723 * @param {String} name The key name
14724 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14725 * @return {Mixed} The state data
14727 get : function(name, defaultValue){
14728 return typeof this.state[name] == "undefined" ?
14729 defaultValue : this.state[name];
14733 * Clears a value from the state
14734 * @param {String} name The key name
14736 clear : function(name){
14737 delete this.state[name];
14738 this.fireEvent("statechange", this, name, null);
14742 * Sets the value for a key
14743 * @param {String} name The key name
14744 * @param {Mixed} value The value to set
14746 set : function(name, value){
14747 this.state[name] = value;
14748 this.fireEvent("statechange", this, name, value);
14752 * Decodes a string previously encoded with {@link #encodeValue}.
14753 * @param {String} value The value to decode
14754 * @return {Mixed} The decoded value
14756 decodeValue : function(cookie){
14757 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14758 var matches = re.exec(unescape(cookie));
14759 if(!matches || !matches[1]) return; // non state cookie
14760 var type = matches[1];
14761 var v = matches[2];
14764 return parseFloat(v);
14766 return new Date(Date.parse(v));
14771 var values = v.split("^");
14772 for(var i = 0, len = values.length; i < len; i++){
14773 all.push(this.decodeValue(values[i]));
14778 var values = v.split("^");
14779 for(var i = 0, len = values.length; i < len; i++){
14780 var kv = values[i].split("=");
14781 all[kv[0]] = this.decodeValue(kv[1]);
14790 * Encodes a value including type information. Decode with {@link #decodeValue}.
14791 * @param {Mixed} value The value to encode
14792 * @return {String} The encoded value
14794 encodeValue : function(v){
14796 if(typeof v == "number"){
14798 }else if(typeof v == "boolean"){
14799 enc = "b:" + (v ? "1" : "0");
14800 }else if(v instanceof Date){
14801 enc = "d:" + v.toGMTString();
14802 }else if(v instanceof Array){
14804 for(var i = 0, len = v.length; i < len; i++){
14805 flat += this.encodeValue(v[i]);
14806 if(i != len-1) flat += "^";
14809 }else if(typeof v == "object"){
14812 if(typeof v[key] != "function"){
14813 flat += key + "=" + this.encodeValue(v[key]) + "^";
14816 enc = "o:" + flat.substring(0, flat.length-1);
14820 return escape(enc);
14826 * Ext JS Library 1.1.1
14827 * Copyright(c) 2006-2007, Ext JS, LLC.
14829 * Originally Released Under LGPL - original licence link has changed is not relivant.
14832 * <script type="text/javascript">
14835 * @class Roo.state.Manager
14836 * This is the global state manager. By default all components that are "state aware" check this class
14837 * for state information if you don't pass them a custom state provider. In order for this class
14838 * to be useful, it must be initialized with a provider when your application initializes.
14840 // in your initialization function
14842 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14844 // supposed you have a {@link Roo.BorderLayout}
14845 var layout = new Roo.BorderLayout(...);
14846 layout.restoreState();
14847 // or a {Roo.BasicDialog}
14848 var dialog = new Roo.BasicDialog(...);
14849 dialog.restoreState();
14853 Roo.state.Manager = function(){
14854 var provider = new Roo.state.Provider();
14858 * Configures the default state provider for your application
14859 * @param {Provider} stateProvider The state provider to set
14861 setProvider : function(stateProvider){
14862 provider = stateProvider;
14866 * Returns the current value for a key
14867 * @param {String} name The key name
14868 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14869 * @return {Mixed} The state data
14871 get : function(key, defaultValue){
14872 return provider.get(key, defaultValue);
14876 * Sets the value for a key
14877 * @param {String} name The key name
14878 * @param {Mixed} value The state data
14880 set : function(key, value){
14881 provider.set(key, value);
14885 * Clears a value from the state
14886 * @param {String} name The key name
14888 clear : function(key){
14889 provider.clear(key);
14893 * Gets the currently configured state provider
14894 * @return {Provider} The state provider
14896 getProvider : function(){
14903 * Ext JS Library 1.1.1
14904 * Copyright(c) 2006-2007, Ext JS, LLC.
14906 * Originally Released Under LGPL - original licence link has changed is not relivant.
14909 * <script type="text/javascript">
14912 * @class Roo.state.CookieProvider
14913 * @extends Roo.state.Provider
14914 * The default Provider implementation which saves state via cookies.
14917 var cp = new Roo.state.CookieProvider({
14919 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14920 domain: "roojs.com"
14922 Roo.state.Manager.setProvider(cp);
14924 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14925 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14926 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14927 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14928 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14929 * domain the page is running on including the 'www' like 'www.roojs.com')
14930 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14932 * Create a new CookieProvider
14933 * @param {Object} config The configuration object
14935 Roo.state.CookieProvider = function(config){
14936 Roo.state.CookieProvider.superclass.constructor.call(this);
14938 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14939 this.domain = null;
14940 this.secure = false;
14941 Roo.apply(this, config);
14942 this.state = this.readCookies();
14945 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14947 set : function(name, value){
14948 if(typeof value == "undefined" || value === null){
14952 this.setCookie(name, value);
14953 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14957 clear : function(name){
14958 this.clearCookie(name);
14959 Roo.state.CookieProvider.superclass.clear.call(this, name);
14963 readCookies : function(){
14965 var c = document.cookie + ";";
14966 var re = /\s?(.*?)=(.*?);/g;
14968 while((matches = re.exec(c)) != null){
14969 var name = matches[1];
14970 var value = matches[2];
14971 if(name && name.substring(0,3) == "ys-"){
14972 cookies[name.substr(3)] = this.decodeValue(value);
14979 setCookie : function(name, value){
14980 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14981 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14982 ((this.path == null) ? "" : ("; path=" + this.path)) +
14983 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14984 ((this.secure == true) ? "; secure" : "");
14988 clearCookie : function(name){
14989 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14990 ((this.path == null) ? "" : ("; path=" + this.path)) +
14991 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14992 ((this.secure == true) ? "; secure" : "");
14996 * Ext JS Library 1.1.1
14997 * Copyright(c) 2006-2007, Ext JS, LLC.
14999 * Originally Released Under LGPL - original licence link has changed is not relivant.
15002 * <script type="text/javascript">
15008 * These classes are derivatives of the similarly named classes in the YUI Library.
15009 * The original license:
15010 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
15011 * Code licensed under the BSD License:
15012 * http://developer.yahoo.net/yui/license.txt
15017 var Event=Roo.EventManager;
15018 var Dom=Roo.lib.Dom;
15021 * @class Roo.dd.DragDrop
15022 * @extends Roo.util.Observable
15023 * Defines the interface and base operation of items that that can be
15024 * dragged or can be drop targets. It was designed to be extended, overriding
15025 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
15026 * Up to three html elements can be associated with a DragDrop instance:
15028 * <li>linked element: the element that is passed into the constructor.
15029 * This is the element which defines the boundaries for interaction with
15030 * other DragDrop objects.</li>
15031 * <li>handle element(s): The drag operation only occurs if the element that
15032 * was clicked matches a handle element. By default this is the linked
15033 * element, but there are times that you will want only a portion of the
15034 * linked element to initiate the drag operation, and the setHandleElId()
15035 * method provides a way to define this.</li>
15036 * <li>drag element: this represents the element that would be moved along
15037 * with the cursor during a drag operation. By default, this is the linked
15038 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
15039 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
15042 * This class should not be instantiated until the onload event to ensure that
15043 * the associated elements are available.
15044 * The following would define a DragDrop obj that would interact with any
15045 * other DragDrop obj in the "group1" group:
15047 * dd = new Roo.dd.DragDrop("div1", "group1");
15049 * Since none of the event handlers have been implemented, nothing would
15050 * actually happen if you were to run the code above. Normally you would
15051 * override this class or one of the default implementations, but you can
15052 * also override the methods you want on an instance of the class...
15054 * dd.onDragDrop = function(e, id) {
15055 * alert("dd was dropped on " + id);
15059 * @param {String} id of the element that is linked to this instance
15060 * @param {String} sGroup the group of related DragDrop objects
15061 * @param {object} config an object containing configurable attributes
15062 * Valid properties for DragDrop:
15063 * padding, isTarget, maintainOffset, primaryButtonOnly
15065 Roo.dd.DragDrop = function(id, sGroup, config) {
15067 this.init(id, sGroup, config);
15072 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15075 * The id of the element associated with this object. This is what we
15076 * refer to as the "linked element" because the size and position of
15077 * this element is used to determine when the drag and drop objects have
15085 * Configuration attributes passed into the constructor
15092 * The id of the element that will be dragged. By default this is same
15093 * as the linked element , but could be changed to another element. Ex:
15095 * @property dragElId
15102 * the id of the element that initiates the drag operation. By default
15103 * this is the linked element, but could be changed to be a child of this
15104 * element. This lets us do things like only starting the drag when the
15105 * header element within the linked html element is clicked.
15106 * @property handleElId
15113 * An associative array of HTML tags that will be ignored if clicked.
15114 * @property invalidHandleTypes
15115 * @type {string: string}
15117 invalidHandleTypes: null,
15120 * An associative array of ids for elements that will be ignored if clicked
15121 * @property invalidHandleIds
15122 * @type {string: string}
15124 invalidHandleIds: null,
15127 * An indexted array of css class names for elements that will be ignored
15129 * @property invalidHandleClasses
15132 invalidHandleClasses: null,
15135 * The linked element's absolute X position at the time the drag was
15137 * @property startPageX
15144 * The linked element's absolute X position at the time the drag was
15146 * @property startPageY
15153 * The group defines a logical collection of DragDrop objects that are
15154 * related. Instances only get events when interacting with other
15155 * DragDrop object in the same group. This lets us define multiple
15156 * groups using a single DragDrop subclass if we want.
15158 * @type {string: string}
15163 * Individual drag/drop instances can be locked. This will prevent
15164 * onmousedown start drag.
15172 * Lock this instance
15175 lock: function() { this.locked = true; },
15178 * Unlock this instace
15181 unlock: function() { this.locked = false; },
15184 * By default, all insances can be a drop target. This can be disabled by
15185 * setting isTarget to false.
15192 * The padding configured for this drag and drop object for calculating
15193 * the drop zone intersection with this object.
15200 * Cached reference to the linked element
15201 * @property _domRef
15207 * Internal typeof flag
15208 * @property __ygDragDrop
15211 __ygDragDrop: true,
15214 * Set to true when horizontal contraints are applied
15215 * @property constrainX
15222 * Set to true when vertical contraints are applied
15223 * @property constrainY
15230 * The left constraint
15238 * The right constraint
15246 * The up constraint
15255 * The down constraint
15263 * Maintain offsets when we resetconstraints. Set to true when you want
15264 * the position of the element relative to its parent to stay the same
15265 * when the page changes
15267 * @property maintainOffset
15270 maintainOffset: false,
15273 * Array of pixel locations the element will snap to if we specified a
15274 * horizontal graduation/interval. This array is generated automatically
15275 * when you define a tick interval.
15282 * Array of pixel locations the element will snap to if we specified a
15283 * vertical graduation/interval. This array is generated automatically
15284 * when you define a tick interval.
15291 * By default the drag and drop instance will only respond to the primary
15292 * button click (left button for a right-handed mouse). Set to true to
15293 * allow drag and drop to start with any mouse click that is propogated
15295 * @property primaryButtonOnly
15298 primaryButtonOnly: true,
15301 * The availabe property is false until the linked dom element is accessible.
15302 * @property available
15308 * By default, drags can only be initiated if the mousedown occurs in the
15309 * region the linked element is. This is done in part to work around a
15310 * bug in some browsers that mis-report the mousedown if the previous
15311 * mouseup happened outside of the window. This property is set to true
15312 * if outer handles are defined.
15314 * @property hasOuterHandles
15318 hasOuterHandles: false,
15321 * Code that executes immediately before the startDrag event
15322 * @method b4StartDrag
15325 b4StartDrag: function(x, y) { },
15328 * Abstract method called after a drag/drop object is clicked
15329 * and the drag or mousedown time thresholds have beeen met.
15330 * @method startDrag
15331 * @param {int} X click location
15332 * @param {int} Y click location
15334 startDrag: function(x, y) { /* override this */ },
15337 * Code that executes immediately before the onDrag event
15341 b4Drag: function(e) { },
15344 * Abstract method called during the onMouseMove event while dragging an
15347 * @param {Event} e the mousemove event
15349 onDrag: function(e) { /* override this */ },
15352 * Abstract method called when this element fist begins hovering over
15353 * another DragDrop obj
15354 * @method onDragEnter
15355 * @param {Event} e the mousemove event
15356 * @param {String|DragDrop[]} id In POINT mode, the element
15357 * id this is hovering over. In INTERSECT mode, an array of one or more
15358 * dragdrop items being hovered over.
15360 onDragEnter: function(e, id) { /* override this */ },
15363 * Code that executes immediately before the onDragOver event
15364 * @method b4DragOver
15367 b4DragOver: function(e) { },
15370 * Abstract method called when this element is hovering over another
15372 * @method onDragOver
15373 * @param {Event} e the mousemove event
15374 * @param {String|DragDrop[]} id In POINT mode, the element
15375 * id this is hovering over. In INTERSECT mode, an array of dd items
15376 * being hovered over.
15378 onDragOver: function(e, id) { /* override this */ },
15381 * Code that executes immediately before the onDragOut event
15382 * @method b4DragOut
15385 b4DragOut: function(e) { },
15388 * Abstract method called when we are no longer hovering over an element
15389 * @method onDragOut
15390 * @param {Event} e the mousemove event
15391 * @param {String|DragDrop[]} id In POINT mode, the element
15392 * id this was hovering over. In INTERSECT mode, an array of dd items
15393 * that the mouse is no longer over.
15395 onDragOut: function(e, id) { /* override this */ },
15398 * Code that executes immediately before the onDragDrop event
15399 * @method b4DragDrop
15402 b4DragDrop: function(e) { },
15405 * Abstract method called when this item is dropped on another DragDrop
15407 * @method onDragDrop
15408 * @param {Event} e the mouseup event
15409 * @param {String|DragDrop[]} id In POINT mode, the element
15410 * id this was dropped on. In INTERSECT mode, an array of dd items this
15413 onDragDrop: function(e, id) { /* override this */ },
15416 * Abstract method called when this item is dropped on an area with no
15418 * @method onInvalidDrop
15419 * @param {Event} e the mouseup event
15421 onInvalidDrop: function(e) { /* override this */ },
15424 * Code that executes immediately before the endDrag event
15425 * @method b4EndDrag
15428 b4EndDrag: function(e) { },
15431 * Fired when we are done dragging the object
15433 * @param {Event} e the mouseup event
15435 endDrag: function(e) { /* override this */ },
15438 * Code executed immediately before the onMouseDown event
15439 * @method b4MouseDown
15440 * @param {Event} e the mousedown event
15443 b4MouseDown: function(e) { },
15446 * Event handler that fires when a drag/drop obj gets a mousedown
15447 * @method onMouseDown
15448 * @param {Event} e the mousedown event
15450 onMouseDown: function(e) { /* override this */ },
15453 * Event handler that fires when a drag/drop obj gets a mouseup
15454 * @method onMouseUp
15455 * @param {Event} e the mouseup event
15457 onMouseUp: function(e) { /* override this */ },
15460 * Override the onAvailable method to do what is needed after the initial
15461 * position was determined.
15462 * @method onAvailable
15464 onAvailable: function () {
15468 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15471 defaultPadding : {left:0, right:0, top:0, bottom:0},
15474 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15478 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15479 { dragElId: "existingProxyDiv" });
15480 dd.startDrag = function(){
15481 this.constrainTo("parent-id");
15484 * Or you can initalize it using the {@link Roo.Element} object:
15486 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15487 startDrag : function(){
15488 this.constrainTo("parent-id");
15492 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15493 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15494 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15495 * an object containing the sides to pad. For example: {right:10, bottom:10}
15496 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15498 constrainTo : function(constrainTo, pad, inContent){
15499 if(typeof pad == "number"){
15500 pad = {left: pad, right:pad, top:pad, bottom:pad};
15502 pad = pad || this.defaultPadding;
15503 var b = Roo.get(this.getEl()).getBox();
15504 var ce = Roo.get(constrainTo);
15505 var s = ce.getScroll();
15506 var c, cd = ce.dom;
15507 if(cd == document.body){
15508 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15511 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15515 var topSpace = b.y - c.y;
15516 var leftSpace = b.x - c.x;
15518 this.resetConstraints();
15519 this.setXConstraint(leftSpace - (pad.left||0), // left
15520 c.width - leftSpace - b.width - (pad.right||0) //right
15522 this.setYConstraint(topSpace - (pad.top||0), //top
15523 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15528 * Returns a reference to the linked element
15530 * @return {HTMLElement} the html element
15532 getEl: function() {
15533 if (!this._domRef) {
15534 this._domRef = Roo.getDom(this.id);
15537 return this._domRef;
15541 * Returns a reference to the actual element to drag. By default this is
15542 * the same as the html element, but it can be assigned to another
15543 * element. An example of this can be found in Roo.dd.DDProxy
15544 * @method getDragEl
15545 * @return {HTMLElement} the html element
15547 getDragEl: function() {
15548 return Roo.getDom(this.dragElId);
15552 * Sets up the DragDrop object. Must be called in the constructor of any
15553 * Roo.dd.DragDrop subclass
15555 * @param id the id of the linked element
15556 * @param {String} sGroup the group of related items
15557 * @param {object} config configuration attributes
15559 init: function(id, sGroup, config) {
15560 this.initTarget(id, sGroup, config);
15561 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15562 // Event.on(this.id, "selectstart", Event.preventDefault);
15566 * Initializes Targeting functionality only... the object does not
15567 * get a mousedown handler.
15568 * @method initTarget
15569 * @param id the id of the linked element
15570 * @param {String} sGroup the group of related items
15571 * @param {object} config configuration attributes
15573 initTarget: function(id, sGroup, config) {
15575 // configuration attributes
15576 this.config = config || {};
15578 // create a local reference to the drag and drop manager
15579 this.DDM = Roo.dd.DDM;
15580 // initialize the groups array
15583 // assume that we have an element reference instead of an id if the
15584 // parameter is not a string
15585 if (typeof id !== "string") {
15592 // add to an interaction group
15593 this.addToGroup((sGroup) ? sGroup : "default");
15595 // We don't want to register this as the handle with the manager
15596 // so we just set the id rather than calling the setter.
15597 this.handleElId = id;
15599 // the linked element is the element that gets dragged by default
15600 this.setDragElId(id);
15602 // by default, clicked anchors will not start drag operations.
15603 this.invalidHandleTypes = { A: "A" };
15604 this.invalidHandleIds = {};
15605 this.invalidHandleClasses = [];
15607 this.applyConfig();
15609 this.handleOnAvailable();
15613 * Applies the configuration parameters that were passed into the constructor.
15614 * This is supposed to happen at each level through the inheritance chain. So
15615 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15616 * DragDrop in order to get all of the parameters that are available in
15618 * @method applyConfig
15620 applyConfig: function() {
15622 // configurable properties:
15623 // padding, isTarget, maintainOffset, primaryButtonOnly
15624 this.padding = this.config.padding || [0, 0, 0, 0];
15625 this.isTarget = (this.config.isTarget !== false);
15626 this.maintainOffset = (this.config.maintainOffset);
15627 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15632 * Executed when the linked element is available
15633 * @method handleOnAvailable
15636 handleOnAvailable: function() {
15637 this.available = true;
15638 this.resetConstraints();
15639 this.onAvailable();
15643 * Configures the padding for the target zone in px. Effectively expands
15644 * (or reduces) the virtual object size for targeting calculations.
15645 * Supports css-style shorthand; if only one parameter is passed, all sides
15646 * will have that padding, and if only two are passed, the top and bottom
15647 * will have the first param, the left and right the second.
15648 * @method setPadding
15649 * @param {int} iTop Top pad
15650 * @param {int} iRight Right pad
15651 * @param {int} iBot Bot pad
15652 * @param {int} iLeft Left pad
15654 setPadding: function(iTop, iRight, iBot, iLeft) {
15655 // this.padding = [iLeft, iRight, iTop, iBot];
15656 if (!iRight && 0 !== iRight) {
15657 this.padding = [iTop, iTop, iTop, iTop];
15658 } else if (!iBot && 0 !== iBot) {
15659 this.padding = [iTop, iRight, iTop, iRight];
15661 this.padding = [iTop, iRight, iBot, iLeft];
15666 * Stores the initial placement of the linked element.
15667 * @method setInitialPosition
15668 * @param {int} diffX the X offset, default 0
15669 * @param {int} diffY the Y offset, default 0
15671 setInitPosition: function(diffX, diffY) {
15672 var el = this.getEl();
15674 if (!this.DDM.verifyEl(el)) {
15678 var dx = diffX || 0;
15679 var dy = diffY || 0;
15681 var p = Dom.getXY( el );
15683 this.initPageX = p[0] - dx;
15684 this.initPageY = p[1] - dy;
15686 this.lastPageX = p[0];
15687 this.lastPageY = p[1];
15690 this.setStartPosition(p);
15694 * Sets the start position of the element. This is set when the obj
15695 * is initialized, the reset when a drag is started.
15696 * @method setStartPosition
15697 * @param pos current position (from previous lookup)
15700 setStartPosition: function(pos) {
15701 var p = pos || Dom.getXY( this.getEl() );
15702 this.deltaSetXY = null;
15704 this.startPageX = p[0];
15705 this.startPageY = p[1];
15709 * Add this instance to a group of related drag/drop objects. All
15710 * instances belong to at least one group, and can belong to as many
15711 * groups as needed.
15712 * @method addToGroup
15713 * @param sGroup {string} the name of the group
15715 addToGroup: function(sGroup) {
15716 this.groups[sGroup] = true;
15717 this.DDM.regDragDrop(this, sGroup);
15721 * Remove's this instance from the supplied interaction group
15722 * @method removeFromGroup
15723 * @param {string} sGroup The group to drop
15725 removeFromGroup: function(sGroup) {
15726 if (this.groups[sGroup]) {
15727 delete this.groups[sGroup];
15730 this.DDM.removeDDFromGroup(this, sGroup);
15734 * Allows you to specify that an element other than the linked element
15735 * will be moved with the cursor during a drag
15736 * @method setDragElId
15737 * @param id {string} the id of the element that will be used to initiate the drag
15739 setDragElId: function(id) {
15740 this.dragElId = id;
15744 * Allows you to specify a child of the linked element that should be
15745 * used to initiate the drag operation. An example of this would be if
15746 * you have a content div with text and links. Clicking anywhere in the
15747 * content area would normally start the drag operation. Use this method
15748 * to specify that an element inside of the content div is the element
15749 * that starts the drag operation.
15750 * @method setHandleElId
15751 * @param id {string} the id of the element that will be used to
15752 * initiate the drag.
15754 setHandleElId: function(id) {
15755 if (typeof id !== "string") {
15758 this.handleElId = id;
15759 this.DDM.regHandle(this.id, id);
15763 * Allows you to set an element outside of the linked element as a drag
15765 * @method setOuterHandleElId
15766 * @param id the id of the element that will be used to initiate the drag
15768 setOuterHandleElId: function(id) {
15769 if (typeof id !== "string") {
15772 Event.on(id, "mousedown",
15773 this.handleMouseDown, this);
15774 this.setHandleElId(id);
15776 this.hasOuterHandles = true;
15780 * Remove all drag and drop hooks for this element
15783 unreg: function() {
15784 Event.un(this.id, "mousedown",
15785 this.handleMouseDown);
15786 this._domRef = null;
15787 this.DDM._remove(this);
15790 destroy : function(){
15795 * Returns true if this instance is locked, or the drag drop mgr is locked
15796 * (meaning that all drag/drop is disabled on the page.)
15798 * @return {boolean} true if this obj or all drag/drop is locked, else
15801 isLocked: function() {
15802 return (this.DDM.isLocked() || this.locked);
15806 * Fired when this object is clicked
15807 * @method handleMouseDown
15809 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15812 handleMouseDown: function(e, oDD){
15813 if (this.primaryButtonOnly && e.button != 0) {
15817 if (this.isLocked()) {
15821 this.DDM.refreshCache(this.groups);
15823 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15824 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15826 if (this.clickValidator(e)) {
15828 // set the initial element position
15829 this.setStartPosition();
15832 this.b4MouseDown(e);
15833 this.onMouseDown(e);
15835 this.DDM.handleMouseDown(e, this);
15837 this.DDM.stopEvent(e);
15845 clickValidator: function(e) {
15846 var target = e.getTarget();
15847 return ( this.isValidHandleChild(target) &&
15848 (this.id == this.handleElId ||
15849 this.DDM.handleWasClicked(target, this.id)) );
15853 * Allows you to specify a tag name that should not start a drag operation
15854 * when clicked. This is designed to facilitate embedding links within a
15855 * drag handle that do something other than start the drag.
15856 * @method addInvalidHandleType
15857 * @param {string} tagName the type of element to exclude
15859 addInvalidHandleType: function(tagName) {
15860 var type = tagName.toUpperCase();
15861 this.invalidHandleTypes[type] = type;
15865 * Lets you to specify an element id for a child of a drag handle
15866 * that should not initiate a drag
15867 * @method addInvalidHandleId
15868 * @param {string} id the element id of the element you wish to ignore
15870 addInvalidHandleId: function(id) {
15871 if (typeof id !== "string") {
15874 this.invalidHandleIds[id] = id;
15878 * Lets you specify a css class of elements that will not initiate a drag
15879 * @method addInvalidHandleClass
15880 * @param {string} cssClass the class of the elements you wish to ignore
15882 addInvalidHandleClass: function(cssClass) {
15883 this.invalidHandleClasses.push(cssClass);
15887 * Unsets an excluded tag name set by addInvalidHandleType
15888 * @method removeInvalidHandleType
15889 * @param {string} tagName the type of element to unexclude
15891 removeInvalidHandleType: function(tagName) {
15892 var type = tagName.toUpperCase();
15893 // this.invalidHandleTypes[type] = null;
15894 delete this.invalidHandleTypes[type];
15898 * Unsets an invalid handle id
15899 * @method removeInvalidHandleId
15900 * @param {string} id the id of the element to re-enable
15902 removeInvalidHandleId: function(id) {
15903 if (typeof id !== "string") {
15906 delete this.invalidHandleIds[id];
15910 * Unsets an invalid css class
15911 * @method removeInvalidHandleClass
15912 * @param {string} cssClass the class of the element(s) you wish to
15915 removeInvalidHandleClass: function(cssClass) {
15916 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15917 if (this.invalidHandleClasses[i] == cssClass) {
15918 delete this.invalidHandleClasses[i];
15924 * Checks the tag exclusion list to see if this click should be ignored
15925 * @method isValidHandleChild
15926 * @param {HTMLElement} node the HTMLElement to evaluate
15927 * @return {boolean} true if this is a valid tag type, false if not
15929 isValidHandleChild: function(node) {
15932 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15935 nodeName = node.nodeName.toUpperCase();
15937 nodeName = node.nodeName;
15939 valid = valid && !this.invalidHandleTypes[nodeName];
15940 valid = valid && !this.invalidHandleIds[node.id];
15942 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15943 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15952 * Create the array of horizontal tick marks if an interval was specified
15953 * in setXConstraint().
15954 * @method setXTicks
15957 setXTicks: function(iStartX, iTickSize) {
15959 this.xTickSize = iTickSize;
15963 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15965 this.xTicks[this.xTicks.length] = i;
15970 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15972 this.xTicks[this.xTicks.length] = i;
15977 this.xTicks.sort(this.DDM.numericSort) ;
15981 * Create the array of vertical tick marks if an interval was specified in
15982 * setYConstraint().
15983 * @method setYTicks
15986 setYTicks: function(iStartY, iTickSize) {
15988 this.yTickSize = iTickSize;
15992 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15994 this.yTicks[this.yTicks.length] = i;
15999 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
16001 this.yTicks[this.yTicks.length] = i;
16006 this.yTicks.sort(this.DDM.numericSort) ;
16010 * By default, the element can be dragged any place on the screen. Use
16011 * this method to limit the horizontal travel of the element. Pass in
16012 * 0,0 for the parameters if you want to lock the drag to the y axis.
16013 * @method setXConstraint
16014 * @param {int} iLeft the number of pixels the element can move to the left
16015 * @param {int} iRight the number of pixels the element can move to the
16017 * @param {int} iTickSize optional parameter for specifying that the
16019 * should move iTickSize pixels at a time.
16021 setXConstraint: function(iLeft, iRight, iTickSize) {
16022 this.leftConstraint = iLeft;
16023 this.rightConstraint = iRight;
16025 this.minX = this.initPageX - iLeft;
16026 this.maxX = this.initPageX + iRight;
16027 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
16029 this.constrainX = true;
16033 * Clears any constraints applied to this instance. Also clears ticks
16034 * since they can't exist independent of a constraint at this time.
16035 * @method clearConstraints
16037 clearConstraints: function() {
16038 this.constrainX = false;
16039 this.constrainY = false;
16044 * Clears any tick interval defined for this instance
16045 * @method clearTicks
16047 clearTicks: function() {
16048 this.xTicks = null;
16049 this.yTicks = null;
16050 this.xTickSize = 0;
16051 this.yTickSize = 0;
16055 * By default, the element can be dragged any place on the screen. Set
16056 * this to limit the vertical travel of the element. Pass in 0,0 for the
16057 * parameters if you want to lock the drag to the x axis.
16058 * @method setYConstraint
16059 * @param {int} iUp the number of pixels the element can move up
16060 * @param {int} iDown the number of pixels the element can move down
16061 * @param {int} iTickSize optional parameter for specifying that the
16062 * element should move iTickSize pixels at a time.
16064 setYConstraint: function(iUp, iDown, iTickSize) {
16065 this.topConstraint = iUp;
16066 this.bottomConstraint = iDown;
16068 this.minY = this.initPageY - iUp;
16069 this.maxY = this.initPageY + iDown;
16070 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16072 this.constrainY = true;
16077 * resetConstraints must be called if you manually reposition a dd element.
16078 * @method resetConstraints
16079 * @param {boolean} maintainOffset
16081 resetConstraints: function() {
16084 // Maintain offsets if necessary
16085 if (this.initPageX || this.initPageX === 0) {
16086 // figure out how much this thing has moved
16087 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16088 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16090 this.setInitPosition(dx, dy);
16092 // This is the first time we have detected the element's position
16094 this.setInitPosition();
16097 if (this.constrainX) {
16098 this.setXConstraint( this.leftConstraint,
16099 this.rightConstraint,
16103 if (this.constrainY) {
16104 this.setYConstraint( this.topConstraint,
16105 this.bottomConstraint,
16111 * Normally the drag element is moved pixel by pixel, but we can specify
16112 * that it move a number of pixels at a time. This method resolves the
16113 * location when we have it set up like this.
16115 * @param {int} val where we want to place the object
16116 * @param {int[]} tickArray sorted array of valid points
16117 * @return {int} the closest tick
16120 getTick: function(val, tickArray) {
16123 // If tick interval is not defined, it is effectively 1 pixel,
16124 // so we return the value passed to us.
16126 } else if (tickArray[0] >= val) {
16127 // The value is lower than the first tick, so we return the first
16129 return tickArray[0];
16131 for (var i=0, len=tickArray.length; i<len; ++i) {
16133 if (tickArray[next] && tickArray[next] >= val) {
16134 var diff1 = val - tickArray[i];
16135 var diff2 = tickArray[next] - val;
16136 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16140 // The value is larger than the last tick, so we return the last
16142 return tickArray[tickArray.length - 1];
16149 * @return {string} string representation of the dd obj
16151 toString: function() {
16152 return ("DragDrop " + this.id);
16160 * Ext JS Library 1.1.1
16161 * Copyright(c) 2006-2007, Ext JS, LLC.
16163 * Originally Released Under LGPL - original licence link has changed is not relivant.
16166 * <script type="text/javascript">
16171 * The drag and drop utility provides a framework for building drag and drop
16172 * applications. In addition to enabling drag and drop for specific elements,
16173 * the drag and drop elements are tracked by the manager class, and the
16174 * interactions between the various elements are tracked during the drag and
16175 * the implementing code is notified about these important moments.
16178 // Only load the library once. Rewriting the manager class would orphan
16179 // existing drag and drop instances.
16180 if (!Roo.dd.DragDropMgr) {
16183 * @class Roo.dd.DragDropMgr
16184 * DragDropMgr is a singleton that tracks the element interaction for
16185 * all DragDrop items in the window. Generally, you will not call
16186 * this class directly, but it does have helper methods that could
16187 * be useful in your DragDrop implementations.
16190 Roo.dd.DragDropMgr = function() {
16192 var Event = Roo.EventManager;
16197 * Two dimensional Array of registered DragDrop objects. The first
16198 * dimension is the DragDrop item group, the second the DragDrop
16201 * @type {string: string}
16208 * Array of element ids defined as drag handles. Used to determine
16209 * if the element that generated the mousedown event is actually the
16210 * handle and not the html element itself.
16211 * @property handleIds
16212 * @type {string: string}
16219 * the DragDrop object that is currently being dragged
16220 * @property dragCurrent
16228 * the DragDrop object(s) that are being hovered over
16229 * @property dragOvers
16237 * the X distance between the cursor and the object being dragged
16246 * the Y distance between the cursor and the object being dragged
16255 * Flag to determine if we should prevent the default behavior of the
16256 * events we define. By default this is true, but this can be set to
16257 * false if you need the default behavior (not recommended)
16258 * @property preventDefault
16262 preventDefault: true,
16265 * Flag to determine if we should stop the propagation of the events
16266 * we generate. This is true by default but you may want to set it to
16267 * false if the html element contains other features that require the
16269 * @property stopPropagation
16273 stopPropagation: true,
16276 * Internal flag that is set to true when drag and drop has been
16278 * @property initialized
16285 * All drag and drop can be disabled.
16293 * Called the first time an element is registered.
16299 this.initialized = true;
16303 * In point mode, drag and drop interaction is defined by the
16304 * location of the cursor during the drag/drop
16312 * In intersect mode, drag and drop interactio nis defined by the
16313 * overlap of two or more drag and drop objects.
16314 * @property INTERSECT
16321 * The current drag and drop mode. Default: POINT
16329 * Runs method on all drag and drop objects
16330 * @method _execOnAll
16334 _execOnAll: function(sMethod, args) {
16335 for (var i in this.ids) {
16336 for (var j in this.ids[i]) {
16337 var oDD = this.ids[i][j];
16338 if (! this.isTypeOfDD(oDD)) {
16341 oDD[sMethod].apply(oDD, args);
16347 * Drag and drop initialization. Sets up the global event handlers
16352 _onLoad: function() {
16357 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16358 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16359 Event.on(window, "unload", this._onUnload, this, true);
16360 Event.on(window, "resize", this._onResize, this, true);
16361 // Event.on(window, "mouseout", this._test);
16366 * Reset constraints on all drag and drop objs
16367 * @method _onResize
16371 _onResize: function(e) {
16372 this._execOnAll("resetConstraints", []);
16376 * Lock all drag and drop functionality
16380 lock: function() { this.locked = true; },
16383 * Unlock all drag and drop functionality
16387 unlock: function() { this.locked = false; },
16390 * Is drag and drop locked?
16392 * @return {boolean} True if drag and drop is locked, false otherwise.
16395 isLocked: function() { return this.locked; },
16398 * Location cache that is set for all drag drop objects when a drag is
16399 * initiated, cleared when the drag is finished.
16400 * @property locationCache
16407 * Set useCache to false if you want to force object the lookup of each
16408 * drag and drop linked element constantly during a drag.
16409 * @property useCache
16416 * The number of pixels that the mouse needs to move after the
16417 * mousedown before the drag is initiated. Default=3;
16418 * @property clickPixelThresh
16422 clickPixelThresh: 3,
16425 * The number of milliseconds after the mousedown event to initiate the
16426 * drag if we don't get a mouseup event. Default=1000
16427 * @property clickTimeThresh
16431 clickTimeThresh: 350,
16434 * Flag that indicates that either the drag pixel threshold or the
16435 * mousdown time threshold has been met
16436 * @property dragThreshMet
16441 dragThreshMet: false,
16444 * Timeout used for the click time threshold
16445 * @property clickTimeout
16450 clickTimeout: null,
16453 * The X position of the mousedown event stored for later use when a
16454 * drag threshold is met.
16463 * The Y position of the mousedown event stored for later use when a
16464 * drag threshold is met.
16473 * Each DragDrop instance must be registered with the DragDropMgr.
16474 * This is executed in DragDrop.init()
16475 * @method regDragDrop
16476 * @param {DragDrop} oDD the DragDrop object to register
16477 * @param {String} sGroup the name of the group this element belongs to
16480 regDragDrop: function(oDD, sGroup) {
16481 if (!this.initialized) { this.init(); }
16483 if (!this.ids[sGroup]) {
16484 this.ids[sGroup] = {};
16486 this.ids[sGroup][oDD.id] = oDD;
16490 * Removes the supplied dd instance from the supplied group. Executed
16491 * by DragDrop.removeFromGroup, so don't call this function directly.
16492 * @method removeDDFromGroup
16496 removeDDFromGroup: function(oDD, sGroup) {
16497 if (!this.ids[sGroup]) {
16498 this.ids[sGroup] = {};
16501 var obj = this.ids[sGroup];
16502 if (obj && obj[oDD.id]) {
16503 delete obj[oDD.id];
16508 * Unregisters a drag and drop item. This is executed in
16509 * DragDrop.unreg, use that method instead of calling this directly.
16514 _remove: function(oDD) {
16515 for (var g in oDD.groups) {
16516 if (g && this.ids[g][oDD.id]) {
16517 delete this.ids[g][oDD.id];
16520 delete this.handleIds[oDD.id];
16524 * Each DragDrop handle element must be registered. This is done
16525 * automatically when executing DragDrop.setHandleElId()
16526 * @method regHandle
16527 * @param {String} sDDId the DragDrop id this element is a handle for
16528 * @param {String} sHandleId the id of the element that is the drag
16532 regHandle: function(sDDId, sHandleId) {
16533 if (!this.handleIds[sDDId]) {
16534 this.handleIds[sDDId] = {};
16536 this.handleIds[sDDId][sHandleId] = sHandleId;
16540 * Utility function to determine if a given element has been
16541 * registered as a drag drop item.
16542 * @method isDragDrop
16543 * @param {String} id the element id to check
16544 * @return {boolean} true if this element is a DragDrop item,
16548 isDragDrop: function(id) {
16549 return ( this.getDDById(id) ) ? true : false;
16553 * Returns the drag and drop instances that are in all groups the
16554 * passed in instance belongs to.
16555 * @method getRelated
16556 * @param {DragDrop} p_oDD the obj to get related data for
16557 * @param {boolean} bTargetsOnly if true, only return targetable objs
16558 * @return {DragDrop[]} the related instances
16561 getRelated: function(p_oDD, bTargetsOnly) {
16563 for (var i in p_oDD.groups) {
16564 for (j in this.ids[i]) {
16565 var dd = this.ids[i][j];
16566 if (! this.isTypeOfDD(dd)) {
16569 if (!bTargetsOnly || dd.isTarget) {
16570 oDDs[oDDs.length] = dd;
16579 * Returns true if the specified dd target is a legal target for
16580 * the specifice drag obj
16581 * @method isLegalTarget
16582 * @param {DragDrop} the drag obj
16583 * @param {DragDrop} the target
16584 * @return {boolean} true if the target is a legal target for the
16588 isLegalTarget: function (oDD, oTargetDD) {
16589 var targets = this.getRelated(oDD, true);
16590 for (var i=0, len=targets.length;i<len;++i) {
16591 if (targets[i].id == oTargetDD.id) {
16600 * My goal is to be able to transparently determine if an object is
16601 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16602 * returns "object", oDD.constructor.toString() always returns
16603 * "DragDrop" and not the name of the subclass. So for now it just
16604 * evaluates a well-known variable in DragDrop.
16605 * @method isTypeOfDD
16606 * @param {Object} the object to evaluate
16607 * @return {boolean} true if typeof oDD = DragDrop
16610 isTypeOfDD: function (oDD) {
16611 return (oDD && oDD.__ygDragDrop);
16615 * Utility function to determine if a given element has been
16616 * registered as a drag drop handle for the given Drag Drop object.
16618 * @param {String} id the element id to check
16619 * @return {boolean} true if this element is a DragDrop handle, false
16623 isHandle: function(sDDId, sHandleId) {
16624 return ( this.handleIds[sDDId] &&
16625 this.handleIds[sDDId][sHandleId] );
16629 * Returns the DragDrop instance for a given id
16630 * @method getDDById
16631 * @param {String} id the id of the DragDrop object
16632 * @return {DragDrop} the drag drop object, null if it is not found
16635 getDDById: function(id) {
16636 for (var i in this.ids) {
16637 if (this.ids[i][id]) {
16638 return this.ids[i][id];
16645 * Fired after a registered DragDrop object gets the mousedown event.
16646 * Sets up the events required to track the object being dragged
16647 * @method handleMouseDown
16648 * @param {Event} e the event
16649 * @param oDD the DragDrop object being dragged
16653 handleMouseDown: function(e, oDD) {
16655 Roo.QuickTips.disable();
16657 this.currentTarget = e.getTarget();
16659 this.dragCurrent = oDD;
16661 var el = oDD.getEl();
16663 // track start position
16664 this.startX = e.getPageX();
16665 this.startY = e.getPageY();
16667 this.deltaX = this.startX - el.offsetLeft;
16668 this.deltaY = this.startY - el.offsetTop;
16670 this.dragThreshMet = false;
16672 this.clickTimeout = setTimeout(
16674 var DDM = Roo.dd.DDM;
16675 DDM.startDrag(DDM.startX, DDM.startY);
16677 this.clickTimeThresh );
16681 * Fired when either the drag pixel threshol or the mousedown hold
16682 * time threshold has been met.
16683 * @method startDrag
16684 * @param x {int} the X position of the original mousedown
16685 * @param y {int} the Y position of the original mousedown
16688 startDrag: function(x, y) {
16689 clearTimeout(this.clickTimeout);
16690 if (this.dragCurrent) {
16691 this.dragCurrent.b4StartDrag(x, y);
16692 this.dragCurrent.startDrag(x, y);
16694 this.dragThreshMet = true;
16698 * Internal function to handle the mouseup event. Will be invoked
16699 * from the context of the document.
16700 * @method handleMouseUp
16701 * @param {Event} e the event
16705 handleMouseUp: function(e) {
16708 Roo.QuickTips.enable();
16710 if (! this.dragCurrent) {
16714 clearTimeout(this.clickTimeout);
16716 if (this.dragThreshMet) {
16717 this.fireEvents(e, true);
16727 * Utility to stop event propagation and event default, if these
16728 * features are turned on.
16729 * @method stopEvent
16730 * @param {Event} e the event as returned by this.getEvent()
16733 stopEvent: function(e){
16734 if(this.stopPropagation) {
16735 e.stopPropagation();
16738 if (this.preventDefault) {
16739 e.preventDefault();
16744 * Internal function to clean up event handlers after the drag
16745 * operation is complete
16747 * @param {Event} e the event
16751 stopDrag: function(e) {
16752 // Fire the drag end event for the item that was dragged
16753 if (this.dragCurrent) {
16754 if (this.dragThreshMet) {
16755 this.dragCurrent.b4EndDrag(e);
16756 this.dragCurrent.endDrag(e);
16759 this.dragCurrent.onMouseUp(e);
16762 this.dragCurrent = null;
16763 this.dragOvers = {};
16767 * Internal function to handle the mousemove event. Will be invoked
16768 * from the context of the html element.
16770 * @TODO figure out what we can do about mouse events lost when the
16771 * user drags objects beyond the window boundary. Currently we can
16772 * detect this in internet explorer by verifying that the mouse is
16773 * down during the mousemove event. Firefox doesn't give us the
16774 * button state on the mousemove event.
16775 * @method handleMouseMove
16776 * @param {Event} e the event
16780 handleMouseMove: function(e) {
16781 if (! this.dragCurrent) {
16785 // var button = e.which || e.button;
16787 // check for IE mouseup outside of page boundary
16788 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16790 return this.handleMouseUp(e);
16793 if (!this.dragThreshMet) {
16794 var diffX = Math.abs(this.startX - e.getPageX());
16795 var diffY = Math.abs(this.startY - e.getPageY());
16796 if (diffX > this.clickPixelThresh ||
16797 diffY > this.clickPixelThresh) {
16798 this.startDrag(this.startX, this.startY);
16802 if (this.dragThreshMet) {
16803 this.dragCurrent.b4Drag(e);
16804 this.dragCurrent.onDrag(e);
16805 if(!this.dragCurrent.moveOnly){
16806 this.fireEvents(e, false);
16816 * Iterates over all of the DragDrop elements to find ones we are
16817 * hovering over or dropping on
16818 * @method fireEvents
16819 * @param {Event} e the event
16820 * @param {boolean} isDrop is this a drop op or a mouseover op?
16824 fireEvents: function(e, isDrop) {
16825 var dc = this.dragCurrent;
16827 // If the user did the mouse up outside of the window, we could
16828 // get here even though we have ended the drag.
16829 if (!dc || dc.isLocked()) {
16833 var pt = e.getPoint();
16835 // cache the previous dragOver array
16841 var enterEvts = [];
16843 // Check to see if the object(s) we were hovering over is no longer
16844 // being hovered over so we can fire the onDragOut event
16845 for (var i in this.dragOvers) {
16847 var ddo = this.dragOvers[i];
16849 if (! this.isTypeOfDD(ddo)) {
16853 if (! this.isOverTarget(pt, ddo, this.mode)) {
16854 outEvts.push( ddo );
16857 oldOvers[i] = true;
16858 delete this.dragOvers[i];
16861 for (var sGroup in dc.groups) {
16863 if ("string" != typeof sGroup) {
16867 for (i in this.ids[sGroup]) {
16868 var oDD = this.ids[sGroup][i];
16869 if (! this.isTypeOfDD(oDD)) {
16873 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16874 if (this.isOverTarget(pt, oDD, this.mode)) {
16875 // look for drop interactions
16877 dropEvts.push( oDD );
16878 // look for drag enter and drag over interactions
16881 // initial drag over: dragEnter fires
16882 if (!oldOvers[oDD.id]) {
16883 enterEvts.push( oDD );
16884 // subsequent drag overs: dragOver fires
16886 overEvts.push( oDD );
16889 this.dragOvers[oDD.id] = oDD;
16897 if (outEvts.length) {
16898 dc.b4DragOut(e, outEvts);
16899 dc.onDragOut(e, outEvts);
16902 if (enterEvts.length) {
16903 dc.onDragEnter(e, enterEvts);
16906 if (overEvts.length) {
16907 dc.b4DragOver(e, overEvts);
16908 dc.onDragOver(e, overEvts);
16911 if (dropEvts.length) {
16912 dc.b4DragDrop(e, dropEvts);
16913 dc.onDragDrop(e, dropEvts);
16917 // fire dragout events
16919 for (i=0, len=outEvts.length; i<len; ++i) {
16920 dc.b4DragOut(e, outEvts[i].id);
16921 dc.onDragOut(e, outEvts[i].id);
16924 // fire enter events
16925 for (i=0,len=enterEvts.length; i<len; ++i) {
16926 // dc.b4DragEnter(e, oDD.id);
16927 dc.onDragEnter(e, enterEvts[i].id);
16930 // fire over events
16931 for (i=0,len=overEvts.length; i<len; ++i) {
16932 dc.b4DragOver(e, overEvts[i].id);
16933 dc.onDragOver(e, overEvts[i].id);
16936 // fire drop events
16937 for (i=0, len=dropEvts.length; i<len; ++i) {
16938 dc.b4DragDrop(e, dropEvts[i].id);
16939 dc.onDragDrop(e, dropEvts[i].id);
16944 // notify about a drop that did not find a target
16945 if (isDrop && !dropEvts.length) {
16946 dc.onInvalidDrop(e);
16952 * Helper function for getting the best match from the list of drag
16953 * and drop objects returned by the drag and drop events when we are
16954 * in INTERSECT mode. It returns either the first object that the
16955 * cursor is over, or the object that has the greatest overlap with
16956 * the dragged element.
16957 * @method getBestMatch
16958 * @param {DragDrop[]} dds The array of drag and drop objects
16960 * @return {DragDrop} The best single match
16963 getBestMatch: function(dds) {
16965 // Return null if the input is not what we expect
16966 //if (!dds || !dds.length || dds.length == 0) {
16968 // If there is only one item, it wins
16969 //} else if (dds.length == 1) {
16971 var len = dds.length;
16976 // Loop through the targeted items
16977 for (var i=0; i<len; ++i) {
16979 // If the cursor is over the object, it wins. If the
16980 // cursor is over multiple matches, the first one we come
16982 if (dd.cursorIsOver) {
16985 // Otherwise the object with the most overlap wins
16988 winner.overlap.getArea() < dd.overlap.getArea()) {
16999 * Refreshes the cache of the top-left and bottom-right points of the
17000 * drag and drop objects in the specified group(s). This is in the
17001 * format that is stored in the drag and drop instance, so typical
17004 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
17008 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
17010 * @TODO this really should be an indexed array. Alternatively this
17011 * method could accept both.
17012 * @method refreshCache
17013 * @param {Object} groups an associative array of groups to refresh
17016 refreshCache: function(groups) {
17017 for (var sGroup in groups) {
17018 if ("string" != typeof sGroup) {
17021 for (var i in this.ids[sGroup]) {
17022 var oDD = this.ids[sGroup][i];
17024 if (this.isTypeOfDD(oDD)) {
17025 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
17026 var loc = this.getLocation(oDD);
17028 this.locationCache[oDD.id] = loc;
17030 delete this.locationCache[oDD.id];
17031 // this will unregister the drag and drop object if
17032 // the element is not in a usable state
17041 * This checks to make sure an element exists and is in the DOM. The
17042 * main purpose is to handle cases where innerHTML is used to remove
17043 * drag and drop objects from the DOM. IE provides an 'unspecified
17044 * error' when trying to access the offsetParent of such an element
17046 * @param {HTMLElement} el the element to check
17047 * @return {boolean} true if the element looks usable
17050 verifyEl: function(el) {
17055 parent = el.offsetParent;
17058 parent = el.offsetParent;
17069 * Returns a Region object containing the drag and drop element's position
17070 * and size, including the padding configured for it
17071 * @method getLocation
17072 * @param {DragDrop} oDD the drag and drop object to get the
17074 * @return {Roo.lib.Region} a Region object representing the total area
17075 * the element occupies, including any padding
17076 * the instance is configured for.
17079 getLocation: function(oDD) {
17080 if (! this.isTypeOfDD(oDD)) {
17084 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17087 pos= Roo.lib.Dom.getXY(el);
17095 x2 = x1 + el.offsetWidth;
17097 y2 = y1 + el.offsetHeight;
17099 t = y1 - oDD.padding[0];
17100 r = x2 + oDD.padding[1];
17101 b = y2 + oDD.padding[2];
17102 l = x1 - oDD.padding[3];
17104 return new Roo.lib.Region( t, r, b, l );
17108 * Checks the cursor location to see if it over the target
17109 * @method isOverTarget
17110 * @param {Roo.lib.Point} pt The point to evaluate
17111 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17112 * @return {boolean} true if the mouse is over the target
17116 isOverTarget: function(pt, oTarget, intersect) {
17117 // use cache if available
17118 var loc = this.locationCache[oTarget.id];
17119 if (!loc || !this.useCache) {
17120 loc = this.getLocation(oTarget);
17121 this.locationCache[oTarget.id] = loc;
17129 oTarget.cursorIsOver = loc.contains( pt );
17131 // DragDrop is using this as a sanity check for the initial mousedown
17132 // in this case we are done. In POINT mode, if the drag obj has no
17133 // contraints, we are also done. Otherwise we need to evaluate the
17134 // location of the target as related to the actual location of the
17135 // dragged element.
17136 var dc = this.dragCurrent;
17137 if (!dc || !dc.getTargetCoord ||
17138 (!intersect && !dc.constrainX && !dc.constrainY)) {
17139 return oTarget.cursorIsOver;
17142 oTarget.overlap = null;
17144 // Get the current location of the drag element, this is the
17145 // location of the mouse event less the delta that represents
17146 // where the original mousedown happened on the element. We
17147 // need to consider constraints and ticks as well.
17148 var pos = dc.getTargetCoord(pt.x, pt.y);
17150 var el = dc.getDragEl();
17151 var curRegion = new Roo.lib.Region( pos.y,
17152 pos.x + el.offsetWidth,
17153 pos.y + el.offsetHeight,
17156 var overlap = curRegion.intersect(loc);
17159 oTarget.overlap = overlap;
17160 return (intersect) ? true : oTarget.cursorIsOver;
17167 * unload event handler
17168 * @method _onUnload
17172 _onUnload: function(e, me) {
17173 Roo.dd.DragDropMgr.unregAll();
17177 * Cleans up the drag and drop events and objects.
17182 unregAll: function() {
17184 if (this.dragCurrent) {
17186 this.dragCurrent = null;
17189 this._execOnAll("unreg", []);
17191 for (i in this.elementCache) {
17192 delete this.elementCache[i];
17195 this.elementCache = {};
17200 * A cache of DOM elements
17201 * @property elementCache
17208 * Get the wrapper for the DOM element specified
17209 * @method getElWrapper
17210 * @param {String} id the id of the element to get
17211 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17213 * @deprecated This wrapper isn't that useful
17216 getElWrapper: function(id) {
17217 var oWrapper = this.elementCache[id];
17218 if (!oWrapper || !oWrapper.el) {
17219 oWrapper = this.elementCache[id] =
17220 new this.ElementWrapper(Roo.getDom(id));
17226 * Returns the actual DOM element
17227 * @method getElement
17228 * @param {String} id the id of the elment to get
17229 * @return {Object} The element
17230 * @deprecated use Roo.getDom instead
17233 getElement: function(id) {
17234 return Roo.getDom(id);
17238 * Returns the style property for the DOM element (i.e.,
17239 * document.getElById(id).style)
17241 * @param {String} id the id of the elment to get
17242 * @return {Object} The style property of the element
17243 * @deprecated use Roo.getDom instead
17246 getCss: function(id) {
17247 var el = Roo.getDom(id);
17248 return (el) ? el.style : null;
17252 * Inner class for cached elements
17253 * @class DragDropMgr.ElementWrapper
17258 ElementWrapper: function(el) {
17263 this.el = el || null;
17268 this.id = this.el && el.id;
17270 * A reference to the style property
17273 this.css = this.el && el.style;
17277 * Returns the X position of an html element
17279 * @param el the element for which to get the position
17280 * @return {int} the X coordinate
17282 * @deprecated use Roo.lib.Dom.getX instead
17285 getPosX: function(el) {
17286 return Roo.lib.Dom.getX(el);
17290 * Returns the Y position of an html element
17292 * @param el the element for which to get the position
17293 * @return {int} the Y coordinate
17294 * @deprecated use Roo.lib.Dom.getY instead
17297 getPosY: function(el) {
17298 return Roo.lib.Dom.getY(el);
17302 * Swap two nodes. In IE, we use the native method, for others we
17303 * emulate the IE behavior
17305 * @param n1 the first node to swap
17306 * @param n2 the other node to swap
17309 swapNode: function(n1, n2) {
17313 var p = n2.parentNode;
17314 var s = n2.nextSibling;
17317 p.insertBefore(n1, n2);
17318 } else if (n2 == n1.nextSibling) {
17319 p.insertBefore(n2, n1);
17321 n1.parentNode.replaceChild(n2, n1);
17322 p.insertBefore(n1, s);
17328 * Returns the current scroll position
17329 * @method getScroll
17333 getScroll: function () {
17334 var t, l, dde=document.documentElement, db=document.body;
17335 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17337 l = dde.scrollLeft;
17344 return { top: t, left: l };
17348 * Returns the specified element style property
17350 * @param {HTMLElement} el the element
17351 * @param {string} styleProp the style property
17352 * @return {string} The value of the style property
17353 * @deprecated use Roo.lib.Dom.getStyle
17356 getStyle: function(el, styleProp) {
17357 return Roo.fly(el).getStyle(styleProp);
17361 * Gets the scrollTop
17362 * @method getScrollTop
17363 * @return {int} the document's scrollTop
17366 getScrollTop: function () { return this.getScroll().top; },
17369 * Gets the scrollLeft
17370 * @method getScrollLeft
17371 * @return {int} the document's scrollTop
17374 getScrollLeft: function () { return this.getScroll().left; },
17377 * Sets the x/y position of an element to the location of the
17380 * @param {HTMLElement} moveEl The element to move
17381 * @param {HTMLElement} targetEl The position reference element
17384 moveToEl: function (moveEl, targetEl) {
17385 var aCoord = Roo.lib.Dom.getXY(targetEl);
17386 Roo.lib.Dom.setXY(moveEl, aCoord);
17390 * Numeric array sort function
17391 * @method numericSort
17394 numericSort: function(a, b) { return (a - b); },
17398 * @property _timeoutCount
17405 * Trying to make the load order less important. Without this we get
17406 * an error if this file is loaded before the Event Utility.
17407 * @method _addListeners
17411 _addListeners: function() {
17412 var DDM = Roo.dd.DDM;
17413 if ( Roo.lib.Event && document ) {
17416 if (DDM._timeoutCount > 2000) {
17418 setTimeout(DDM._addListeners, 10);
17419 if (document && document.body) {
17420 DDM._timeoutCount += 1;
17427 * Recursively searches the immediate parent and all child nodes for
17428 * the handle element in order to determine wheter or not it was
17430 * @method handleWasClicked
17431 * @param node the html element to inspect
17434 handleWasClicked: function(node, id) {
17435 if (this.isHandle(id, node.id)) {
17438 // check to see if this is a text node child of the one we want
17439 var p = node.parentNode;
17442 if (this.isHandle(id, p.id)) {
17457 // shorter alias, save a few bytes
17458 Roo.dd.DDM = Roo.dd.DragDropMgr;
17459 Roo.dd.DDM._addListeners();
17463 * Ext JS Library 1.1.1
17464 * Copyright(c) 2006-2007, Ext JS, LLC.
17466 * Originally Released Under LGPL - original licence link has changed is not relivant.
17469 * <script type="text/javascript">
17474 * A DragDrop implementation where the linked element follows the
17475 * mouse cursor during a drag.
17476 * @extends Roo.dd.DragDrop
17478 * @param {String} id the id of the linked element
17479 * @param {String} sGroup the group of related DragDrop items
17480 * @param {object} config an object containing configurable attributes
17481 * Valid properties for DD:
17484 Roo.dd.DD = function(id, sGroup, config) {
17486 this.init(id, sGroup, config);
17490 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17493 * When set to true, the utility automatically tries to scroll the browser
17494 * window wehn a drag and drop element is dragged near the viewport boundary.
17495 * Defaults to true.
17502 * Sets the pointer offset to the distance between the linked element's top
17503 * left corner and the location the element was clicked
17504 * @method autoOffset
17505 * @param {int} iPageX the X coordinate of the click
17506 * @param {int} iPageY the Y coordinate of the click
17508 autoOffset: function(iPageX, iPageY) {
17509 var x = iPageX - this.startPageX;
17510 var y = iPageY - this.startPageY;
17511 this.setDelta(x, y);
17515 * Sets the pointer offset. You can call this directly to force the
17516 * offset to be in a particular location (e.g., pass in 0,0 to set it
17517 * to the center of the object)
17519 * @param {int} iDeltaX the distance from the left
17520 * @param {int} iDeltaY the distance from the top
17522 setDelta: function(iDeltaX, iDeltaY) {
17523 this.deltaX = iDeltaX;
17524 this.deltaY = iDeltaY;
17528 * Sets the drag element to the location of the mousedown or click event,
17529 * maintaining the cursor location relative to the location on the element
17530 * that was clicked. Override this if you want to place the element in a
17531 * location other than where the cursor is.
17532 * @method setDragElPos
17533 * @param {int} iPageX the X coordinate of the mousedown or drag event
17534 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17536 setDragElPos: function(iPageX, iPageY) {
17537 // the first time we do this, we are going to check to make sure
17538 // the element has css positioning
17540 var el = this.getDragEl();
17541 this.alignElWithMouse(el, iPageX, iPageY);
17545 * Sets the element to the location of the mousedown or click event,
17546 * maintaining the cursor location relative to the location on the element
17547 * that was clicked. Override this if you want to place the element in a
17548 * location other than where the cursor is.
17549 * @method alignElWithMouse
17550 * @param {HTMLElement} el the element to move
17551 * @param {int} iPageX the X coordinate of the mousedown or drag event
17552 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17554 alignElWithMouse: function(el, iPageX, iPageY) {
17555 var oCoord = this.getTargetCoord(iPageX, iPageY);
17556 var fly = el.dom ? el : Roo.fly(el);
17557 if (!this.deltaSetXY) {
17558 var aCoord = [oCoord.x, oCoord.y];
17560 var newLeft = fly.getLeft(true);
17561 var newTop = fly.getTop(true);
17562 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17564 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17567 this.cachePosition(oCoord.x, oCoord.y);
17568 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17573 * Saves the most recent position so that we can reset the constraints and
17574 * tick marks on-demand. We need to know this so that we can calculate the
17575 * number of pixels the element is offset from its original position.
17576 * @method cachePosition
17577 * @param iPageX the current x position (optional, this just makes it so we
17578 * don't have to look it up again)
17579 * @param iPageY the current y position (optional, this just makes it so we
17580 * don't have to look it up again)
17582 cachePosition: function(iPageX, iPageY) {
17584 this.lastPageX = iPageX;
17585 this.lastPageY = iPageY;
17587 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17588 this.lastPageX = aCoord[0];
17589 this.lastPageY = aCoord[1];
17594 * Auto-scroll the window if the dragged object has been moved beyond the
17595 * visible window boundary.
17596 * @method autoScroll
17597 * @param {int} x the drag element's x position
17598 * @param {int} y the drag element's y position
17599 * @param {int} h the height of the drag element
17600 * @param {int} w the width of the drag element
17603 autoScroll: function(x, y, h, w) {
17606 // The client height
17607 var clientH = Roo.lib.Dom.getViewWidth();
17609 // The client width
17610 var clientW = Roo.lib.Dom.getViewHeight();
17612 // The amt scrolled down
17613 var st = this.DDM.getScrollTop();
17615 // The amt scrolled right
17616 var sl = this.DDM.getScrollLeft();
17618 // Location of the bottom of the element
17621 // Location of the right of the element
17624 // The distance from the cursor to the bottom of the visible area,
17625 // adjusted so that we don't scroll if the cursor is beyond the
17626 // element drag constraints
17627 var toBot = (clientH + st - y - this.deltaY);
17629 // The distance from the cursor to the right of the visible area
17630 var toRight = (clientW + sl - x - this.deltaX);
17633 // How close to the edge the cursor must be before we scroll
17634 // var thresh = (document.all) ? 100 : 40;
17637 // How many pixels to scroll per autoscroll op. This helps to reduce
17638 // clunky scrolling. IE is more sensitive about this ... it needs this
17639 // value to be higher.
17640 var scrAmt = (document.all) ? 80 : 30;
17642 // Scroll down if we are near the bottom of the visible page and the
17643 // obj extends below the crease
17644 if ( bot > clientH && toBot < thresh ) {
17645 window.scrollTo(sl, st + scrAmt);
17648 // Scroll up if the window is scrolled down and the top of the object
17649 // goes above the top border
17650 if ( y < st && st > 0 && y - st < thresh ) {
17651 window.scrollTo(sl, st - scrAmt);
17654 // Scroll right if the obj is beyond the right border and the cursor is
17655 // near the border.
17656 if ( right > clientW && toRight < thresh ) {
17657 window.scrollTo(sl + scrAmt, st);
17660 // Scroll left if the window has been scrolled to the right and the obj
17661 // extends past the left border
17662 if ( x < sl && sl > 0 && x - sl < thresh ) {
17663 window.scrollTo(sl - scrAmt, st);
17669 * Finds the location the element should be placed if we want to move
17670 * it to where the mouse location less the click offset would place us.
17671 * @method getTargetCoord
17672 * @param {int} iPageX the X coordinate of the click
17673 * @param {int} iPageY the Y coordinate of the click
17674 * @return an object that contains the coordinates (Object.x and Object.y)
17677 getTargetCoord: function(iPageX, iPageY) {
17680 var x = iPageX - this.deltaX;
17681 var y = iPageY - this.deltaY;
17683 if (this.constrainX) {
17684 if (x < this.minX) { x = this.minX; }
17685 if (x > this.maxX) { x = this.maxX; }
17688 if (this.constrainY) {
17689 if (y < this.minY) { y = this.minY; }
17690 if (y > this.maxY) { y = this.maxY; }
17693 x = this.getTick(x, this.xTicks);
17694 y = this.getTick(y, this.yTicks);
17701 * Sets up config options specific to this class. Overrides
17702 * Roo.dd.DragDrop, but all versions of this method through the
17703 * inheritance chain are called
17705 applyConfig: function() {
17706 Roo.dd.DD.superclass.applyConfig.call(this);
17707 this.scroll = (this.config.scroll !== false);
17711 * Event that fires prior to the onMouseDown event. Overrides
17714 b4MouseDown: function(e) {
17715 // this.resetConstraints();
17716 this.autoOffset(e.getPageX(),
17721 * Event that fires prior to the onDrag event. Overrides
17724 b4Drag: function(e) {
17725 this.setDragElPos(e.getPageX(),
17729 toString: function() {
17730 return ("DD " + this.id);
17733 //////////////////////////////////////////////////////////////////////////
17734 // Debugging ygDragDrop events that can be overridden
17735 //////////////////////////////////////////////////////////////////////////
17737 startDrag: function(x, y) {
17740 onDrag: function(e) {
17743 onDragEnter: function(e, id) {
17746 onDragOver: function(e, id) {
17749 onDragOut: function(e, id) {
17752 onDragDrop: function(e, id) {
17755 endDrag: function(e) {
17762 * Ext JS Library 1.1.1
17763 * Copyright(c) 2006-2007, Ext JS, LLC.
17765 * Originally Released Under LGPL - original licence link has changed is not relivant.
17768 * <script type="text/javascript">
17772 * @class Roo.dd.DDProxy
17773 * A DragDrop implementation that inserts an empty, bordered div into
17774 * the document that follows the cursor during drag operations. At the time of
17775 * the click, the frame div is resized to the dimensions of the linked html
17776 * element, and moved to the exact location of the linked element.
17778 * References to the "frame" element refer to the single proxy element that
17779 * was created to be dragged in place of all DDProxy elements on the
17782 * @extends Roo.dd.DD
17784 * @param {String} id the id of the linked html element
17785 * @param {String} sGroup the group of related DragDrop objects
17786 * @param {object} config an object containing configurable attributes
17787 * Valid properties for DDProxy in addition to those in DragDrop:
17788 * resizeFrame, centerFrame, dragElId
17790 Roo.dd.DDProxy = function(id, sGroup, config) {
17792 this.init(id, sGroup, config);
17798 * The default drag frame div id
17799 * @property Roo.dd.DDProxy.dragElId
17803 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17805 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17808 * By default we resize the drag frame to be the same size as the element
17809 * we want to drag (this is to get the frame effect). We can turn it off
17810 * if we want a different behavior.
17811 * @property resizeFrame
17817 * By default the frame is positioned exactly where the drag element is, so
17818 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17819 * you do not have constraints on the obj is to have the drag frame centered
17820 * around the cursor. Set centerFrame to true for this effect.
17821 * @property centerFrame
17824 centerFrame: false,
17827 * Creates the proxy element if it does not yet exist
17828 * @method createFrame
17830 createFrame: function() {
17832 var body = document.body;
17834 if (!body || !body.firstChild) {
17835 setTimeout( function() { self.createFrame(); }, 50 );
17839 var div = this.getDragEl();
17842 div = document.createElement("div");
17843 div.id = this.dragElId;
17846 s.position = "absolute";
17847 s.visibility = "hidden";
17849 s.border = "2px solid #aaa";
17852 // appendChild can blow up IE if invoked prior to the window load event
17853 // while rendering a table. It is possible there are other scenarios
17854 // that would cause this to happen as well.
17855 body.insertBefore(div, body.firstChild);
17860 * Initialization for the drag frame element. Must be called in the
17861 * constructor of all subclasses
17862 * @method initFrame
17864 initFrame: function() {
17865 this.createFrame();
17868 applyConfig: function() {
17869 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17871 this.resizeFrame = (this.config.resizeFrame !== false);
17872 this.centerFrame = (this.config.centerFrame);
17873 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17877 * Resizes the drag frame to the dimensions of the clicked object, positions
17878 * it over the object, and finally displays it
17879 * @method showFrame
17880 * @param {int} iPageX X click position
17881 * @param {int} iPageY Y click position
17884 showFrame: function(iPageX, iPageY) {
17885 var el = this.getEl();
17886 var dragEl = this.getDragEl();
17887 var s = dragEl.style;
17889 this._resizeProxy();
17891 if (this.centerFrame) {
17892 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17893 Math.round(parseInt(s.height, 10)/2) );
17896 this.setDragElPos(iPageX, iPageY);
17898 Roo.fly(dragEl).show();
17902 * The proxy is automatically resized to the dimensions of the linked
17903 * element when a drag is initiated, unless resizeFrame is set to false
17904 * @method _resizeProxy
17907 _resizeProxy: function() {
17908 if (this.resizeFrame) {
17909 var el = this.getEl();
17910 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17914 // overrides Roo.dd.DragDrop
17915 b4MouseDown: function(e) {
17916 var x = e.getPageX();
17917 var y = e.getPageY();
17918 this.autoOffset(x, y);
17919 this.setDragElPos(x, y);
17922 // overrides Roo.dd.DragDrop
17923 b4StartDrag: function(x, y) {
17924 // show the drag frame
17925 this.showFrame(x, y);
17928 // overrides Roo.dd.DragDrop
17929 b4EndDrag: function(e) {
17930 Roo.fly(this.getDragEl()).hide();
17933 // overrides Roo.dd.DragDrop
17934 // By default we try to move the element to the last location of the frame.
17935 // This is so that the default behavior mirrors that of Roo.dd.DD.
17936 endDrag: function(e) {
17938 var lel = this.getEl();
17939 var del = this.getDragEl();
17941 // Show the drag frame briefly so we can get its position
17942 del.style.visibility = "";
17945 // Hide the linked element before the move to get around a Safari
17947 lel.style.visibility = "hidden";
17948 Roo.dd.DDM.moveToEl(lel, del);
17949 del.style.visibility = "hidden";
17950 lel.style.visibility = "";
17955 beforeMove : function(){
17959 afterDrag : function(){
17963 toString: function() {
17964 return ("DDProxy " + this.id);
17970 * Ext JS Library 1.1.1
17971 * Copyright(c) 2006-2007, Ext JS, LLC.
17973 * Originally Released Under LGPL - original licence link has changed is not relivant.
17976 * <script type="text/javascript">
17980 * @class Roo.dd.DDTarget
17981 * A DragDrop implementation that does not move, but can be a drop
17982 * target. You would get the same result by simply omitting implementation
17983 * for the event callbacks, but this way we reduce the processing cost of the
17984 * event listener and the callbacks.
17985 * @extends Roo.dd.DragDrop
17987 * @param {String} id the id of the element that is a drop target
17988 * @param {String} sGroup the group of related DragDrop objects
17989 * @param {object} config an object containing configurable attributes
17990 * Valid properties for DDTarget in addition to those in
17994 Roo.dd.DDTarget = function(id, sGroup, config) {
17996 this.initTarget(id, sGroup, config);
17998 if (config.listeners || config.events) {
17999 Roo.dd.DragDrop.superclass.constructor.call(this, {
18000 listeners : config.listeners || {},
18001 events : config.events || {}
18006 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
18007 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
18008 toString: function() {
18009 return ("DDTarget " + this.id);
18014 * Ext JS Library 1.1.1
18015 * Copyright(c) 2006-2007, Ext JS, LLC.
18017 * Originally Released Under LGPL - original licence link has changed is not relivant.
18020 * <script type="text/javascript">
18025 * @class Roo.dd.ScrollManager
18026 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
18027 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
18030 Roo.dd.ScrollManager = function(){
18031 var ddm = Roo.dd.DragDropMgr;
18038 var onStop = function(e){
18043 var triggerRefresh = function(){
18044 if(ddm.dragCurrent){
18045 ddm.refreshCache(ddm.dragCurrent.groups);
18049 var doScroll = function(){
18050 if(ddm.dragCurrent){
18051 var dds = Roo.dd.ScrollManager;
18053 if(proc.el.scroll(proc.dir, dds.increment)){
18057 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18062 var clearProc = function(){
18064 clearInterval(proc.id);
18071 var startProc = function(el, dir){
18072 Roo.log('scroll startproc');
18076 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18079 var onFire = function(e, isDrop){
18081 if(isDrop || !ddm.dragCurrent){ return; }
18082 var dds = Roo.dd.ScrollManager;
18083 if(!dragEl || dragEl != ddm.dragCurrent){
18084 dragEl = ddm.dragCurrent;
18085 // refresh regions on drag start
18086 dds.refreshCache();
18089 var xy = Roo.lib.Event.getXY(e);
18090 var pt = new Roo.lib.Point(xy[0], xy[1]);
18091 for(var id in els){
18092 var el = els[id], r = el._region;
18093 if(r && r.contains(pt) && el.isScrollable()){
18094 if(r.bottom - pt.y <= dds.thresh){
18096 startProc(el, "down");
18099 }else if(r.right - pt.x <= dds.thresh){
18101 startProc(el, "left");
18104 }else if(pt.y - r.top <= dds.thresh){
18106 startProc(el, "up");
18109 }else if(pt.x - r.left <= dds.thresh){
18111 startProc(el, "right");
18120 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18121 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18125 * Registers new overflow element(s) to auto scroll
18126 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18128 register : function(el){
18129 if(el instanceof Array){
18130 for(var i = 0, len = el.length; i < len; i++) {
18131 this.register(el[i]);
18137 Roo.dd.ScrollManager.els = els;
18141 * Unregisters overflow element(s) so they are no longer scrolled
18142 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18144 unregister : function(el){
18145 if(el instanceof Array){
18146 for(var i = 0, len = el.length; i < len; i++) {
18147 this.unregister(el[i]);
18156 * The number of pixels from the edge of a container the pointer needs to be to
18157 * trigger scrolling (defaults to 25)
18163 * The number of pixels to scroll in each scroll increment (defaults to 50)
18169 * The frequency of scrolls in milliseconds (defaults to 500)
18175 * True to animate the scroll (defaults to true)
18181 * The animation duration in seconds -
18182 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18188 * Manually trigger a cache refresh.
18190 refreshCache : function(){
18191 for(var id in els){
18192 if(typeof els[id] == 'object'){ // for people extending the object prototype
18193 els[id]._region = els[id].getRegion();
18200 * Ext JS Library 1.1.1
18201 * Copyright(c) 2006-2007, Ext JS, LLC.
18203 * Originally Released Under LGPL - original licence link has changed is not relivant.
18206 * <script type="text/javascript">
18211 * @class Roo.dd.Registry
18212 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18213 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18216 Roo.dd.Registry = function(){
18219 var autoIdSeed = 0;
18221 var getId = function(el, autogen){
18222 if(typeof el == "string"){
18226 if(!id && autogen !== false){
18227 id = "roodd-" + (++autoIdSeed);
18235 * Register a drag drop element
18236 * @param {String|HTMLElement} element The id or DOM node to register
18237 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18238 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18239 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18240 * populated in the data object (if applicable):
18242 Value Description<br />
18243 --------- ------------------------------------------<br />
18244 handles Array of DOM nodes that trigger dragging<br />
18245 for the element being registered<br />
18246 isHandle True if the element passed in triggers<br />
18247 dragging itself, else false
18250 register : function(el, data){
18252 if(typeof el == "string"){
18253 el = document.getElementById(el);
18256 elements[getId(el)] = data;
18257 if(data.isHandle !== false){
18258 handles[data.ddel.id] = data;
18261 var hs = data.handles;
18262 for(var i = 0, len = hs.length; i < len; i++){
18263 handles[getId(hs[i])] = data;
18269 * Unregister a drag drop element
18270 * @param {String|HTMLElement} element The id or DOM node to unregister
18272 unregister : function(el){
18273 var id = getId(el, false);
18274 var data = elements[id];
18276 delete elements[id];
18278 var hs = data.handles;
18279 for(var i = 0, len = hs.length; i < len; i++){
18280 delete handles[getId(hs[i], false)];
18287 * Returns the handle registered for a DOM Node by id
18288 * @param {String|HTMLElement} id The DOM node or id to look up
18289 * @return {Object} handle The custom handle data
18291 getHandle : function(id){
18292 if(typeof id != "string"){ // must be element?
18295 return handles[id];
18299 * Returns the handle that is registered for the DOM node that is the target of the event
18300 * @param {Event} e The event
18301 * @return {Object} handle The custom handle data
18303 getHandleFromEvent : function(e){
18304 var t = Roo.lib.Event.getTarget(e);
18305 return t ? handles[t.id] : null;
18309 * Returns a custom data object that is registered for a DOM node by id
18310 * @param {String|HTMLElement} id The DOM node or id to look up
18311 * @return {Object} data The custom data
18313 getTarget : function(id){
18314 if(typeof id != "string"){ // must be element?
18317 return elements[id];
18321 * Returns a custom data object that is registered for the DOM node that is the target of the event
18322 * @param {Event} e The event
18323 * @return {Object} data The custom data
18325 getTargetFromEvent : function(e){
18326 var t = Roo.lib.Event.getTarget(e);
18327 return t ? elements[t.id] || handles[t.id] : null;
18332 * Ext JS Library 1.1.1
18333 * Copyright(c) 2006-2007, Ext JS, LLC.
18335 * Originally Released Under LGPL - original licence link has changed is not relivant.
18338 * <script type="text/javascript">
18343 * @class Roo.dd.StatusProxy
18344 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18345 * default drag proxy used by all Roo.dd components.
18347 * @param {Object} config
18349 Roo.dd.StatusProxy = function(config){
18350 Roo.apply(this, config);
18351 this.id = this.id || Roo.id();
18352 this.el = new Roo.Layer({
18354 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18355 {tag: "div", cls: "x-dd-drop-icon"},
18356 {tag: "div", cls: "x-dd-drag-ghost"}
18359 shadow: !config || config.shadow !== false
18361 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18362 this.dropStatus = this.dropNotAllowed;
18365 Roo.dd.StatusProxy.prototype = {
18367 * @cfg {String} dropAllowed
18368 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18370 dropAllowed : "x-dd-drop-ok",
18372 * @cfg {String} dropNotAllowed
18373 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18375 dropNotAllowed : "x-dd-drop-nodrop",
18378 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18379 * over the current target element.
18380 * @param {String} cssClass The css class for the new drop status indicator image
18382 setStatus : function(cssClass){
18383 cssClass = cssClass || this.dropNotAllowed;
18384 if(this.dropStatus != cssClass){
18385 this.el.replaceClass(this.dropStatus, cssClass);
18386 this.dropStatus = cssClass;
18391 * Resets the status indicator to the default dropNotAllowed value
18392 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18394 reset : function(clearGhost){
18395 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18396 this.dropStatus = this.dropNotAllowed;
18398 this.ghost.update("");
18403 * Updates the contents of the ghost element
18404 * @param {String} html The html that will replace the current innerHTML of the ghost element
18406 update : function(html){
18407 if(typeof html == "string"){
18408 this.ghost.update(html);
18410 this.ghost.update("");
18411 html.style.margin = "0";
18412 this.ghost.dom.appendChild(html);
18414 // ensure float = none set?? cant remember why though.
18415 var el = this.ghost.dom.firstChild;
18417 Roo.fly(el).setStyle('float', 'none');
18422 * Returns the underlying proxy {@link Roo.Layer}
18423 * @return {Roo.Layer} el
18425 getEl : function(){
18430 * Returns the ghost element
18431 * @return {Roo.Element} el
18433 getGhost : function(){
18439 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18441 hide : function(clear){
18449 * Stops the repair animation if it's currently running
18452 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18458 * Displays this proxy
18465 * Force the Layer to sync its shadow and shim positions to the element
18472 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18473 * invalid drop operation by the item being dragged.
18474 * @param {Array} xy The XY position of the element ([x, y])
18475 * @param {Function} callback The function to call after the repair is complete
18476 * @param {Object} scope The scope in which to execute the callback
18478 repair : function(xy, callback, scope){
18479 this.callback = callback;
18480 this.scope = scope;
18481 if(xy && this.animRepair !== false){
18482 this.el.addClass("x-dd-drag-repair");
18483 this.el.hideUnders(true);
18484 this.anim = this.el.shift({
18485 duration: this.repairDuration || .5,
18489 callback: this.afterRepair,
18493 this.afterRepair();
18498 afterRepair : function(){
18500 if(typeof this.callback == "function"){
18501 this.callback.call(this.scope || this);
18503 this.callback = null;
18508 * Ext JS Library 1.1.1
18509 * Copyright(c) 2006-2007, Ext JS, LLC.
18511 * Originally Released Under LGPL - original licence link has changed is not relivant.
18514 * <script type="text/javascript">
18518 * @class Roo.dd.DragSource
18519 * @extends Roo.dd.DDProxy
18520 * A simple class that provides the basic implementation needed to make any element draggable.
18522 * @param {String/HTMLElement/Element} el The container element
18523 * @param {Object} config
18525 Roo.dd.DragSource = function(el, config){
18526 this.el = Roo.get(el);
18527 this.dragData = {};
18529 Roo.apply(this, config);
18532 this.proxy = new Roo.dd.StatusProxy();
18535 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18536 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18538 this.dragging = false;
18541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18543 * @cfg {String} dropAllowed
18544 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18546 dropAllowed : "x-dd-drop-ok",
18548 * @cfg {String} dropNotAllowed
18549 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18551 dropNotAllowed : "x-dd-drop-nodrop",
18554 * Returns the data object associated with this drag source
18555 * @return {Object} data An object containing arbitrary data
18557 getDragData : function(e){
18558 return this.dragData;
18562 onDragEnter : function(e, id){
18563 var target = Roo.dd.DragDropMgr.getDDById(id);
18564 this.cachedTarget = target;
18565 if(this.beforeDragEnter(target, e, id) !== false){
18566 if(target.isNotifyTarget){
18567 var status = target.notifyEnter(this, e, this.dragData);
18568 this.proxy.setStatus(status);
18570 this.proxy.setStatus(this.dropAllowed);
18573 if(this.afterDragEnter){
18575 * An empty function by default, but provided so that you can perform a custom action
18576 * when the dragged item enters the drop target by providing an implementation.
18577 * @param {Roo.dd.DragDrop} target The drop target
18578 * @param {Event} e The event object
18579 * @param {String} id The id of the dragged element
18580 * @method afterDragEnter
18582 this.afterDragEnter(target, e, id);
18588 * An empty function by default, but provided so that you can perform a custom action
18589 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
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 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18595 beforeDragEnter : function(target, e, id){
18600 alignElWithMouse: function() {
18601 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18606 onDragOver : function(e, id){
18607 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18608 if(this.beforeDragOver(target, e, id) !== false){
18609 if(target.isNotifyTarget){
18610 var status = target.notifyOver(this, e, this.dragData);
18611 this.proxy.setStatus(status);
18614 if(this.afterDragOver){
18616 * An empty function by default, but provided so that you can perform a custom action
18617 * while the dragged item is over the drop target by providing an implementation.
18618 * @param {Roo.dd.DragDrop} target The drop target
18619 * @param {Event} e The event object
18620 * @param {String} id The id of the dragged element
18621 * @method afterDragOver
18623 this.afterDragOver(target, e, id);
18629 * An empty function by default, but provided so that you can perform a custom action
18630 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18631 * @param {Roo.dd.DragDrop} target The drop target
18632 * @param {Event} e The event object
18633 * @param {String} id The id of the dragged element
18634 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18636 beforeDragOver : function(target, e, id){
18641 onDragOut : function(e, id){
18642 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18643 if(this.beforeDragOut(target, e, id) !== false){
18644 if(target.isNotifyTarget){
18645 target.notifyOut(this, e, this.dragData);
18647 this.proxy.reset();
18648 if(this.afterDragOut){
18650 * An empty function by default, but provided so that you can perform a custom action
18651 * after the dragged item is dragged out of the target without dropping.
18652 * @param {Roo.dd.DragDrop} target The drop target
18653 * @param {Event} e The event object
18654 * @param {String} id The id of the dragged element
18655 * @method afterDragOut
18657 this.afterDragOut(target, e, id);
18660 this.cachedTarget = null;
18664 * An empty function by default, but provided so that you can perform a custom action before the dragged
18665 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18666 * @param {Roo.dd.DragDrop} target The drop target
18667 * @param {Event} e The event object
18668 * @param {String} id The id of the dragged element
18669 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18671 beforeDragOut : function(target, e, id){
18676 onDragDrop : function(e, id){
18677 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18678 if(this.beforeDragDrop(target, e, id) !== false){
18679 if(target.isNotifyTarget){
18680 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18681 this.onValidDrop(target, e, id);
18683 this.onInvalidDrop(target, e, id);
18686 this.onValidDrop(target, e, id);
18689 if(this.afterDragDrop){
18691 * An empty function by default, but provided so that you can perform a custom action
18692 * after a valid drag drop has occurred by providing an implementation.
18693 * @param {Roo.dd.DragDrop} target The drop target
18694 * @param {Event} e The event object
18695 * @param {String} id The id of the dropped element
18696 * @method afterDragDrop
18698 this.afterDragDrop(target, e, id);
18701 delete this.cachedTarget;
18705 * An empty function by default, but provided so that you can perform a custom action before the dragged
18706 * item is dropped onto the target and optionally cancel the onDragDrop.
18707 * @param {Roo.dd.DragDrop} target The drop target
18708 * @param {Event} e The event object
18709 * @param {String} id The id of the dragged element
18710 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18712 beforeDragDrop : function(target, e, id){
18717 onValidDrop : function(target, e, id){
18719 if(this.afterValidDrop){
18721 * An empty function by default, but provided so that you can perform a custom action
18722 * after a valid drop has occurred by providing an implementation.
18723 * @param {Object} target The target DD
18724 * @param {Event} e The event object
18725 * @param {String} id The id of the dropped element
18726 * @method afterInvalidDrop
18728 this.afterValidDrop(target, e, id);
18733 getRepairXY : function(e, data){
18734 return this.el.getXY();
18738 onInvalidDrop : function(target, e, id){
18739 this.beforeInvalidDrop(target, e, id);
18740 if(this.cachedTarget){
18741 if(this.cachedTarget.isNotifyTarget){
18742 this.cachedTarget.notifyOut(this, e, this.dragData);
18744 this.cacheTarget = null;
18746 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18748 if(this.afterInvalidDrop){
18750 * An empty function by default, but provided so that you can perform a custom action
18751 * after an invalid drop has occurred by providing an implementation.
18752 * @param {Event} e The event object
18753 * @param {String} id The id of the dropped element
18754 * @method afterInvalidDrop
18756 this.afterInvalidDrop(e, id);
18761 afterRepair : function(){
18763 this.el.highlight(this.hlColor || "c3daf9");
18765 this.dragging = false;
18769 * An empty function by default, but provided so that you can perform a custom action after an invalid
18770 * drop has occurred.
18771 * @param {Roo.dd.DragDrop} target The drop target
18772 * @param {Event} e The event object
18773 * @param {String} id The id of the dragged element
18774 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18776 beforeInvalidDrop : function(target, e, id){
18781 handleMouseDown : function(e){
18782 if(this.dragging) {
18785 var data = this.getDragData(e);
18786 if(data && this.onBeforeDrag(data, e) !== false){
18787 this.dragData = data;
18789 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18794 * An empty function by default, but provided so that you can perform a custom action before the initial
18795 * drag event begins and optionally cancel it.
18796 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18797 * @param {Event} e The event object
18798 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18800 onBeforeDrag : function(data, e){
18805 * An empty function by default, but provided so that you can perform a custom action once the initial
18806 * drag event has begun. The drag cannot be canceled from this function.
18807 * @param {Number} x The x position of the click on the dragged object
18808 * @param {Number} y The y position of the click on the dragged object
18810 onStartDrag : Roo.emptyFn,
18812 // private - YUI override
18813 startDrag : function(x, y){
18814 this.proxy.reset();
18815 this.dragging = true;
18816 this.proxy.update("");
18817 this.onInitDrag(x, y);
18822 onInitDrag : function(x, y){
18823 var clone = this.el.dom.cloneNode(true);
18824 clone.id = Roo.id(); // prevent duplicate ids
18825 this.proxy.update(clone);
18826 this.onStartDrag(x, y);
18831 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18832 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18834 getProxy : function(){
18839 * Hides the drag source's {@link Roo.dd.StatusProxy}
18841 hideProxy : function(){
18843 this.proxy.reset(true);
18844 this.dragging = false;
18848 triggerCacheRefresh : function(){
18849 Roo.dd.DDM.refreshCache(this.groups);
18852 // private - override to prevent hiding
18853 b4EndDrag: function(e) {
18856 // private - override to prevent moving
18857 endDrag : function(e){
18858 this.onEndDrag(this.dragData, e);
18862 onEndDrag : function(data, e){
18865 // private - pin to cursor
18866 autoOffset : function(x, y) {
18867 this.setDelta(-12, -20);
18871 * Ext JS Library 1.1.1
18872 * Copyright(c) 2006-2007, Ext JS, LLC.
18874 * Originally Released Under LGPL - original licence link has changed is not relivant.
18877 * <script type="text/javascript">
18882 * @class Roo.dd.DropTarget
18883 * @extends Roo.dd.DDTarget
18884 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18885 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18887 * @param {String/HTMLElement/Element} el The container element
18888 * @param {Object} config
18890 Roo.dd.DropTarget = function(el, config){
18891 this.el = Roo.get(el);
18893 var listeners = false; ;
18894 if (config && config.listeners) {
18895 listeners= config.listeners;
18896 delete config.listeners;
18898 Roo.apply(this, config);
18900 if(this.containerScroll){
18901 Roo.dd.ScrollManager.register(this.el);
18905 * @scope Roo.dd.DropTarget
18910 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18911 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18912 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18914 * IMPORTANT : it should set this.overClass and this.dropAllowed
18916 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18917 * @param {Event} e The event
18918 * @param {Object} data An object containing arbitrary data supplied by the drag source
18924 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18925 * This method will be called on every mouse movement while the drag source is over the drop target.
18926 * This default implementation simply returns the dropAllowed config value.
18928 * IMPORTANT : it should set this.dropAllowed
18930 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18931 * @param {Event} e The event
18932 * @param {Object} data An object containing arbitrary data supplied by the drag source
18938 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18939 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18940 * overClass (if any) from the drop element.
18942 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18943 * @param {Event} e The event
18944 * @param {Object} data An object containing arbitrary data supplied by the drag source
18950 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18951 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18952 * implementation that does something to process the drop event and returns true so that the drag source's
18953 * repair action does not run.
18955 * IMPORTANT : it should set this.success
18957 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18958 * @param {Event} e The event
18959 * @param {Object} data An object containing arbitrary data supplied by the drag source
18965 Roo.dd.DropTarget.superclass.constructor.call( this,
18967 this.ddGroup || this.group,
18970 listeners : listeners || {}
18978 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18980 * @cfg {String} overClass
18981 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18984 * @cfg {String} ddGroup
18985 * The drag drop group to handle drop events for
18989 * @cfg {String} dropAllowed
18990 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18992 dropAllowed : "x-dd-drop-ok",
18994 * @cfg {String} dropNotAllowed
18995 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18997 dropNotAllowed : "x-dd-drop-nodrop",
18999 * @cfg {boolean} success
19000 * set this after drop listener..
19004 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
19005 * if the drop point is valid for over/enter..
19012 isNotifyTarget : true,
19017 notifyEnter : function(dd, e, data)
19020 this.fireEvent('enter', dd, e, data);
19021 if(this.overClass){
19022 this.el.addClass(this.overClass);
19024 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19025 this.valid ? this.dropAllowed : this.dropNotAllowed
19032 notifyOver : function(dd, e, data)
19035 this.fireEvent('over', dd, e, data);
19036 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19037 this.valid ? this.dropAllowed : this.dropNotAllowed
19044 notifyOut : function(dd, e, data)
19046 this.fireEvent('out', dd, e, data);
19047 if(this.overClass){
19048 this.el.removeClass(this.overClass);
19055 notifyDrop : function(dd, e, data)
19057 this.success = false;
19058 this.fireEvent('drop', dd, e, data);
19059 return this.success;
19063 * Ext JS Library 1.1.1
19064 * Copyright(c) 2006-2007, Ext JS, LLC.
19066 * Originally Released Under LGPL - original licence link has changed is not relivant.
19069 * <script type="text/javascript">
19074 * @class Roo.dd.DragZone
19075 * @extends Roo.dd.DragSource
19076 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19077 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19079 * @param {String/HTMLElement/Element} el The container element
19080 * @param {Object} config
19082 Roo.dd.DragZone = function(el, config){
19083 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19084 if(this.containerScroll){
19085 Roo.dd.ScrollManager.register(this.el);
19089 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19091 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19092 * for auto scrolling during drag operations.
19095 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19096 * method after a failed drop (defaults to "c3daf9" - light blue)
19100 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19101 * for a valid target to drag based on the mouse down. Override this method
19102 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19103 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19104 * @param {EventObject} e The mouse down event
19105 * @return {Object} The dragData
19107 getDragData : function(e){
19108 return Roo.dd.Registry.getHandleFromEvent(e);
19112 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19113 * this.dragData.ddel
19114 * @param {Number} x The x position of the click on the dragged object
19115 * @param {Number} y The y position of the click on the dragged object
19116 * @return {Boolean} true to continue the drag, false to cancel
19118 onInitDrag : function(x, y){
19119 this.proxy.update(this.dragData.ddel.cloneNode(true));
19120 this.onStartDrag(x, y);
19125 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19127 afterRepair : function(){
19129 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19131 this.dragging = false;
19135 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19136 * the XY of this.dragData.ddel
19137 * @param {EventObject} e The mouse up event
19138 * @return {Array} The xy location (e.g. [100, 200])
19140 getRepairXY : function(e){
19141 return Roo.Element.fly(this.dragData.ddel).getXY();
19145 * Ext JS Library 1.1.1
19146 * Copyright(c) 2006-2007, Ext JS, LLC.
19148 * Originally Released Under LGPL - original licence link has changed is not relivant.
19151 * <script type="text/javascript">
19154 * @class Roo.dd.DropZone
19155 * @extends Roo.dd.DropTarget
19156 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19157 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19159 * @param {String/HTMLElement/Element} el The container element
19160 * @param {Object} config
19162 Roo.dd.DropZone = function(el, config){
19163 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19166 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19168 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19169 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19170 * provide your own custom lookup.
19171 * @param {Event} e The event
19172 * @return {Object} data The custom data
19174 getTargetFromEvent : function(e){
19175 return Roo.dd.Registry.getTargetFromEvent(e);
19179 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19180 * that it has registered. This method has no default implementation and should be overridden to provide
19181 * node-specific processing if necessary.
19182 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19183 * {@link #getTargetFromEvent} for this node)
19184 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19185 * @param {Event} e The event
19186 * @param {Object} data An object containing arbitrary data supplied by the drag source
19188 onNodeEnter : function(n, dd, e, data){
19193 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19194 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19195 * overridden to provide the proper feedback.
19196 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19197 * {@link #getTargetFromEvent} for this node)
19198 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19199 * @param {Event} e The event
19200 * @param {Object} data An object containing arbitrary data supplied by the drag source
19201 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19202 * underlying {@link Roo.dd.StatusProxy} can be updated
19204 onNodeOver : function(n, dd, e, data){
19205 return this.dropAllowed;
19209 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19210 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19211 * node-specific processing if necessary.
19212 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19213 * {@link #getTargetFromEvent} for this node)
19214 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19215 * @param {Event} e The event
19216 * @param {Object} data An object containing arbitrary data supplied by the drag source
19218 onNodeOut : function(n, dd, e, data){
19223 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19224 * the drop node. The default implementation returns false, so it should be overridden to provide the
19225 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19226 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19227 * {@link #getTargetFromEvent} for this node)
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 onNodeDrop : function(n, dd, e, data){
19238 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19239 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19240 * it should be overridden to provide the proper feedback if necessary.
19241 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19242 * @param {Event} e The event
19243 * @param {Object} data An object containing arbitrary data supplied by the drag source
19244 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19245 * underlying {@link Roo.dd.StatusProxy} can be updated
19247 onContainerOver : function(dd, e, data){
19248 return this.dropNotAllowed;
19252 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19253 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19254 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19255 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19256 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19257 * @param {Event} e The event
19258 * @param {Object} data An object containing arbitrary data supplied by the drag source
19259 * @return {Boolean} True if the drop was valid, else false
19261 onContainerDrop : function(dd, e, data){
19266 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19267 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19268 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19269 * you should override this method and provide a custom implementation.
19270 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19271 * @param {Event} e The event
19272 * @param {Object} data An object containing arbitrary data supplied by the drag source
19273 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19274 * underlying {@link Roo.dd.StatusProxy} can be updated
19276 notifyEnter : function(dd, e, data){
19277 return this.dropNotAllowed;
19281 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19282 * This method will be called on every mouse movement while the drag source is over the drop zone.
19283 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19284 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19285 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19286 * registered node, it will call {@link #onContainerOver}.
19287 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19288 * @param {Event} e The event
19289 * @param {Object} data An object containing arbitrary data supplied by the drag source
19290 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19291 * underlying {@link Roo.dd.StatusProxy} can be updated
19293 notifyOver : function(dd, e, data){
19294 var n = this.getTargetFromEvent(e);
19295 if(!n){ // not over valid drop target
19296 if(this.lastOverNode){
19297 this.onNodeOut(this.lastOverNode, dd, e, data);
19298 this.lastOverNode = null;
19300 return this.onContainerOver(dd, e, data);
19302 if(this.lastOverNode != n){
19303 if(this.lastOverNode){
19304 this.onNodeOut(this.lastOverNode, dd, e, data);
19306 this.onNodeEnter(n, dd, e, data);
19307 this.lastOverNode = n;
19309 return this.onNodeOver(n, dd, e, data);
19313 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19314 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19315 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19316 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19317 * @param {Event} e The event
19318 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19320 notifyOut : function(dd, e, data){
19321 if(this.lastOverNode){
19322 this.onNodeOut(this.lastOverNode, dd, e, data);
19323 this.lastOverNode = null;
19328 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19329 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19330 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19331 * otherwise it will call {@link #onContainerDrop}.
19332 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19333 * @param {Event} e The event
19334 * @param {Object} data An object containing arbitrary data supplied by the drag source
19335 * @return {Boolean} True if the drop was valid, else false
19337 notifyDrop : function(dd, e, data){
19338 if(this.lastOverNode){
19339 this.onNodeOut(this.lastOverNode, dd, e, data);
19340 this.lastOverNode = null;
19342 var n = this.getTargetFromEvent(e);
19344 this.onNodeDrop(n, dd, e, data) :
19345 this.onContainerDrop(dd, e, data);
19349 triggerCacheRefresh : function(){
19350 Roo.dd.DDM.refreshCache(this.groups);
19354 * Ext JS Library 1.1.1
19355 * Copyright(c) 2006-2007, Ext JS, LLC.
19357 * Originally Released Under LGPL - original licence link has changed is not relivant.
19360 * <script type="text/javascript">
19365 * @class Roo.data.SortTypes
19367 * Defines the default sorting (casting?) comparison functions used when sorting data.
19369 Roo.data.SortTypes = {
19371 * Default sort that does nothing
19372 * @param {Mixed} s The value being converted
19373 * @return {Mixed} The comparison value
19375 none : function(s){
19380 * The regular expression used to strip tags
19384 stripTagsRE : /<\/?[^>]+>/gi,
19387 * Strips all HTML tags to sort on text only
19388 * @param {Mixed} s The value being converted
19389 * @return {String} The comparison value
19391 asText : function(s){
19392 return String(s).replace(this.stripTagsRE, "");
19396 * Strips all HTML tags to sort on text only - Case insensitive
19397 * @param {Mixed} s The value being converted
19398 * @return {String} The comparison value
19400 asUCText : function(s){
19401 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19405 * Case insensitive string
19406 * @param {Mixed} s The value being converted
19407 * @return {String} The comparison value
19409 asUCString : function(s) {
19410 return String(s).toUpperCase();
19415 * @param {Mixed} s The value being converted
19416 * @return {Number} The comparison value
19418 asDate : function(s) {
19422 if(s instanceof Date){
19423 return s.getTime();
19425 return Date.parse(String(s));
19430 * @param {Mixed} s The value being converted
19431 * @return {Float} The comparison value
19433 asFloat : function(s) {
19434 var val = parseFloat(String(s).replace(/,/g, ""));
19435 if(isNaN(val)) val = 0;
19441 * @param {Mixed} s The value being converted
19442 * @return {Number} The comparison value
19444 asInt : function(s) {
19445 var val = parseInt(String(s).replace(/,/g, ""));
19446 if(isNaN(val)) val = 0;
19451 * Ext JS Library 1.1.1
19452 * Copyright(c) 2006-2007, Ext JS, LLC.
19454 * Originally Released Under LGPL - original licence link has changed is not relivant.
19457 * <script type="text/javascript">
19461 * @class Roo.data.Record
19462 * Instances of this class encapsulate both record <em>definition</em> information, and record
19463 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19464 * to access Records cached in an {@link Roo.data.Store} object.<br>
19466 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19467 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19470 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19472 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19473 * {@link #create}. The parameters are the same.
19474 * @param {Array} data An associative Array of data values keyed by the field name.
19475 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19476 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19477 * not specified an integer id is generated.
19479 Roo.data.Record = function(data, id){
19480 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19485 * Generate a constructor for a specific record layout.
19486 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19487 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19488 * Each field definition object may contain the following properties: <ul>
19489 * <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,
19490 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19491 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19492 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19493 * is being used, then this is a string containing the javascript expression to reference the data relative to
19494 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19495 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19496 * this may be omitted.</p></li>
19497 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19498 * <ul><li>auto (Default, implies no conversion)</li>
19503 * <li>date</li></ul></p></li>
19504 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19505 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19506 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19507 * by the Reader into an object that will be stored in the Record. It is passed the
19508 * following parameters:<ul>
19509 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19511 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19513 * <br>usage:<br><pre><code>
19514 var TopicRecord = Roo.data.Record.create(
19515 {name: 'title', mapping: 'topic_title'},
19516 {name: 'author', mapping: 'username'},
19517 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19518 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19519 {name: 'lastPoster', mapping: 'user2'},
19520 {name: 'excerpt', mapping: 'post_text'}
19523 var myNewRecord = new TopicRecord({
19524 title: 'Do my job please',
19527 lastPost: new Date(),
19528 lastPoster: 'Animal',
19529 excerpt: 'No way dude!'
19531 myStore.add(myNewRecord);
19536 Roo.data.Record.create = function(o){
19537 var f = function(){
19538 f.superclass.constructor.apply(this, arguments);
19540 Roo.extend(f, Roo.data.Record);
19541 var p = f.prototype;
19542 p.fields = new Roo.util.MixedCollection(false, function(field){
19545 for(var i = 0, len = o.length; i < len; i++){
19546 p.fields.add(new Roo.data.Field(o[i]));
19548 f.getField = function(name){
19549 return p.fields.get(name);
19554 Roo.data.Record.AUTO_ID = 1000;
19555 Roo.data.Record.EDIT = 'edit';
19556 Roo.data.Record.REJECT = 'reject';
19557 Roo.data.Record.COMMIT = 'commit';
19559 Roo.data.Record.prototype = {
19561 * Readonly flag - true if this record has been modified.
19570 join : function(store){
19571 this.store = store;
19575 * Set the named field to the specified value.
19576 * @param {String} name The name of the field to set.
19577 * @param {Object} value The value to set the field to.
19579 set : function(name, value){
19580 if(this.data[name] == value){
19584 if(!this.modified){
19585 this.modified = {};
19587 if(typeof this.modified[name] == 'undefined'){
19588 this.modified[name] = this.data[name];
19590 this.data[name] = value;
19591 if(!this.editing && this.store){
19592 this.store.afterEdit(this);
19597 * Get the value of the named field.
19598 * @param {String} name The name of the field to get the value of.
19599 * @return {Object} The value of the field.
19601 get : function(name){
19602 return this.data[name];
19606 beginEdit : function(){
19607 this.editing = true;
19608 this.modified = {};
19612 cancelEdit : function(){
19613 this.editing = false;
19614 delete this.modified;
19618 endEdit : function(){
19619 this.editing = false;
19620 if(this.dirty && this.store){
19621 this.store.afterEdit(this);
19626 * Usually called by the {@link Roo.data.Store} which owns the Record.
19627 * Rejects all changes made to the Record since either creation, or the last commit operation.
19628 * Modified fields are reverted to their original values.
19630 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19631 * of reject operations.
19633 reject : function(){
19634 var m = this.modified;
19636 if(typeof m[n] != "function"){
19637 this.data[n] = m[n];
19640 this.dirty = false;
19641 delete this.modified;
19642 this.editing = false;
19644 this.store.afterReject(this);
19649 * Usually called by the {@link Roo.data.Store} which owns the Record.
19650 * Commits all changes made to the Record since either creation, or the last commit operation.
19652 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19653 * of commit operations.
19655 commit : function(){
19656 this.dirty = false;
19657 delete this.modified;
19658 this.editing = false;
19660 this.store.afterCommit(this);
19665 hasError : function(){
19666 return this.error != null;
19670 clearError : function(){
19675 * Creates a copy of this record.
19676 * @param {String} id (optional) A new record id if you don't want to use this record's id
19679 copy : function(newId) {
19680 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19684 * Ext JS Library 1.1.1
19685 * Copyright(c) 2006-2007, Ext JS, LLC.
19687 * Originally Released Under LGPL - original licence link has changed is not relivant.
19690 * <script type="text/javascript">
19696 * @class Roo.data.Store
19697 * @extends Roo.util.Observable
19698 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19699 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19701 * 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
19702 * has no knowledge of the format of the data returned by the Proxy.<br>
19704 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19705 * instances from the data object. These records are cached and made available through accessor functions.
19707 * Creates a new Store.
19708 * @param {Object} config A config object containing the objects needed for the Store to access data,
19709 * and read the data into Records.
19711 Roo.data.Store = function(config){
19712 this.data = new Roo.util.MixedCollection(false);
19713 this.data.getKey = function(o){
19716 this.baseParams = {};
19718 this.paramNames = {
19723 "multisort" : "_multisort"
19726 if(config && config.data){
19727 this.inlineData = config.data;
19728 delete config.data;
19731 Roo.apply(this, config);
19733 if(this.reader){ // reader passed
19734 this.reader = Roo.factory(this.reader, Roo.data);
19735 this.reader.xmodule = this.xmodule || false;
19736 if(!this.recordType){
19737 this.recordType = this.reader.recordType;
19739 if(this.reader.onMetaChange){
19740 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19744 if(this.recordType){
19745 this.fields = this.recordType.prototype.fields;
19747 this.modified = [];
19751 * @event datachanged
19752 * Fires when the data cache has changed, and a widget which is using this Store
19753 * as a Record cache should refresh its view.
19754 * @param {Store} this
19756 datachanged : true,
19758 * @event metachange
19759 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19760 * @param {Store} this
19761 * @param {Object} meta The JSON metadata
19766 * Fires when Records have been added to the Store
19767 * @param {Store} this
19768 * @param {Roo.data.Record[]} records The array of Records added
19769 * @param {Number} index The index at which the record(s) were added
19774 * Fires when a Record has been removed from the Store
19775 * @param {Store} this
19776 * @param {Roo.data.Record} record The Record that was removed
19777 * @param {Number} index The index at which the record was removed
19782 * Fires when a Record has been updated
19783 * @param {Store} this
19784 * @param {Roo.data.Record} record The Record that was updated
19785 * @param {String} operation The update operation being performed. Value may be one of:
19787 Roo.data.Record.EDIT
19788 Roo.data.Record.REJECT
19789 Roo.data.Record.COMMIT
19795 * Fires when the data cache has been cleared.
19796 * @param {Store} this
19800 * @event beforeload
19801 * Fires before a request is made for a new data object. If the beforeload handler returns false
19802 * the load action will be canceled.
19803 * @param {Store} this
19804 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19809 * Fires after a new set of Records has been loaded.
19810 * @param {Store} this
19811 * @param {Roo.data.Record[]} records The Records that were loaded
19812 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19816 * @event loadexception
19817 * Fires if an exception occurs in the Proxy during loading.
19818 * Called with the signature of the Proxy's "loadexception" event.
19819 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19822 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19823 * @param {Object} load options
19824 * @param {Object} jsonData from your request (normally this contains the Exception)
19826 loadexception : true
19830 this.proxy = Roo.factory(this.proxy, Roo.data);
19831 this.proxy.xmodule = this.xmodule || false;
19832 this.relayEvents(this.proxy, ["loadexception"]);
19834 this.sortToggle = {};
19835 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19837 Roo.data.Store.superclass.constructor.call(this);
19839 if(this.inlineData){
19840 this.loadData(this.inlineData);
19841 delete this.inlineData;
19844 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19846 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19847 * without a remote query - used by combo/forms at present.
19851 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19854 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19857 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19858 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19861 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19862 * on any HTTP request
19865 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19868 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19872 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19873 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19875 remoteSort : false,
19878 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19879 * loaded or when a record is removed. (defaults to false).
19881 pruneModifiedRecords : false,
19884 lastOptions : null,
19887 * Add Records to the Store and fires the add event.
19888 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19890 add : function(records){
19891 records = [].concat(records);
19892 for(var i = 0, len = records.length; i < len; i++){
19893 records[i].join(this);
19895 var index = this.data.length;
19896 this.data.addAll(records);
19897 this.fireEvent("add", this, records, index);
19901 * Remove a Record from the Store and fires the remove event.
19902 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19904 remove : function(record){
19905 var index = this.data.indexOf(record);
19906 this.data.removeAt(index);
19907 if(this.pruneModifiedRecords){
19908 this.modified.remove(record);
19910 this.fireEvent("remove", this, record, index);
19914 * Remove all Records from the Store and fires the clear event.
19916 removeAll : function(){
19918 if(this.pruneModifiedRecords){
19919 this.modified = [];
19921 this.fireEvent("clear", this);
19925 * Inserts Records to the Store at the given index and fires the add event.
19926 * @param {Number} index The start index at which to insert the passed Records.
19927 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19929 insert : function(index, records){
19930 records = [].concat(records);
19931 for(var i = 0, len = records.length; i < len; i++){
19932 this.data.insert(index, records[i]);
19933 records[i].join(this);
19935 this.fireEvent("add", this, records, index);
19939 * Get the index within the cache of the passed Record.
19940 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19941 * @return {Number} The index of the passed Record. Returns -1 if not found.
19943 indexOf : function(record){
19944 return this.data.indexOf(record);
19948 * Get the index within the cache of the Record with the passed id.
19949 * @param {String} id The id of the Record to find.
19950 * @return {Number} The index of the Record. Returns -1 if not found.
19952 indexOfId : function(id){
19953 return this.data.indexOfKey(id);
19957 * Get the Record with the specified id.
19958 * @param {String} id The id of the Record to find.
19959 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19961 getById : function(id){
19962 return this.data.key(id);
19966 * Get the Record at the specified index.
19967 * @param {Number} index The index of the Record to find.
19968 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19970 getAt : function(index){
19971 return this.data.itemAt(index);
19975 * Returns a range of Records between specified indices.
19976 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19977 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19978 * @return {Roo.data.Record[]} An array of Records
19980 getRange : function(start, end){
19981 return this.data.getRange(start, end);
19985 storeOptions : function(o){
19986 o = Roo.apply({}, o);
19989 this.lastOptions = o;
19993 * Loads the Record cache from the configured Proxy using the configured Reader.
19995 * If using remote paging, then the first load call must specify the <em>start</em>
19996 * and <em>limit</em> properties in the options.params property to establish the initial
19997 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19999 * <strong>It is important to note that for remote data sources, loading is asynchronous,
20000 * and this call will return before the new data has been loaded. Perform any post-processing
20001 * in a callback function, or in a "load" event handler.</strong>
20003 * @param {Object} options An object containing properties which control loading options:<ul>
20004 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
20005 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
20006 * passed the following arguments:<ul>
20007 * <li>r : Roo.data.Record[]</li>
20008 * <li>options: Options object from the load call</li>
20009 * <li>success: Boolean success indicator</li></ul></li>
20010 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
20011 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
20014 load : function(options){
20015 options = options || {};
20016 if(this.fireEvent("beforeload", this, options) !== false){
20017 this.storeOptions(options);
20018 var p = Roo.apply(options.params || {}, this.baseParams);
20019 // if meta was not loaded from remote source.. try requesting it.
20020 if (!this.reader.metaFromRemote) {
20021 p._requestMeta = 1;
20023 if(this.sortInfo && this.remoteSort){
20024 var pn = this.paramNames;
20025 p[pn["sort"]] = this.sortInfo.field;
20026 p[pn["dir"]] = this.sortInfo.direction;
20028 if (this.multiSort) {
20029 var pn = this.paramNames;
20030 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
20033 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20038 * Reloads the Record cache from the configured Proxy using the configured Reader and
20039 * the options from the last load operation performed.
20040 * @param {Object} options (optional) An object containing properties which may override the options
20041 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20042 * the most recently used options are reused).
20044 reload : function(options){
20045 this.load(Roo.applyIf(options||{}, this.lastOptions));
20049 // Called as a callback by the Reader during a load operation.
20050 loadRecords : function(o, options, success){
20051 if(!o || success === false){
20052 if(success !== false){
20053 this.fireEvent("load", this, [], options);
20055 if(options.callback){
20056 options.callback.call(options.scope || this, [], options, false);
20060 // if data returned failure - throw an exception.
20061 if (o.success === false) {
20062 // show a message if no listener is registered.
20063 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
20064 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
20066 // loadmask wil be hooked into this..
20067 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
20070 var r = o.records, t = o.totalRecords || r.length;
20071 if(!options || options.add !== true){
20072 if(this.pruneModifiedRecords){
20073 this.modified = [];
20075 for(var i = 0, len = r.length; i < len; i++){
20079 this.data = this.snapshot;
20080 delete this.snapshot;
20083 this.data.addAll(r);
20084 this.totalLength = t;
20086 this.fireEvent("datachanged", this);
20088 this.totalLength = Math.max(t, this.data.length+r.length);
20091 this.fireEvent("load", this, r, options);
20092 if(options.callback){
20093 options.callback.call(options.scope || this, r, options, true);
20099 * Loads data from a passed data block. A Reader which understands the format of the data
20100 * must have been configured in the constructor.
20101 * @param {Object} data The data block from which to read the Records. The format of the data expected
20102 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20103 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20105 loadData : function(o, append){
20106 var r = this.reader.readRecords(o);
20107 this.loadRecords(r, {add: append}, true);
20111 * Gets the number of cached records.
20113 * <em>If using paging, this may not be the total size of the dataset. If the data object
20114 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20115 * the data set size</em>
20117 getCount : function(){
20118 return this.data.length || 0;
20122 * Gets the total number of records in the dataset as returned by the server.
20124 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20125 * the dataset size</em>
20127 getTotalCount : function(){
20128 return this.totalLength || 0;
20132 * Returns the sort state of the Store as an object with two properties:
20134 field {String} The name of the field by which the Records are sorted
20135 direction {String} The sort order, "ASC" or "DESC"
20138 getSortState : function(){
20139 return this.sortInfo;
20143 applySort : function(){
20144 if(this.sortInfo && !this.remoteSort){
20145 var s = this.sortInfo, f = s.field;
20146 var st = this.fields.get(f).sortType;
20147 var fn = function(r1, r2){
20148 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20149 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20151 this.data.sort(s.direction, fn);
20152 if(this.snapshot && this.snapshot != this.data){
20153 this.snapshot.sort(s.direction, fn);
20159 * Sets the default sort column and order to be used by the next load operation.
20160 * @param {String} fieldName The name of the field to sort by.
20161 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20163 setDefaultSort : function(field, dir){
20164 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20168 * Sort the Records.
20169 * If remote sorting is used, the sort is performed on the server, and the cache is
20170 * reloaded. If local sorting is used, the cache is sorted internally.
20171 * @param {String} fieldName The name of the field to sort by.
20172 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20174 sort : function(fieldName, dir){
20175 var f = this.fields.get(fieldName);
20177 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20179 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20180 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20185 this.sortToggle[f.name] = dir;
20186 this.sortInfo = {field: f.name, direction: dir};
20187 if(!this.remoteSort){
20189 this.fireEvent("datachanged", this);
20191 this.load(this.lastOptions);
20196 * Calls the specified function for each of the Records in the cache.
20197 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20198 * Returning <em>false</em> aborts and exits the iteration.
20199 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20201 each : function(fn, scope){
20202 this.data.each(fn, scope);
20206 * Gets all records modified since the last commit. Modified records are persisted across load operations
20207 * (e.g., during paging).
20208 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20210 getModifiedRecords : function(){
20211 return this.modified;
20215 createFilterFn : function(property, value, anyMatch){
20216 if(!value.exec){ // not a regex
20217 value = String(value);
20218 if(value.length == 0){
20221 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20223 return function(r){
20224 return value.test(r.data[property]);
20229 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20230 * @param {String} property A field on your records
20231 * @param {Number} start The record index to start at (defaults to 0)
20232 * @param {Number} end The last record index to include (defaults to length - 1)
20233 * @return {Number} The sum
20235 sum : function(property, start, end){
20236 var rs = this.data.items, v = 0;
20237 start = start || 0;
20238 end = (end || end === 0) ? end : rs.length-1;
20240 for(var i = start; i <= end; i++){
20241 v += (rs[i].data[property] || 0);
20247 * Filter the records by a specified property.
20248 * @param {String} field A field on your records
20249 * @param {String/RegExp} value Either a string that the field
20250 * should start with or a RegExp to test against the field
20251 * @param {Boolean} anyMatch True to match any part not just the beginning
20253 filter : function(property, value, anyMatch){
20254 var fn = this.createFilterFn(property, value, anyMatch);
20255 return fn ? this.filterBy(fn) : this.clearFilter();
20259 * Filter by a function. The specified function will be called with each
20260 * record in this data source. If the function returns true the record is included,
20261 * otherwise it is filtered.
20262 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20263 * @param {Object} scope (optional) The scope of the function (defaults to this)
20265 filterBy : function(fn, scope){
20266 this.snapshot = this.snapshot || this.data;
20267 this.data = this.queryBy(fn, scope||this);
20268 this.fireEvent("datachanged", this);
20272 * Query the records by a specified property.
20273 * @param {String} field A field on your records
20274 * @param {String/RegExp} value Either a string that the field
20275 * should start with or a RegExp to test against the field
20276 * @param {Boolean} anyMatch True to match any part not just the beginning
20277 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20279 query : function(property, value, anyMatch){
20280 var fn = this.createFilterFn(property, value, anyMatch);
20281 return fn ? this.queryBy(fn) : this.data.clone();
20285 * Query by a function. The specified function will be called with each
20286 * record in this data source. If the function returns true the record is included
20288 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20289 * @param {Object} scope (optional) The scope of the function (defaults to this)
20290 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20292 queryBy : function(fn, scope){
20293 var data = this.snapshot || this.data;
20294 return data.filterBy(fn, scope||this);
20298 * Collects unique values for a particular dataIndex from this store.
20299 * @param {String} dataIndex The property to collect
20300 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20301 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20302 * @return {Array} An array of the unique values
20304 collect : function(dataIndex, allowNull, bypassFilter){
20305 var d = (bypassFilter === true && this.snapshot) ?
20306 this.snapshot.items : this.data.items;
20307 var v, sv, r = [], l = {};
20308 for(var i = 0, len = d.length; i < len; i++){
20309 v = d[i].data[dataIndex];
20311 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20320 * Revert to a view of the Record cache with no filtering applied.
20321 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20323 clearFilter : function(suppressEvent){
20324 if(this.snapshot && this.snapshot != this.data){
20325 this.data = this.snapshot;
20326 delete this.snapshot;
20327 if(suppressEvent !== true){
20328 this.fireEvent("datachanged", this);
20334 afterEdit : function(record){
20335 if(this.modified.indexOf(record) == -1){
20336 this.modified.push(record);
20338 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20342 afterReject : function(record){
20343 this.modified.remove(record);
20344 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20348 afterCommit : function(record){
20349 this.modified.remove(record);
20350 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20354 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20355 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20357 commitChanges : function(){
20358 var m = this.modified.slice(0);
20359 this.modified = [];
20360 for(var i = 0, len = m.length; i < len; i++){
20366 * Cancel outstanding changes on all changed records.
20368 rejectChanges : function(){
20369 var m = this.modified.slice(0);
20370 this.modified = [];
20371 for(var i = 0, len = m.length; i < len; i++){
20376 onMetaChange : function(meta, rtype, o){
20377 this.recordType = rtype;
20378 this.fields = rtype.prototype.fields;
20379 delete this.snapshot;
20380 this.sortInfo = meta.sortInfo || this.sortInfo;
20381 this.modified = [];
20382 this.fireEvent('metachange', this, this.reader.meta);
20386 * Ext JS Library 1.1.1
20387 * Copyright(c) 2006-2007, Ext JS, LLC.
20389 * Originally Released Under LGPL - original licence link has changed is not relivant.
20392 * <script type="text/javascript">
20396 * @class Roo.data.SimpleStore
20397 * @extends Roo.data.Store
20398 * Small helper class to make creating Stores from Array data easier.
20399 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20400 * @cfg {Array} fields An array of field definition objects, or field name strings.
20401 * @cfg {Array} data The multi-dimensional array of data
20403 * @param {Object} config
20405 Roo.data.SimpleStore = function(config){
20406 Roo.data.SimpleStore.superclass.constructor.call(this, {
20408 reader: new Roo.data.ArrayReader({
20411 Roo.data.Record.create(config.fields)
20413 proxy : new Roo.data.MemoryProxy(config.data)
20417 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
20419 * Ext JS Library 1.1.1
20420 * Copyright(c) 2006-2007, Ext JS, LLC.
20422 * Originally Released Under LGPL - original licence link has changed is not relivant.
20425 * <script type="text/javascript">
20430 * @extends Roo.data.Store
20431 * @class Roo.data.JsonStore
20432 * Small helper class to make creating Stores for JSON data easier. <br/>
20434 var store = new Roo.data.JsonStore({
20435 url: 'get-images.php',
20437 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20440 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20441 * JsonReader and HttpProxy (unless inline data is provided).</b>
20442 * @cfg {Array} fields An array of field definition objects, or field name strings.
20444 * @param {Object} config
20446 Roo.data.JsonStore = function(c){
20447 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20448 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20449 reader: new Roo.data.JsonReader(c, c.fields)
20452 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20454 * Ext JS Library 1.1.1
20455 * Copyright(c) 2006-2007, Ext JS, LLC.
20457 * Originally Released Under LGPL - original licence link has changed is not relivant.
20460 * <script type="text/javascript">
20464 Roo.data.Field = function(config){
20465 if(typeof config == "string"){
20466 config = {name: config};
20468 Roo.apply(this, config);
20471 this.type = "auto";
20474 var st = Roo.data.SortTypes;
20475 // named sortTypes are supported, here we look them up
20476 if(typeof this.sortType == "string"){
20477 this.sortType = st[this.sortType];
20480 // set default sortType for strings and dates
20481 if(!this.sortType){
20484 this.sortType = st.asUCString;
20487 this.sortType = st.asDate;
20490 this.sortType = st.none;
20495 var stripRe = /[\$,%]/g;
20497 // prebuilt conversion function for this field, instead of
20498 // switching every time we're reading a value
20500 var cv, dateFormat = this.dateFormat;
20505 cv = function(v){ return v; };
20508 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20512 return v !== undefined && v !== null && v !== '' ?
20513 parseInt(String(v).replace(stripRe, ""), 10) : '';
20518 return v !== undefined && v !== null && v !== '' ?
20519 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20524 cv = function(v){ return v === true || v === "true" || v == 1; };
20531 if(v instanceof Date){
20535 if(dateFormat == "timestamp"){
20536 return new Date(v*1000);
20538 return Date.parseDate(v, dateFormat);
20540 var parsed = Date.parse(v);
20541 return parsed ? new Date(parsed) : null;
20550 Roo.data.Field.prototype = {
20558 * Ext JS Library 1.1.1
20559 * Copyright(c) 2006-2007, Ext JS, LLC.
20561 * Originally Released Under LGPL - original licence link has changed is not relivant.
20564 * <script type="text/javascript">
20567 // Base class for reading structured data from a data source. This class is intended to be
20568 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20571 * @class Roo.data.DataReader
20572 * Base class for reading structured data from a data source. This class is intended to be
20573 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20576 Roo.data.DataReader = function(meta, recordType){
20580 this.recordType = recordType instanceof Array ?
20581 Roo.data.Record.create(recordType) : recordType;
20584 Roo.data.DataReader.prototype = {
20586 * Create an empty record
20587 * @param {Object} data (optional) - overlay some values
20588 * @return {Roo.data.Record} record created.
20590 newRow : function(d) {
20592 this.recordType.prototype.fields.each(function(c) {
20594 case 'int' : da[c.name] = 0; break;
20595 case 'date' : da[c.name] = new Date(); break;
20596 case 'float' : da[c.name] = 0.0; break;
20597 case 'boolean' : da[c.name] = false; break;
20598 default : da[c.name] = ""; break;
20602 return new this.recordType(Roo.apply(da, d));
20607 * Ext JS Library 1.1.1
20608 * Copyright(c) 2006-2007, Ext JS, LLC.
20610 * Originally Released Under LGPL - original licence link has changed is not relivant.
20613 * <script type="text/javascript">
20617 * @class Roo.data.DataProxy
20618 * @extends Roo.data.Observable
20619 * This class is an abstract base class for implementations which provide retrieval of
20620 * unformatted data objects.<br>
20622 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20623 * (of the appropriate type which knows how to parse the data object) to provide a block of
20624 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20626 * Custom implementations must implement the load method as described in
20627 * {@link Roo.data.HttpProxy#load}.
20629 Roo.data.DataProxy = function(){
20632 * @event beforeload
20633 * Fires before a network request is made to retrieve a data object.
20634 * @param {Object} This DataProxy object.
20635 * @param {Object} params The params parameter to the load function.
20640 * Fires before the load method's callback is called.
20641 * @param {Object} This DataProxy object.
20642 * @param {Object} o The data object.
20643 * @param {Object} arg The callback argument object passed to the load function.
20647 * @event loadexception
20648 * Fires if an Exception occurs during data retrieval.
20649 * @param {Object} This DataProxy object.
20650 * @param {Object} o The data object.
20651 * @param {Object} arg The callback argument object passed to the load function.
20652 * @param {Object} e The Exception.
20654 loadexception : true
20656 Roo.data.DataProxy.superclass.constructor.call(this);
20659 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20662 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20666 * Ext JS Library 1.1.1
20667 * Copyright(c) 2006-2007, Ext JS, LLC.
20669 * Originally Released Under LGPL - original licence link has changed is not relivant.
20672 * <script type="text/javascript">
20675 * @class Roo.data.MemoryProxy
20676 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20677 * to the Reader when its load method is called.
20679 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20681 Roo.data.MemoryProxy = function(data){
20685 Roo.data.MemoryProxy.superclass.constructor.call(this);
20689 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20691 * Load data from the requested source (in this case an in-memory
20692 * data object passed to the constructor), read the data object into
20693 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20694 * process that block using the passed callback.
20695 * @param {Object} params This parameter is not used by the MemoryProxy class.
20696 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20697 * object into a block of Roo.data.Records.
20698 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20699 * The function must be passed <ul>
20700 * <li>The Record block object</li>
20701 * <li>The "arg" argument from the load function</li>
20702 * <li>A boolean success indicator</li>
20704 * @param {Object} scope The scope in which to call the callback
20705 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20707 load : function(params, reader, callback, scope, arg){
20708 params = params || {};
20711 result = reader.readRecords(this.data);
20713 this.fireEvent("loadexception", this, arg, null, e);
20714 callback.call(scope, null, arg, false);
20717 callback.call(scope, result, arg, true);
20721 update : function(params, records){
20726 * Ext JS Library 1.1.1
20727 * Copyright(c) 2006-2007, Ext JS, LLC.
20729 * Originally Released Under LGPL - original licence link has changed is not relivant.
20732 * <script type="text/javascript">
20735 * @class Roo.data.HttpProxy
20736 * @extends Roo.data.DataProxy
20737 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20738 * configured to reference a certain URL.<br><br>
20740 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20741 * from which the running page was served.<br><br>
20743 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20745 * Be aware that to enable the browser to parse an XML document, the server must set
20746 * the Content-Type header in the HTTP response to "text/xml".
20748 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20749 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20750 * will be used to make the request.
20752 Roo.data.HttpProxy = function(conn){
20753 Roo.data.HttpProxy.superclass.constructor.call(this);
20754 // is conn a conn config or a real conn?
20756 this.useAjax = !conn || !conn.events;
20760 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20761 // thse are take from connection...
20764 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20767 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20768 * extra parameters to each request made by this object. (defaults to undefined)
20771 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20772 * to each request made by this object. (defaults to undefined)
20775 * @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)
20778 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20781 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20787 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20791 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20792 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20793 * a finer-grained basis than the DataProxy events.
20795 getConnection : function(){
20796 return this.useAjax ? Roo.Ajax : this.conn;
20800 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20801 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20802 * process that block using the passed callback.
20803 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20804 * for the request to the remote server.
20805 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20806 * object into a block of Roo.data.Records.
20807 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20808 * The function must be passed <ul>
20809 * <li>The Record block object</li>
20810 * <li>The "arg" argument from the load function</li>
20811 * <li>A boolean success indicator</li>
20813 * @param {Object} scope The scope in which to call the callback
20814 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20816 load : function(params, reader, callback, scope, arg){
20817 if(this.fireEvent("beforeload", this, params) !== false){
20819 params : params || {},
20821 callback : callback,
20826 callback : this.loadResponse,
20830 Roo.applyIf(o, this.conn);
20831 if(this.activeRequest){
20832 Roo.Ajax.abort(this.activeRequest);
20834 this.activeRequest = Roo.Ajax.request(o);
20836 this.conn.request(o);
20839 callback.call(scope||this, null, arg, false);
20844 loadResponse : function(o, success, response){
20845 delete this.activeRequest;
20847 this.fireEvent("loadexception", this, o, response);
20848 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20853 result = o.reader.read(response);
20855 this.fireEvent("loadexception", this, o, response, e);
20856 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20860 this.fireEvent("load", this, o, o.request.arg);
20861 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20865 update : function(dataSet){
20870 updateResponse : function(dataSet){
20875 * Ext JS Library 1.1.1
20876 * Copyright(c) 2006-2007, Ext JS, LLC.
20878 * Originally Released Under LGPL - original licence link has changed is not relivant.
20881 * <script type="text/javascript">
20885 * @class Roo.data.ScriptTagProxy
20886 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20887 * other than the originating domain of the running page.<br><br>
20889 * <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
20890 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20892 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20893 * source code that is used as the source inside a <script> tag.<br><br>
20895 * In order for the browser to process the returned data, the server must wrap the data object
20896 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20897 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20898 * depending on whether the callback name was passed:
20901 boolean scriptTag = false;
20902 String cb = request.getParameter("callback");
20905 response.setContentType("text/javascript");
20907 response.setContentType("application/x-json");
20909 Writer out = response.getWriter();
20911 out.write(cb + "(");
20913 out.print(dataBlock.toJsonString());
20920 * @param {Object} config A configuration object.
20922 Roo.data.ScriptTagProxy = function(config){
20923 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20924 Roo.apply(this, config);
20925 this.head = document.getElementsByTagName("head")[0];
20928 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20930 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20932 * @cfg {String} url The URL from which to request the data object.
20935 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20939 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20940 * the server the name of the callback function set up by the load call to process the returned data object.
20941 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20942 * javascript output which calls this named function passing the data object as its only parameter.
20944 callbackParam : "callback",
20946 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20947 * name to the request.
20952 * Load data from the configured URL, read the data object into
20953 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20954 * process that block using the passed callback.
20955 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20956 * for the request to the remote server.
20957 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20958 * object into a block of Roo.data.Records.
20959 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20960 * The function must be passed <ul>
20961 * <li>The Record block object</li>
20962 * <li>The "arg" argument from the load function</li>
20963 * <li>A boolean success indicator</li>
20965 * @param {Object} scope The scope in which to call the callback
20966 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20968 load : function(params, reader, callback, scope, arg){
20969 if(this.fireEvent("beforeload", this, params) !== false){
20971 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20973 var url = this.url;
20974 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20976 url += "&_dc=" + (new Date().getTime());
20978 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20981 cb : "stcCallback"+transId,
20982 scriptId : "stcScript"+transId,
20986 callback : callback,
20992 window[trans.cb] = function(o){
20993 conn.handleResponse(o, trans);
20996 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20998 if(this.autoAbort !== false){
21002 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
21004 var script = document.createElement("script");
21005 script.setAttribute("src", url);
21006 script.setAttribute("type", "text/javascript");
21007 script.setAttribute("id", trans.scriptId);
21008 this.head.appendChild(script);
21010 this.trans = trans;
21012 callback.call(scope||this, null, arg, false);
21017 isLoading : function(){
21018 return this.trans ? true : false;
21022 * Abort the current server request.
21024 abort : function(){
21025 if(this.isLoading()){
21026 this.destroyTrans(this.trans);
21031 destroyTrans : function(trans, isLoaded){
21032 this.head.removeChild(document.getElementById(trans.scriptId));
21033 clearTimeout(trans.timeoutId);
21035 window[trans.cb] = undefined;
21037 delete window[trans.cb];
21040 // if hasn't been loaded, wait for load to remove it to prevent script error
21041 window[trans.cb] = function(){
21042 window[trans.cb] = undefined;
21044 delete window[trans.cb];
21051 handleResponse : function(o, trans){
21052 this.trans = false;
21053 this.destroyTrans(trans, true);
21056 result = trans.reader.readRecords(o);
21058 this.fireEvent("loadexception", this, o, trans.arg, e);
21059 trans.callback.call(trans.scope||window, null, trans.arg, false);
21062 this.fireEvent("load", this, o, trans.arg);
21063 trans.callback.call(trans.scope||window, result, trans.arg, true);
21067 handleFailure : function(trans){
21068 this.trans = false;
21069 this.destroyTrans(trans, false);
21070 this.fireEvent("loadexception", this, null, trans.arg);
21071 trans.callback.call(trans.scope||window, null, trans.arg, false);
21075 * Ext JS Library 1.1.1
21076 * Copyright(c) 2006-2007, Ext JS, LLC.
21078 * Originally Released Under LGPL - original licence link has changed is not relivant.
21081 * <script type="text/javascript">
21085 * @class Roo.data.JsonReader
21086 * @extends Roo.data.DataReader
21087 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21088 * based on mappings in a provided Roo.data.Record constructor.
21090 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21091 * in the reply previously.
21096 var RecordDef = Roo.data.Record.create([
21097 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21098 {name: 'occupation'} // This field will use "occupation" as the mapping.
21100 var myReader = new Roo.data.JsonReader({
21101 totalProperty: "results", // The property which contains the total dataset size (optional)
21102 root: "rows", // The property which contains an Array of row objects
21103 id: "id" // The property within each row object that provides an ID for the record (optional)
21107 * This would consume a JSON file like this:
21109 { 'results': 2, 'rows': [
21110 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21111 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21114 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21115 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21116 * paged from the remote server.
21117 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21118 * @cfg {String} root name of the property which contains the Array of row objects.
21119 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21121 * Create a new JsonReader
21122 * @param {Object} meta Metadata configuration options
21123 * @param {Object} recordType Either an Array of field definition objects,
21124 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21126 Roo.data.JsonReader = function(meta, recordType){
21129 // set some defaults:
21130 Roo.applyIf(meta, {
21131 totalProperty: 'total',
21132 successProperty : 'success',
21137 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21139 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21142 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21143 * Used by Store query builder to append _requestMeta to params.
21146 metaFromRemote : false,
21148 * This method is only used by a DataProxy which has retrieved data from a remote server.
21149 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21150 * @return {Object} data A data block which is used by an Roo.data.Store object as
21151 * a cache of Roo.data.Records.
21153 read : function(response){
21154 var json = response.responseText;
21156 var o = /* eval:var:o */ eval("("+json+")");
21158 throw {message: "JsonReader.read: Json object not found"};
21164 this.metaFromRemote = true;
21165 this.meta = o.metaData;
21166 this.recordType = Roo.data.Record.create(o.metaData.fields);
21167 this.onMetaChange(this.meta, this.recordType, o);
21169 return this.readRecords(o);
21172 // private function a store will implement
21173 onMetaChange : function(meta, recordType, o){
21180 simpleAccess: function(obj, subsc) {
21187 getJsonAccessor: function(){
21189 return function(expr) {
21191 return(re.test(expr))
21192 ? new Function("obj", "return obj." + expr)
21197 return Roo.emptyFn;
21202 * Create a data block containing Roo.data.Records from an XML document.
21203 * @param {Object} o An object which contains an Array of row objects in the property specified
21204 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21205 * which contains the total size of the dataset.
21206 * @return {Object} data A data block which is used by an Roo.data.Store object as
21207 * a cache of Roo.data.Records.
21209 readRecords : function(o){
21211 * After any data loads, the raw JSON data is available for further custom processing.
21215 var s = this.meta, Record = this.recordType,
21216 f = Record.prototype.fields, fi = f.items, fl = f.length;
21218 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21220 if(s.totalProperty) {
21221 this.getTotal = this.getJsonAccessor(s.totalProperty);
21223 if(s.successProperty) {
21224 this.getSuccess = this.getJsonAccessor(s.successProperty);
21226 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21228 var g = this.getJsonAccessor(s.id);
21229 this.getId = function(rec) {
21231 return (r === undefined || r === "") ? null : r;
21234 this.getId = function(){return null;};
21237 for(var jj = 0; jj < fl; jj++){
21239 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21240 this.ef[jj] = this.getJsonAccessor(map);
21244 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21245 if(s.totalProperty){
21246 var vt = parseInt(this.getTotal(o), 10);
21251 if(s.successProperty){
21252 var vs = this.getSuccess(o);
21253 if(vs === false || vs === 'false'){
21258 for(var i = 0; i < c; i++){
21261 var id = this.getId(n);
21262 for(var j = 0; j < fl; j++){
21264 var v = this.ef[j](n);
21266 Roo.log('missing convert for ' + f.name);
21270 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21272 var record = new Record(values, id);
21274 records[i] = record;
21279 totalRecords : totalRecords
21284 * Ext JS Library 1.1.1
21285 * Copyright(c) 2006-2007, Ext JS, LLC.
21287 * Originally Released Under LGPL - original licence link has changed is not relivant.
21290 * <script type="text/javascript">
21294 * @class Roo.data.XmlReader
21295 * @extends Roo.data.DataReader
21296 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21297 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21299 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21300 * header in the HTTP response must be set to "text/xml".</em>
21304 var RecordDef = Roo.data.Record.create([
21305 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21306 {name: 'occupation'} // This field will use "occupation" as the mapping.
21308 var myReader = new Roo.data.XmlReader({
21309 totalRecords: "results", // The element which contains the total dataset size (optional)
21310 record: "row", // The repeated element which contains row information
21311 id: "id" // The element within the row that provides an ID for the record (optional)
21315 * This would consume an XML file like this:
21319 <results>2</results>
21322 <name>Bill</name>
21323 <occupation>Gardener</occupation>
21327 <name>Ben</name>
21328 <occupation>Horticulturalist</occupation>
21332 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21333 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21334 * paged from the remote server.
21335 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21336 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21337 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21338 * a record identifier value.
21340 * Create a new XmlReader
21341 * @param {Object} meta Metadata configuration options
21342 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21343 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21344 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21346 Roo.data.XmlReader = function(meta, recordType){
21348 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21350 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21352 * This method is only used by a DataProxy which has retrieved data from a remote server.
21353 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21354 * to contain a method called 'responseXML' that returns an XML document object.
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 read : function(response){
21359 var doc = response.responseXML;
21361 throw {message: "XmlReader.read: XML Document not available"};
21363 return this.readRecords(doc);
21367 * Create a data block containing Roo.data.Records from an XML document.
21368 * @param {Object} doc A parsed XML document.
21369 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21370 * a cache of Roo.data.Records.
21372 readRecords : function(doc){
21374 * After any data loads/reads, the raw XML Document is available for further custom processing.
21375 * @type XMLDocument
21377 this.xmlData = doc;
21378 var root = doc.documentElement || doc;
21379 var q = Roo.DomQuery;
21380 var recordType = this.recordType, fields = recordType.prototype.fields;
21381 var sid = this.meta.id;
21382 var totalRecords = 0, success = true;
21383 if(this.meta.totalRecords){
21384 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21387 if(this.meta.success){
21388 var sv = q.selectValue(this.meta.success, root, true);
21389 success = sv !== false && sv !== 'false';
21392 var ns = q.select(this.meta.record, root);
21393 for(var i = 0, len = ns.length; i < len; i++) {
21396 var id = sid ? q.selectValue(sid, n) : undefined;
21397 for(var j = 0, jlen = fields.length; j < jlen; j++){
21398 var f = fields.items[j];
21399 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21401 values[f.name] = v;
21403 var record = new recordType(values, id);
21405 records[records.length] = record;
21411 totalRecords : totalRecords || records.length
21416 * Ext JS Library 1.1.1
21417 * Copyright(c) 2006-2007, Ext JS, LLC.
21419 * Originally Released Under LGPL - original licence link has changed is not relivant.
21422 * <script type="text/javascript">
21426 * @class Roo.data.ArrayReader
21427 * @extends Roo.data.DataReader
21428 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21429 * Each element of that Array represents a row of data fields. The
21430 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21431 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21435 var RecordDef = Roo.data.Record.create([
21436 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21437 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21439 var myReader = new Roo.data.ArrayReader({
21440 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21444 * This would consume an Array like this:
21446 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21448 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21450 * Create a new JsonReader
21451 * @param {Object} meta Metadata configuration options.
21452 * @param {Object} recordType Either an Array of field definition objects
21453 * as specified to {@link Roo.data.Record#create},
21454 * or an {@link Roo.data.Record} object
21455 * created using {@link Roo.data.Record#create}.
21457 Roo.data.ArrayReader = function(meta, recordType){
21458 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21461 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21463 * Create a data block containing Roo.data.Records from an XML document.
21464 * @param {Object} o An Array of row objects which represents the dataset.
21465 * @return {Object} data A data block which is used by an Roo.data.Store object as
21466 * a cache of Roo.data.Records.
21468 readRecords : function(o){
21469 var sid = this.meta ? this.meta.id : null;
21470 var recordType = this.recordType, fields = recordType.prototype.fields;
21473 for(var i = 0; i < root.length; i++){
21476 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21477 for(var j = 0, jlen = fields.length; j < jlen; j++){
21478 var f = fields.items[j];
21479 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21480 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21482 values[f.name] = v;
21484 var record = new recordType(values, id);
21486 records[records.length] = record;
21490 totalRecords : records.length
21495 * Ext JS Library 1.1.1
21496 * Copyright(c) 2006-2007, Ext JS, LLC.
21498 * Originally Released Under LGPL - original licence link has changed is not relivant.
21501 * <script type="text/javascript">
21506 * @class Roo.data.Tree
21507 * @extends Roo.util.Observable
21508 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21509 * in the tree have most standard DOM functionality.
21511 * @param {Node} root (optional) The root node
21513 Roo.data.Tree = function(root){
21514 this.nodeHash = {};
21516 * The root node for this tree
21521 this.setRootNode(root);
21526 * Fires when a new child node is appended to a node in this tree.
21527 * @param {Tree} tree The owner tree
21528 * @param {Node} parent The parent node
21529 * @param {Node} node The newly appended node
21530 * @param {Number} index The index of the newly appended node
21535 * Fires when a child node is removed from a node in this tree.
21536 * @param {Tree} tree The owner tree
21537 * @param {Node} parent The parent node
21538 * @param {Node} node The child node removed
21543 * Fires when a node is moved to a new location in the tree
21544 * @param {Tree} tree The owner tree
21545 * @param {Node} node The node moved
21546 * @param {Node} oldParent The old parent of this node
21547 * @param {Node} newParent The new parent of this node
21548 * @param {Number} index The index it was moved to
21553 * Fires when a new child node is inserted in a node in this tree.
21554 * @param {Tree} tree The owner tree
21555 * @param {Node} parent The parent node
21556 * @param {Node} node The child node inserted
21557 * @param {Node} refNode The child node the node was inserted before
21561 * @event beforeappend
21562 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21563 * @param {Tree} tree The owner tree
21564 * @param {Node} parent The parent node
21565 * @param {Node} node The child node to be appended
21567 "beforeappend" : true,
21569 * @event beforeremove
21570 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21571 * @param {Tree} tree The owner tree
21572 * @param {Node} parent The parent node
21573 * @param {Node} node The child node to be removed
21575 "beforeremove" : true,
21577 * @event beforemove
21578 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21579 * @param {Tree} tree The owner tree
21580 * @param {Node} node The node being moved
21581 * @param {Node} oldParent The parent of the node
21582 * @param {Node} newParent The new parent the node is moving to
21583 * @param {Number} index The index it is being moved to
21585 "beforemove" : true,
21587 * @event beforeinsert
21588 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21589 * @param {Tree} tree The owner tree
21590 * @param {Node} parent The parent node
21591 * @param {Node} node The child node to be inserted
21592 * @param {Node} refNode The child node the node is being inserted before
21594 "beforeinsert" : true
21597 Roo.data.Tree.superclass.constructor.call(this);
21600 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21601 pathSeparator: "/",
21603 proxyNodeEvent : function(){
21604 return this.fireEvent.apply(this, arguments);
21608 * Returns the root node for this tree.
21611 getRootNode : function(){
21616 * Sets the root node for this tree.
21617 * @param {Node} node
21620 setRootNode : function(node){
21622 node.ownerTree = this;
21623 node.isRoot = true;
21624 this.registerNode(node);
21629 * Gets a node in this tree by its id.
21630 * @param {String} id
21633 getNodeById : function(id){
21634 return this.nodeHash[id];
21637 registerNode : function(node){
21638 this.nodeHash[node.id] = node;
21641 unregisterNode : function(node){
21642 delete this.nodeHash[node.id];
21645 toString : function(){
21646 return "[Tree"+(this.id?" "+this.id:"")+"]";
21651 * @class Roo.data.Node
21652 * @extends Roo.util.Observable
21653 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21654 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21656 * @param {Object} attributes The attributes/config for the node
21658 Roo.data.Node = function(attributes){
21660 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21663 this.attributes = attributes || {};
21664 this.leaf = this.attributes.leaf;
21666 * The node id. @type String
21668 this.id = this.attributes.id;
21670 this.id = Roo.id(null, "ynode-");
21671 this.attributes.id = this.id;
21676 * All child nodes of this node. @type Array
21678 this.childNodes = [];
21679 if(!this.childNodes.indexOf){ // indexOf is a must
21680 this.childNodes.indexOf = function(o){
21681 for(var i = 0, len = this.length; i < len; i++){
21690 * The parent node for this node. @type Node
21692 this.parentNode = null;
21694 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21696 this.firstChild = null;
21698 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21700 this.lastChild = null;
21702 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21704 this.previousSibling = null;
21706 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21708 this.nextSibling = null;
21713 * Fires when a new child node is appended
21714 * @param {Tree} tree The owner tree
21715 * @param {Node} this This node
21716 * @param {Node} node The newly appended node
21717 * @param {Number} index The index of the newly appended node
21722 * Fires when a child node is removed
21723 * @param {Tree} tree The owner tree
21724 * @param {Node} this This node
21725 * @param {Node} node The removed node
21730 * Fires when this node is moved to a new location in the tree
21731 * @param {Tree} tree The owner tree
21732 * @param {Node} this This node
21733 * @param {Node} oldParent The old parent of this node
21734 * @param {Node} newParent The new parent of this node
21735 * @param {Number} index The index it was moved to
21740 * Fires when a new child node is inserted.
21741 * @param {Tree} tree The owner tree
21742 * @param {Node} this This node
21743 * @param {Node} node The child node inserted
21744 * @param {Node} refNode The child node the node was inserted before
21748 * @event beforeappend
21749 * Fires before a new child is appended, return false to cancel the append.
21750 * @param {Tree} tree The owner tree
21751 * @param {Node} this This node
21752 * @param {Node} node The child node to be appended
21754 "beforeappend" : true,
21756 * @event beforeremove
21757 * Fires before a child is removed, return false to cancel the remove.
21758 * @param {Tree} tree The owner tree
21759 * @param {Node} this This node
21760 * @param {Node} node The child node to be removed
21762 "beforeremove" : true,
21764 * @event beforemove
21765 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21766 * @param {Tree} tree The owner tree
21767 * @param {Node} this This node
21768 * @param {Node} oldParent The parent of this node
21769 * @param {Node} newParent The new parent this node is moving to
21770 * @param {Number} index The index it is being moved to
21772 "beforemove" : true,
21774 * @event beforeinsert
21775 * Fires before a new child is inserted, return false to cancel the insert.
21776 * @param {Tree} tree The owner tree
21777 * @param {Node} this This node
21778 * @param {Node} node The child node to be inserted
21779 * @param {Node} refNode The child node the node is being inserted before
21781 "beforeinsert" : true
21783 this.listeners = this.attributes.listeners;
21784 Roo.data.Node.superclass.constructor.call(this);
21787 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21788 fireEvent : function(evtName){
21789 // first do standard event for this node
21790 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21793 // then bubble it up to the tree if the event wasn't cancelled
21794 var ot = this.getOwnerTree();
21796 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21804 * Returns true if this node is a leaf
21805 * @return {Boolean}
21807 isLeaf : function(){
21808 return this.leaf === true;
21812 setFirstChild : function(node){
21813 this.firstChild = node;
21817 setLastChild : function(node){
21818 this.lastChild = node;
21823 * Returns true if this node is the last child of its parent
21824 * @return {Boolean}
21826 isLast : function(){
21827 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21831 * Returns true if this node is the first child of its parent
21832 * @return {Boolean}
21834 isFirst : function(){
21835 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21838 hasChildNodes : function(){
21839 return !this.isLeaf() && this.childNodes.length > 0;
21843 * Insert node(s) as the last child node of this node.
21844 * @param {Node/Array} node The node or Array of nodes to append
21845 * @return {Node} The appended node if single append, or null if an array was passed
21847 appendChild : function(node){
21849 if(node instanceof Array){
21851 }else if(arguments.length > 1){
21854 // if passed an array or multiple args do them one by one
21856 for(var i = 0, len = multi.length; i < len; i++) {
21857 this.appendChild(multi[i]);
21860 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21863 var index = this.childNodes.length;
21864 var oldParent = node.parentNode;
21865 // it's a move, make sure we move it cleanly
21867 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21870 oldParent.removeChild(node);
21872 index = this.childNodes.length;
21874 this.setFirstChild(node);
21876 this.childNodes.push(node);
21877 node.parentNode = this;
21878 var ps = this.childNodes[index-1];
21880 node.previousSibling = ps;
21881 ps.nextSibling = node;
21883 node.previousSibling = null;
21885 node.nextSibling = null;
21886 this.setLastChild(node);
21887 node.setOwnerTree(this.getOwnerTree());
21888 this.fireEvent("append", this.ownerTree, this, node, index);
21890 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21897 * Removes a child node from this node.
21898 * @param {Node} node The node to remove
21899 * @return {Node} The removed node
21901 removeChild : function(node){
21902 var index = this.childNodes.indexOf(node);
21906 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21910 // remove it from childNodes collection
21911 this.childNodes.splice(index, 1);
21914 if(node.previousSibling){
21915 node.previousSibling.nextSibling = node.nextSibling;
21917 if(node.nextSibling){
21918 node.nextSibling.previousSibling = node.previousSibling;
21921 // update child refs
21922 if(this.firstChild == node){
21923 this.setFirstChild(node.nextSibling);
21925 if(this.lastChild == node){
21926 this.setLastChild(node.previousSibling);
21929 node.setOwnerTree(null);
21930 // clear any references from the node
21931 node.parentNode = null;
21932 node.previousSibling = null;
21933 node.nextSibling = null;
21934 this.fireEvent("remove", this.ownerTree, this, node);
21939 * Inserts the first node before the second node in this nodes childNodes collection.
21940 * @param {Node} node The node to insert
21941 * @param {Node} refNode The node to insert before (if null the node is appended)
21942 * @return {Node} The inserted node
21944 insertBefore : function(node, refNode){
21945 if(!refNode){ // like standard Dom, refNode can be null for append
21946 return this.appendChild(node);
21949 if(node == refNode){
21953 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21956 var index = this.childNodes.indexOf(refNode);
21957 var oldParent = node.parentNode;
21958 var refIndex = index;
21960 // when moving internally, indexes will change after remove
21961 if(oldParent == this && this.childNodes.indexOf(node) < index){
21965 // it's a move, make sure we move it cleanly
21967 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21970 oldParent.removeChild(node);
21973 this.setFirstChild(node);
21975 this.childNodes.splice(refIndex, 0, node);
21976 node.parentNode = this;
21977 var ps = this.childNodes[refIndex-1];
21979 node.previousSibling = ps;
21980 ps.nextSibling = node;
21982 node.previousSibling = null;
21984 node.nextSibling = refNode;
21985 refNode.previousSibling = node;
21986 node.setOwnerTree(this.getOwnerTree());
21987 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21989 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21995 * Returns the child node at the specified index.
21996 * @param {Number} index
21999 item : function(index){
22000 return this.childNodes[index];
22004 * Replaces one child node in this node with another.
22005 * @param {Node} newChild The replacement node
22006 * @param {Node} oldChild The node to replace
22007 * @return {Node} The replaced node
22009 replaceChild : function(newChild, oldChild){
22010 this.insertBefore(newChild, oldChild);
22011 this.removeChild(oldChild);
22016 * Returns the index of a child node
22017 * @param {Node} node
22018 * @return {Number} The index of the node or -1 if it was not found
22020 indexOf : function(child){
22021 return this.childNodes.indexOf(child);
22025 * Returns the tree this node is in.
22028 getOwnerTree : function(){
22029 // if it doesn't have one, look for one
22030 if(!this.ownerTree){
22034 this.ownerTree = p.ownerTree;
22040 return this.ownerTree;
22044 * Returns depth of this node (the root node has a depth of 0)
22047 getDepth : function(){
22050 while(p.parentNode){
22058 setOwnerTree : function(tree){
22059 // if it's move, we need to update everyone
22060 if(tree != this.ownerTree){
22061 if(this.ownerTree){
22062 this.ownerTree.unregisterNode(this);
22064 this.ownerTree = tree;
22065 var cs = this.childNodes;
22066 for(var i = 0, len = cs.length; i < len; i++) {
22067 cs[i].setOwnerTree(tree);
22070 tree.registerNode(this);
22076 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22077 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22078 * @return {String} The path
22080 getPath : function(attr){
22081 attr = attr || "id";
22082 var p = this.parentNode;
22083 var b = [this.attributes[attr]];
22085 b.unshift(p.attributes[attr]);
22088 var sep = this.getOwnerTree().pathSeparator;
22089 return sep + b.join(sep);
22093 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22094 * function call will be the scope provided or the current node. The arguments to the function
22095 * will be the args provided or the current node. If the function returns false at any point,
22096 * the bubble is stopped.
22097 * @param {Function} fn The function to call
22098 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22099 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22101 bubble : function(fn, scope, args){
22104 if(fn.call(scope || p, args || p) === false){
22112 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22113 * function call will be the scope provided or the current node. The arguments to the function
22114 * will be the args provided or the current node. If the function returns false at any point,
22115 * the cascade is stopped on that branch.
22116 * @param {Function} fn The function to call
22117 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22118 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22120 cascade : function(fn, scope, args){
22121 if(fn.call(scope || this, args || this) !== false){
22122 var cs = this.childNodes;
22123 for(var i = 0, len = cs.length; i < len; i++) {
22124 cs[i].cascade(fn, scope, args);
22130 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22131 * function call will be the scope provided or the current node. The arguments to the function
22132 * will be the args provided or the current node. If the function returns false at any point,
22133 * the iteration stops.
22134 * @param {Function} fn The function to call
22135 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22136 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22138 eachChild : function(fn, scope, args){
22139 var cs = this.childNodes;
22140 for(var i = 0, len = cs.length; i < len; i++) {
22141 if(fn.call(scope || this, args || cs[i]) === false){
22148 * Finds the first child that has the attribute with the specified value.
22149 * @param {String} attribute The attribute name
22150 * @param {Mixed} value The value to search for
22151 * @return {Node} The found child or null if none was found
22153 findChild : function(attribute, value){
22154 var cs = this.childNodes;
22155 for(var i = 0, len = cs.length; i < len; i++) {
22156 if(cs[i].attributes[attribute] == value){
22164 * Finds the first child by a custom function. The child matches if the function passed
22166 * @param {Function} fn
22167 * @param {Object} scope (optional)
22168 * @return {Node} The found child or null if none was found
22170 findChildBy : function(fn, scope){
22171 var cs = this.childNodes;
22172 for(var i = 0, len = cs.length; i < len; i++) {
22173 if(fn.call(scope||cs[i], cs[i]) === true){
22181 * Sorts this nodes children using the supplied sort function
22182 * @param {Function} fn
22183 * @param {Object} scope (optional)
22185 sort : function(fn, scope){
22186 var cs = this.childNodes;
22187 var len = cs.length;
22189 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22191 for(var i = 0; i < len; i++){
22193 n.previousSibling = cs[i-1];
22194 n.nextSibling = cs[i+1];
22196 this.setFirstChild(n);
22199 this.setLastChild(n);
22206 * Returns true if this node is an ancestor (at any point) of the passed node.
22207 * @param {Node} node
22208 * @return {Boolean}
22210 contains : function(node){
22211 return node.isAncestor(this);
22215 * Returns true if the passed node is an ancestor (at any point) of this node.
22216 * @param {Node} node
22217 * @return {Boolean}
22219 isAncestor : function(node){
22220 var p = this.parentNode;
22230 toString : function(){
22231 return "[Node"+(this.id?" "+this.id:"")+"]";
22235 * Ext JS Library 1.1.1
22236 * Copyright(c) 2006-2007, Ext JS, LLC.
22238 * Originally Released Under LGPL - original licence link has changed is not relivant.
22241 * <script type="text/javascript">
22246 * @class Roo.ComponentMgr
22247 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22250 Roo.ComponentMgr = function(){
22251 var all = new Roo.util.MixedCollection();
22255 * Registers a component.
22256 * @param {Roo.Component} c The component
22258 register : function(c){
22263 * Unregisters a component.
22264 * @param {Roo.Component} c The component
22266 unregister : function(c){
22271 * Returns a component by id
22272 * @param {String} id The component id
22274 get : function(id){
22275 return all.get(id);
22279 * Registers a function that will be called when a specified component is added to ComponentMgr
22280 * @param {String} id The component id
22281 * @param {Funtction} fn The callback function
22282 * @param {Object} scope The scope of the callback
22284 onAvailable : function(id, fn, scope){
22285 all.on("add", function(index, o){
22287 fn.call(scope || o, o);
22288 all.un("add", fn, scope);
22295 * Ext JS Library 1.1.1
22296 * Copyright(c) 2006-2007, Ext JS, LLC.
22298 * Originally Released Under LGPL - original licence link has changed is not relivant.
22301 * <script type="text/javascript">
22305 * @class Roo.Component
22306 * @extends Roo.util.Observable
22307 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22308 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22309 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22310 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22311 * All visual components (widgets) that require rendering into a layout should subclass Component.
22313 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22314 * 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
22315 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22317 Roo.Component = function(config){
22318 config = config || {};
22319 if(config.tagName || config.dom || typeof config == "string"){ // element object
22320 config = {el: config, id: config.id || config};
22322 this.initialConfig = config;
22324 Roo.apply(this, config);
22328 * Fires after the component is disabled.
22329 * @param {Roo.Component} this
22334 * Fires after the component is enabled.
22335 * @param {Roo.Component} this
22339 * @event beforeshow
22340 * Fires before the component is shown. Return false to stop the show.
22341 * @param {Roo.Component} this
22346 * Fires after the component is shown.
22347 * @param {Roo.Component} this
22351 * @event beforehide
22352 * Fires before the component is hidden. Return false to stop the hide.
22353 * @param {Roo.Component} this
22358 * Fires after the component is hidden.
22359 * @param {Roo.Component} this
22363 * @event beforerender
22364 * Fires before the component is rendered. Return false to stop the render.
22365 * @param {Roo.Component} this
22367 beforerender : true,
22370 * Fires after the component is rendered.
22371 * @param {Roo.Component} this
22375 * @event beforedestroy
22376 * Fires before the component is destroyed. Return false to stop the destroy.
22377 * @param {Roo.Component} this
22379 beforedestroy : true,
22382 * Fires after the component is destroyed.
22383 * @param {Roo.Component} this
22388 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22390 Roo.ComponentMgr.register(this);
22391 Roo.Component.superclass.constructor.call(this);
22392 this.initComponent();
22393 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22394 this.render(this.renderTo);
22395 delete this.renderTo;
22400 Roo.Component.AUTO_ID = 1000;
22402 Roo.extend(Roo.Component, Roo.util.Observable, {
22404 * @scope Roo.Component.prototype
22406 * true if this component is hidden. Read-only.
22411 * true if this component is disabled. Read-only.
22416 * true if this component has been rendered. Read-only.
22420 /** @cfg {String} disableClass
22421 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22423 disabledClass : "x-item-disabled",
22424 /** @cfg {Boolean} allowDomMove
22425 * Whether the component can move the Dom node when rendering (defaults to true).
22427 allowDomMove : true,
22428 /** @cfg {String} hideMode
22429 * How this component should hidden. Supported values are
22430 * "visibility" (css visibility), "offsets" (negative offset position) and
22431 * "display" (css display) - defaults to "display".
22433 hideMode: 'display',
22436 ctype : "Roo.Component",
22439 * @cfg {String} actionMode
22440 * which property holds the element that used for hide() / show() / disable() / enable()
22446 getActionEl : function(){
22447 return this[this.actionMode];
22450 initComponent : Roo.emptyFn,
22452 * If this is a lazy rendering component, render it to its container element.
22453 * @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.
22455 render : function(container, position){
22456 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22457 if(!container && this.el){
22458 this.el = Roo.get(this.el);
22459 container = this.el.dom.parentNode;
22460 this.allowDomMove = false;
22462 this.container = Roo.get(container);
22463 this.rendered = true;
22464 if(position !== undefined){
22465 if(typeof position == 'number'){
22466 position = this.container.dom.childNodes[position];
22468 position = Roo.getDom(position);
22471 this.onRender(this.container, position || null);
22473 this.el.addClass(this.cls);
22477 this.el.applyStyles(this.style);
22480 this.fireEvent("render", this);
22481 this.afterRender(this.container);
22493 // default function is not really useful
22494 onRender : function(ct, position){
22496 this.el = Roo.get(this.el);
22497 if(this.allowDomMove !== false){
22498 ct.dom.insertBefore(this.el.dom, position);
22504 getAutoCreate : function(){
22505 var cfg = typeof this.autoCreate == "object" ?
22506 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22507 if(this.id && !cfg.id){
22514 afterRender : Roo.emptyFn,
22517 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22518 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22520 destroy : function(){
22521 if(this.fireEvent("beforedestroy", this) !== false){
22522 this.purgeListeners();
22523 this.beforeDestroy();
22525 this.el.removeAllListeners();
22527 if(this.actionMode == "container"){
22528 this.container.remove();
22532 Roo.ComponentMgr.unregister(this);
22533 this.fireEvent("destroy", this);
22538 beforeDestroy : function(){
22543 onDestroy : function(){
22548 * Returns the underlying {@link Roo.Element}.
22549 * @return {Roo.Element} The element
22551 getEl : function(){
22556 * Returns the id of this component.
22559 getId : function(){
22564 * Try to focus this component.
22565 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22566 * @return {Roo.Component} this
22568 focus : function(selectText){
22571 if(selectText === true){
22572 this.el.dom.select();
22587 * Disable this component.
22588 * @return {Roo.Component} this
22590 disable : function(){
22594 this.disabled = true;
22595 this.fireEvent("disable", this);
22600 onDisable : function(){
22601 this.getActionEl().addClass(this.disabledClass);
22602 this.el.dom.disabled = true;
22606 * Enable this component.
22607 * @return {Roo.Component} this
22609 enable : function(){
22613 this.disabled = false;
22614 this.fireEvent("enable", this);
22619 onEnable : function(){
22620 this.getActionEl().removeClass(this.disabledClass);
22621 this.el.dom.disabled = false;
22625 * Convenience function for setting disabled/enabled by boolean.
22626 * @param {Boolean} disabled
22628 setDisabled : function(disabled){
22629 this[disabled ? "disable" : "enable"]();
22633 * Show this component.
22634 * @return {Roo.Component} this
22637 if(this.fireEvent("beforeshow", this) !== false){
22638 this.hidden = false;
22642 this.fireEvent("show", this);
22648 onShow : function(){
22649 var ae = this.getActionEl();
22650 if(this.hideMode == 'visibility'){
22651 ae.dom.style.visibility = "visible";
22652 }else if(this.hideMode == 'offsets'){
22653 ae.removeClass('x-hidden');
22655 ae.dom.style.display = "";
22660 * Hide this component.
22661 * @return {Roo.Component} this
22664 if(this.fireEvent("beforehide", this) !== false){
22665 this.hidden = true;
22669 this.fireEvent("hide", this);
22675 onHide : function(){
22676 var ae = this.getActionEl();
22677 if(this.hideMode == 'visibility'){
22678 ae.dom.style.visibility = "hidden";
22679 }else if(this.hideMode == 'offsets'){
22680 ae.addClass('x-hidden');
22682 ae.dom.style.display = "none";
22687 * Convenience function to hide or show this component by boolean.
22688 * @param {Boolean} visible True to show, false to hide
22689 * @return {Roo.Component} this
22691 setVisible: function(visible){
22701 * Returns true if this component is visible.
22703 isVisible : function(){
22704 return this.getActionEl().isVisible();
22707 cloneConfig : function(overrides){
22708 overrides = overrides || {};
22709 var id = overrides.id || Roo.id();
22710 var cfg = Roo.applyIf(overrides, this.initialConfig);
22711 cfg.id = id; // prevent dup id
22712 return new this.constructor(cfg);
22716 * Ext JS Library 1.1.1
22717 * Copyright(c) 2006-2007, Ext JS, LLC.
22719 * Originally Released Under LGPL - original licence link has changed is not relivant.
22722 * <script type="text/javascript">
22727 * @extends Roo.Element
22728 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22729 * automatic maintaining of shadow/shim positions.
22730 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22731 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22732 * you can pass a string with a CSS class name. False turns off the shadow.
22733 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22734 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22735 * @cfg {String} cls CSS class to add to the element
22736 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22737 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22739 * @param {Object} config An object with config options.
22740 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22743 Roo.Layer = function(config, existingEl){
22744 config = config || {};
22745 var dh = Roo.DomHelper;
22746 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22748 this.dom = Roo.getDom(existingEl);
22751 var o = config.dh || {tag: "div", cls: "x-layer"};
22752 this.dom = dh.append(pel, o);
22755 this.addClass(config.cls);
22757 this.constrain = config.constrain !== false;
22758 this.visibilityMode = Roo.Element.VISIBILITY;
22760 this.id = this.dom.id = config.id;
22762 this.id = Roo.id(this.dom);
22764 this.zindex = config.zindex || this.getZIndex();
22765 this.position("absolute", this.zindex);
22767 this.shadowOffset = config.shadowOffset || 4;
22768 this.shadow = new Roo.Shadow({
22769 offset : this.shadowOffset,
22770 mode : config.shadow
22773 this.shadowOffset = 0;
22775 this.useShim = config.shim !== false && Roo.useShims;
22776 this.useDisplay = config.useDisplay;
22780 var supr = Roo.Element.prototype;
22782 // shims are shared among layer to keep from having 100 iframes
22785 Roo.extend(Roo.Layer, Roo.Element, {
22787 getZIndex : function(){
22788 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22791 getShim : function(){
22798 var shim = shims.shift();
22800 shim = this.createShim();
22801 shim.enableDisplayMode('block');
22802 shim.dom.style.display = 'none';
22803 shim.dom.style.visibility = 'visible';
22805 var pn = this.dom.parentNode;
22806 if(shim.dom.parentNode != pn){
22807 pn.insertBefore(shim.dom, this.dom);
22809 shim.setStyle('z-index', this.getZIndex()-2);
22814 hideShim : function(){
22816 this.shim.setDisplayed(false);
22817 shims.push(this.shim);
22822 disableShadow : function(){
22824 this.shadowDisabled = true;
22825 this.shadow.hide();
22826 this.lastShadowOffset = this.shadowOffset;
22827 this.shadowOffset = 0;
22831 enableShadow : function(show){
22833 this.shadowDisabled = false;
22834 this.shadowOffset = this.lastShadowOffset;
22835 delete this.lastShadowOffset;
22843 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22844 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22845 sync : function(doShow){
22846 var sw = this.shadow;
22847 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22848 var sh = this.getShim();
22850 var w = this.getWidth(),
22851 h = this.getHeight();
22853 var l = this.getLeft(true),
22854 t = this.getTop(true);
22856 if(sw && !this.shadowDisabled){
22857 if(doShow && !sw.isVisible()){
22860 sw.realign(l, t, w, h);
22866 // fit the shim behind the shadow, so it is shimmed too
22867 var a = sw.adjusts, s = sh.dom.style;
22868 s.left = (Math.min(l, l+a.l))+"px";
22869 s.top = (Math.min(t, t+a.t))+"px";
22870 s.width = (w+a.w)+"px";
22871 s.height = (h+a.h)+"px";
22878 sh.setLeftTop(l, t);
22885 destroy : function(){
22888 this.shadow.hide();
22890 this.removeAllListeners();
22891 var pn = this.dom.parentNode;
22893 pn.removeChild(this.dom);
22895 Roo.Element.uncache(this.id);
22898 remove : function(){
22903 beginUpdate : function(){
22904 this.updating = true;
22908 endUpdate : function(){
22909 this.updating = false;
22914 hideUnders : function(negOffset){
22916 this.shadow.hide();
22922 constrainXY : function(){
22923 if(this.constrain){
22924 var vw = Roo.lib.Dom.getViewWidth(),
22925 vh = Roo.lib.Dom.getViewHeight();
22926 var s = Roo.get(document).getScroll();
22928 var xy = this.getXY();
22929 var x = xy[0], y = xy[1];
22930 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22931 // only move it if it needs it
22933 // first validate right/bottom
22934 if((x + w) > vw+s.left){
22935 x = vw - w - this.shadowOffset;
22938 if((y + h) > vh+s.top){
22939 y = vh - h - this.shadowOffset;
22942 // then make sure top/left isn't negative
22953 var ay = this.avoidY;
22954 if(y <= ay && (y+h) >= ay){
22960 supr.setXY.call(this, xy);
22966 isVisible : function(){
22967 return this.visible;
22971 showAction : function(){
22972 this.visible = true; // track visibility to prevent getStyle calls
22973 if(this.useDisplay === true){
22974 this.setDisplayed("");
22975 }else if(this.lastXY){
22976 supr.setXY.call(this, this.lastXY);
22977 }else if(this.lastLT){
22978 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22983 hideAction : function(){
22984 this.visible = false;
22985 if(this.useDisplay === true){
22986 this.setDisplayed(false);
22988 this.setLeftTop(-10000,-10000);
22992 // overridden Element method
22993 setVisible : function(v, a, d, c, e){
22998 var cb = function(){
23003 }.createDelegate(this);
23004 supr.setVisible.call(this, true, true, d, cb, e);
23007 this.hideUnders(true);
23016 }.createDelegate(this);
23018 supr.setVisible.call(this, v, a, d, cb, e);
23027 storeXY : function(xy){
23028 delete this.lastLT;
23032 storeLeftTop : function(left, top){
23033 delete this.lastXY;
23034 this.lastLT = [left, top];
23038 beforeFx : function(){
23039 this.beforeAction();
23040 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23044 afterFx : function(){
23045 Roo.Layer.superclass.afterFx.apply(this, arguments);
23046 this.sync(this.isVisible());
23050 beforeAction : function(){
23051 if(!this.updating && this.shadow){
23052 this.shadow.hide();
23056 // overridden Element method
23057 setLeft : function(left){
23058 this.storeLeftTop(left, this.getTop(true));
23059 supr.setLeft.apply(this, arguments);
23063 setTop : function(top){
23064 this.storeLeftTop(this.getLeft(true), top);
23065 supr.setTop.apply(this, arguments);
23069 setLeftTop : function(left, top){
23070 this.storeLeftTop(left, top);
23071 supr.setLeftTop.apply(this, arguments);
23075 setXY : function(xy, a, d, c, e){
23077 this.beforeAction();
23079 var cb = this.createCB(c);
23080 supr.setXY.call(this, xy, a, d, cb, e);
23087 createCB : function(c){
23098 // overridden Element method
23099 setX : function(x, a, d, c, e){
23100 this.setXY([x, this.getY()], a, d, c, e);
23103 // overridden Element method
23104 setY : function(y, a, d, c, e){
23105 this.setXY([this.getX(), y], a, d, c, e);
23108 // overridden Element method
23109 setSize : function(w, h, a, d, c, e){
23110 this.beforeAction();
23111 var cb = this.createCB(c);
23112 supr.setSize.call(this, w, h, a, d, cb, e);
23118 // overridden Element method
23119 setWidth : function(w, a, d, c, e){
23120 this.beforeAction();
23121 var cb = this.createCB(c);
23122 supr.setWidth.call(this, w, a, d, cb, e);
23128 // overridden Element method
23129 setHeight : function(h, a, d, c, e){
23130 this.beforeAction();
23131 var cb = this.createCB(c);
23132 supr.setHeight.call(this, h, a, d, cb, e);
23138 // overridden Element method
23139 setBounds : function(x, y, w, h, a, d, c, e){
23140 this.beforeAction();
23141 var cb = this.createCB(c);
23143 this.storeXY([x, y]);
23144 supr.setXY.call(this, [x, y]);
23145 supr.setSize.call(this, w, h, a, d, cb, e);
23148 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23154 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23155 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23156 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23157 * @param {Number} zindex The new z-index to set
23158 * @return {this} The Layer
23160 setZIndex : function(zindex){
23161 this.zindex = zindex;
23162 this.setStyle("z-index", zindex + 2);
23164 this.shadow.setZIndex(zindex + 1);
23167 this.shim.setStyle("z-index", zindex);
23173 * Ext JS Library 1.1.1
23174 * Copyright(c) 2006-2007, Ext JS, LLC.
23176 * Originally Released Under LGPL - original licence link has changed is not relivant.
23179 * <script type="text/javascript">
23184 * @class Roo.Shadow
23185 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23186 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23187 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23189 * Create a new Shadow
23190 * @param {Object} config The config object
23192 Roo.Shadow = function(config){
23193 Roo.apply(this, config);
23194 if(typeof this.mode != "string"){
23195 this.mode = this.defaultMode;
23197 var o = this.offset, a = {h: 0};
23198 var rad = Math.floor(this.offset/2);
23199 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23205 a.l -= this.offset + rad;
23206 a.t -= this.offset + rad;
23217 a.l -= (this.offset - rad);
23218 a.t -= this.offset + rad;
23220 a.w -= (this.offset - rad)*2;
23231 a.l -= (this.offset - rad);
23232 a.t -= (this.offset - rad);
23234 a.w -= (this.offset + rad + 1);
23235 a.h -= (this.offset + rad);
23244 Roo.Shadow.prototype = {
23246 * @cfg {String} mode
23247 * The shadow display mode. Supports the following options:<br />
23248 * sides: Shadow displays on both sides and bottom only<br />
23249 * frame: Shadow displays equally on all four sides<br />
23250 * drop: Traditional bottom-right drop shadow (default)
23253 * @cfg {String} offset
23254 * The number of pixels to offset the shadow from the element (defaults to 4)
23259 defaultMode: "drop",
23262 * Displays the shadow under the target element
23263 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23265 show : function(target){
23266 target = Roo.get(target);
23268 this.el = Roo.Shadow.Pool.pull();
23269 if(this.el.dom.nextSibling != target.dom){
23270 this.el.insertBefore(target);
23273 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23275 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23278 target.getLeft(true),
23279 target.getTop(true),
23283 this.el.dom.style.display = "block";
23287 * Returns true if the shadow is visible, else false
23289 isVisible : function(){
23290 return this.el ? true : false;
23294 * Direct alignment when values are already available. Show must be called at least once before
23295 * calling this method to ensure it is initialized.
23296 * @param {Number} left The target element left position
23297 * @param {Number} top The target element top position
23298 * @param {Number} width The target element width
23299 * @param {Number} height The target element height
23301 realign : function(l, t, w, h){
23305 var a = this.adjusts, d = this.el.dom, s = d.style;
23307 s.left = (l+a.l)+"px";
23308 s.top = (t+a.t)+"px";
23309 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23311 if(s.width != sws || s.height != shs){
23315 var cn = d.childNodes;
23316 var sww = Math.max(0, (sw-12))+"px";
23317 cn[0].childNodes[1].style.width = sww;
23318 cn[1].childNodes[1].style.width = sww;
23319 cn[2].childNodes[1].style.width = sww;
23320 cn[1].style.height = Math.max(0, (sh-12))+"px";
23326 * Hides this shadow
23330 this.el.dom.style.display = "none";
23331 Roo.Shadow.Pool.push(this.el);
23337 * Adjust the z-index of this shadow
23338 * @param {Number} zindex The new z-index
23340 setZIndex : function(z){
23343 this.el.setStyle("z-index", z);
23348 // Private utility class that manages the internal Shadow cache
23349 Roo.Shadow.Pool = function(){
23351 var markup = Roo.isIE ?
23352 '<div class="x-ie-shadow"></div>' :
23353 '<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>';
23356 var sh = p.shift();
23358 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23359 sh.autoBoxAdjust = false;
23364 push : function(sh){
23370 * Ext JS Library 1.1.1
23371 * Copyright(c) 2006-2007, Ext JS, LLC.
23373 * Originally Released Under LGPL - original licence link has changed is not relivant.
23376 * <script type="text/javascript">
23380 * @class Roo.BoxComponent
23381 * @extends Roo.Component
23382 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23383 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23384 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23385 * layout containers.
23387 * @param {Roo.Element/String/Object} config The configuration options.
23389 Roo.BoxComponent = function(config){
23390 Roo.Component.call(this, config);
23394 * Fires after the component is resized.
23395 * @param {Roo.Component} this
23396 * @param {Number} adjWidth The box-adjusted width that was set
23397 * @param {Number} adjHeight The box-adjusted height that was set
23398 * @param {Number} rawWidth The width that was originally specified
23399 * @param {Number} rawHeight The height that was originally specified
23404 * Fires after the component is moved.
23405 * @param {Roo.Component} this
23406 * @param {Number} x The new x position
23407 * @param {Number} y The new y position
23413 Roo.extend(Roo.BoxComponent, Roo.Component, {
23414 // private, set in afterRender to signify that the component has been rendered
23416 // private, used to defer height settings to subclasses
23417 deferHeight: false,
23418 /** @cfg {Number} width
23419 * width (optional) size of component
23421 /** @cfg {Number} height
23422 * height (optional) size of component
23426 * Sets the width and height of the component. This method fires the resize event. This method can accept
23427 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23428 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23429 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23430 * @return {Roo.BoxComponent} this
23432 setSize : function(w, h){
23433 // support for standard size objects
23434 if(typeof w == 'object'){
23439 if(!this.boxReady){
23445 // prevent recalcs when not needed
23446 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23449 this.lastSize = {width: w, height: h};
23451 var adj = this.adjustSize(w, h);
23452 var aw = adj.width, ah = adj.height;
23453 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23454 var rz = this.getResizeEl();
23455 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23456 rz.setSize(aw, ah);
23457 }else if(!this.deferHeight && ah !== undefined){
23459 }else if(aw !== undefined){
23462 this.onResize(aw, ah, w, h);
23463 this.fireEvent('resize', this, aw, ah, w, h);
23469 * Gets the current size of the component's underlying element.
23470 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23472 getSize : function(){
23473 return this.el.getSize();
23477 * Gets the current XY position of the component's underlying element.
23478 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23479 * @return {Array} The XY position of the element (e.g., [100, 200])
23481 getPosition : function(local){
23482 if(local === true){
23483 return [this.el.getLeft(true), this.el.getTop(true)];
23485 return this.xy || this.el.getXY();
23489 * Gets the current box measurements of the component's underlying element.
23490 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23491 * @returns {Object} box An object in the format {x, y, width, height}
23493 getBox : function(local){
23494 var s = this.el.getSize();
23496 s.x = this.el.getLeft(true);
23497 s.y = this.el.getTop(true);
23499 var xy = this.xy || this.el.getXY();
23507 * Sets the current box measurements of the component's underlying element.
23508 * @param {Object} box An object in the format {x, y, width, height}
23509 * @returns {Roo.BoxComponent} this
23511 updateBox : function(box){
23512 this.setSize(box.width, box.height);
23513 this.setPagePosition(box.x, box.y);
23518 getResizeEl : function(){
23519 return this.resizeEl || this.el;
23523 getPositionEl : function(){
23524 return this.positionEl || this.el;
23528 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23529 * This method fires the move event.
23530 * @param {Number} left The new left
23531 * @param {Number} top The new top
23532 * @returns {Roo.BoxComponent} this
23534 setPosition : function(x, y){
23537 if(!this.boxReady){
23540 var adj = this.adjustPosition(x, y);
23541 var ax = adj.x, ay = adj.y;
23543 var el = this.getPositionEl();
23544 if(ax !== undefined || ay !== undefined){
23545 if(ax !== undefined && ay !== undefined){
23546 el.setLeftTop(ax, ay);
23547 }else if(ax !== undefined){
23549 }else if(ay !== undefined){
23552 this.onPosition(ax, ay);
23553 this.fireEvent('move', this, ax, ay);
23559 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23560 * This method fires the move event.
23561 * @param {Number} x The new x position
23562 * @param {Number} y The new y position
23563 * @returns {Roo.BoxComponent} this
23565 setPagePosition : function(x, y){
23568 if(!this.boxReady){
23571 if(x === undefined || y === undefined){ // cannot translate undefined points
23574 var p = this.el.translatePoints(x, y);
23575 this.setPosition(p.left, p.top);
23580 onRender : function(ct, position){
23581 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23583 this.resizeEl = Roo.get(this.resizeEl);
23585 if(this.positionEl){
23586 this.positionEl = Roo.get(this.positionEl);
23591 afterRender : function(){
23592 Roo.BoxComponent.superclass.afterRender.call(this);
23593 this.boxReady = true;
23594 this.setSize(this.width, this.height);
23595 if(this.x || this.y){
23596 this.setPosition(this.x, this.y);
23598 if(this.pageX || this.pageY){
23599 this.setPagePosition(this.pageX, this.pageY);
23604 * Force the component's size to recalculate based on the underlying element's current height and width.
23605 * @returns {Roo.BoxComponent} this
23607 syncSize : function(){
23608 delete this.lastSize;
23609 this.setSize(this.el.getWidth(), this.el.getHeight());
23614 * Called after the component is resized, this method is empty by default but can be implemented by any
23615 * subclass that needs to perform custom logic after a resize occurs.
23616 * @param {Number} adjWidth The box-adjusted width that was set
23617 * @param {Number} adjHeight The box-adjusted height that was set
23618 * @param {Number} rawWidth The width that was originally specified
23619 * @param {Number} rawHeight The height that was originally specified
23621 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23626 * Called after the component is moved, this method is empty by default but can be implemented by any
23627 * subclass that needs to perform custom logic after a move occurs.
23628 * @param {Number} x The new x position
23629 * @param {Number} y The new y position
23631 onPosition : function(x, y){
23636 adjustSize : function(w, h){
23637 if(this.autoWidth){
23640 if(this.autoHeight){
23643 return {width : w, height: h};
23647 adjustPosition : function(x, y){
23648 return {x : x, y: y};
23652 * Ext JS Library 1.1.1
23653 * Copyright(c) 2006-2007, Ext JS, LLC.
23655 * Originally Released Under LGPL - original licence link has changed is not relivant.
23658 * <script type="text/javascript">
23663 * @class Roo.SplitBar
23664 * @extends Roo.util.Observable
23665 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23669 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23670 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23671 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23672 split.minSize = 100;
23673 split.maxSize = 600;
23674 split.animate = true;
23675 split.on('moved', splitterMoved);
23678 * Create a new SplitBar
23679 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23680 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23681 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23682 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23683 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23684 position of the SplitBar).
23686 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23689 this.el = Roo.get(dragElement, true);
23690 this.el.dom.unselectable = "on";
23692 this.resizingEl = Roo.get(resizingElement, true);
23696 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23697 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23700 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23703 * The minimum size of the resizing element. (Defaults to 0)
23709 * The maximum size of the resizing element. (Defaults to 2000)
23712 this.maxSize = 2000;
23715 * Whether to animate the transition to the new size
23718 this.animate = false;
23721 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23724 this.useShim = false;
23729 if(!existingProxy){
23731 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23733 this.proxy = Roo.get(existingProxy).dom;
23736 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23739 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23742 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23745 this.dragSpecs = {};
23748 * @private The adapter to use to positon and resize elements
23750 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23751 this.adapter.init(this);
23753 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23755 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23756 this.el.addClass("x-splitbar-h");
23759 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23760 this.el.addClass("x-splitbar-v");
23766 * Fires when the splitter is moved (alias for {@link #event-moved})
23767 * @param {Roo.SplitBar} this
23768 * @param {Number} newSize the new width or height
23773 * Fires when the splitter is moved
23774 * @param {Roo.SplitBar} this
23775 * @param {Number} newSize the new width or height
23779 * @event beforeresize
23780 * Fires before the splitter is dragged
23781 * @param {Roo.SplitBar} this
23783 "beforeresize" : true,
23785 "beforeapply" : true
23788 Roo.util.Observable.call(this);
23791 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23792 onStartProxyDrag : function(x, y){
23793 this.fireEvent("beforeresize", this);
23795 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23797 o.enableDisplayMode("block");
23798 // all splitbars share the same overlay
23799 Roo.SplitBar.prototype.overlay = o;
23801 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23802 this.overlay.show();
23803 Roo.get(this.proxy).setDisplayed("block");
23804 var size = this.adapter.getElementSize(this);
23805 this.activeMinSize = this.getMinimumSize();;
23806 this.activeMaxSize = this.getMaximumSize();;
23807 var c1 = size - this.activeMinSize;
23808 var c2 = Math.max(this.activeMaxSize - size, 0);
23809 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23810 this.dd.resetConstraints();
23811 this.dd.setXConstraint(
23812 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23813 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23815 this.dd.setYConstraint(0, 0);
23817 this.dd.resetConstraints();
23818 this.dd.setXConstraint(0, 0);
23819 this.dd.setYConstraint(
23820 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23821 this.placement == Roo.SplitBar.TOP ? c2 : c1
23824 this.dragSpecs.startSize = size;
23825 this.dragSpecs.startPoint = [x, y];
23826 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23830 * @private Called after the drag operation by the DDProxy
23832 onEndProxyDrag : function(e){
23833 Roo.get(this.proxy).setDisplayed(false);
23834 var endPoint = Roo.lib.Event.getXY(e);
23836 this.overlay.hide();
23839 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23840 newSize = this.dragSpecs.startSize +
23841 (this.placement == Roo.SplitBar.LEFT ?
23842 endPoint[0] - this.dragSpecs.startPoint[0] :
23843 this.dragSpecs.startPoint[0] - endPoint[0]
23846 newSize = this.dragSpecs.startSize +
23847 (this.placement == Roo.SplitBar.TOP ?
23848 endPoint[1] - this.dragSpecs.startPoint[1] :
23849 this.dragSpecs.startPoint[1] - endPoint[1]
23852 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23853 if(newSize != this.dragSpecs.startSize){
23854 if(this.fireEvent('beforeapply', this, newSize) !== false){
23855 this.adapter.setElementSize(this, newSize);
23856 this.fireEvent("moved", this, newSize);
23857 this.fireEvent("resize", this, newSize);
23863 * Get the adapter this SplitBar uses
23864 * @return The adapter object
23866 getAdapter : function(){
23867 return this.adapter;
23871 * Set the adapter this SplitBar uses
23872 * @param {Object} adapter A SplitBar adapter object
23874 setAdapter : function(adapter){
23875 this.adapter = adapter;
23876 this.adapter.init(this);
23880 * Gets the minimum size for the resizing element
23881 * @return {Number} The minimum size
23883 getMinimumSize : function(){
23884 return this.minSize;
23888 * Sets the minimum size for the resizing element
23889 * @param {Number} minSize The minimum size
23891 setMinimumSize : function(minSize){
23892 this.minSize = minSize;
23896 * Gets the maximum size for the resizing element
23897 * @return {Number} The maximum size
23899 getMaximumSize : function(){
23900 return this.maxSize;
23904 * Sets the maximum size for the resizing element
23905 * @param {Number} maxSize The maximum size
23907 setMaximumSize : function(maxSize){
23908 this.maxSize = maxSize;
23912 * Sets the initialize size for the resizing element
23913 * @param {Number} size The initial size
23915 setCurrentSize : function(size){
23916 var oldAnimate = this.animate;
23917 this.animate = false;
23918 this.adapter.setElementSize(this, size);
23919 this.animate = oldAnimate;
23923 * Destroy this splitbar.
23924 * @param {Boolean} removeEl True to remove the element
23926 destroy : function(removeEl){
23928 this.shim.remove();
23931 this.proxy.parentNode.removeChild(this.proxy);
23939 * @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.
23941 Roo.SplitBar.createProxy = function(dir){
23942 var proxy = new Roo.Element(document.createElement("div"));
23943 proxy.unselectable();
23944 var cls = 'x-splitbar-proxy';
23945 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23946 document.body.appendChild(proxy.dom);
23951 * @class Roo.SplitBar.BasicLayoutAdapter
23952 * Default Adapter. It assumes the splitter and resizing element are not positioned
23953 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23955 Roo.SplitBar.BasicLayoutAdapter = function(){
23958 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23959 // do nothing for now
23960 init : function(s){
23964 * Called before drag operations to get the current size of the resizing element.
23965 * @param {Roo.SplitBar} s The SplitBar using this adapter
23967 getElementSize : function(s){
23968 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23969 return s.resizingEl.getWidth();
23971 return s.resizingEl.getHeight();
23976 * Called after drag operations to set the size of the resizing element.
23977 * @param {Roo.SplitBar} s The SplitBar using this adapter
23978 * @param {Number} newSize The new size to set
23979 * @param {Function} onComplete A function to be invoked when resizing is complete
23981 setElementSize : function(s, newSize, onComplete){
23982 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23984 s.resizingEl.setWidth(newSize);
23986 onComplete(s, newSize);
23989 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23994 s.resizingEl.setHeight(newSize);
23996 onComplete(s, newSize);
23999 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24006 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24007 * @extends Roo.SplitBar.BasicLayoutAdapter
24008 * Adapter that moves the splitter element to align with the resized sizing element.
24009 * Used with an absolute positioned SplitBar.
24010 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24011 * document.body, make sure you assign an id to the body element.
24013 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24014 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24015 this.container = Roo.get(container);
24018 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24019 init : function(s){
24020 this.basic.init(s);
24023 getElementSize : function(s){
24024 return this.basic.getElementSize(s);
24027 setElementSize : function(s, newSize, onComplete){
24028 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24031 moveSplitter : function(s){
24032 var yes = Roo.SplitBar;
24033 switch(s.placement){
24035 s.el.setX(s.resizingEl.getRight());
24038 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24041 s.el.setY(s.resizingEl.getBottom());
24044 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24051 * Orientation constant - Create a vertical SplitBar
24055 Roo.SplitBar.VERTICAL = 1;
24058 * Orientation constant - Create a horizontal SplitBar
24062 Roo.SplitBar.HORIZONTAL = 2;
24065 * Placement constant - The resizing element is to the left of the splitter element
24069 Roo.SplitBar.LEFT = 1;
24072 * Placement constant - The resizing element is to the right of the splitter element
24076 Roo.SplitBar.RIGHT = 2;
24079 * Placement constant - The resizing element is positioned above the splitter element
24083 Roo.SplitBar.TOP = 3;
24086 * Placement constant - The resizing element is positioned under splitter element
24090 Roo.SplitBar.BOTTOM = 4;
24093 * Ext JS Library 1.1.1
24094 * Copyright(c) 2006-2007, Ext JS, LLC.
24096 * Originally Released Under LGPL - original licence link has changed is not relivant.
24099 * <script type="text/javascript">
24104 * @extends Roo.util.Observable
24105 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24106 * This class also supports single and multi selection modes. <br>
24107 * Create a data model bound view:
24109 var store = new Roo.data.Store(...);
24111 var view = new Roo.View({
24113 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24115 singleSelect: true,
24116 selectedClass: "ydataview-selected",
24120 // listen for node click?
24121 view.on("click", function(vw, index, node, e){
24122 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24126 dataModel.load("foobar.xml");
24128 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24130 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24131 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24133 * Note: old style constructor is still suported (container, template, config)
24136 * Create a new View
24137 * @param {Object} config The config object
24140 Roo.View = function(config, depreciated_tpl, depreciated_config){
24142 if (typeof(depreciated_tpl) == 'undefined') {
24143 // new way.. - universal constructor.
24144 Roo.apply(this, config);
24145 this.el = Roo.get(this.el);
24148 this.el = Roo.get(config);
24149 this.tpl = depreciated_tpl;
24150 Roo.apply(this, depreciated_config);
24154 if(typeof(this.tpl) == "string"){
24155 this.tpl = new Roo.Template(this.tpl);
24157 // support xtype ctors..
24158 this.tpl = new Roo.factory(this.tpl, Roo);
24162 this.tpl.compile();
24169 * @event beforeclick
24170 * Fires before a click is processed. Returns false to cancel the default action.
24171 * @param {Roo.View} this
24172 * @param {Number} index The index of the target node
24173 * @param {HTMLElement} node The target node
24174 * @param {Roo.EventObject} e The raw event object
24176 "beforeclick" : true,
24179 * Fires when a template node is clicked.
24180 * @param {Roo.View} this
24181 * @param {Number} index The index of the target node
24182 * @param {HTMLElement} node The target node
24183 * @param {Roo.EventObject} e The raw event object
24188 * Fires when a template node is double clicked.
24189 * @param {Roo.View} this
24190 * @param {Number} index The index of the target node
24191 * @param {HTMLElement} node The target node
24192 * @param {Roo.EventObject} e The raw event object
24196 * @event contextmenu
24197 * Fires when a template node is right clicked.
24198 * @param {Roo.View} this
24199 * @param {Number} index The index of the target node
24200 * @param {HTMLElement} node The target node
24201 * @param {Roo.EventObject} e The raw event object
24203 "contextmenu" : true,
24205 * @event selectionchange
24206 * Fires when the selected nodes change.
24207 * @param {Roo.View} this
24208 * @param {Array} selections Array of the selected nodes
24210 "selectionchange" : true,
24213 * @event beforeselect
24214 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24215 * @param {Roo.View} this
24216 * @param {HTMLElement} node The node to be selected
24217 * @param {Array} selections Array of currently selected nodes
24219 "beforeselect" : true,
24221 * @event preparedata
24222 * Fires on every row to render, to allow you to change the data.
24223 * @param {Roo.View} this
24224 * @param {Object} data to be rendered (change this)
24226 "preparedata" : true
24230 "click": this.onClick,
24231 "dblclick": this.onDblClick,
24232 "contextmenu": this.onContextMenu,
24236 this.selections = [];
24238 this.cmp = new Roo.CompositeElementLite([]);
24240 this.store = Roo.factory(this.store, Roo.data);
24241 this.setStore(this.store, true);
24243 Roo.View.superclass.constructor.call(this);
24246 Roo.extend(Roo.View, Roo.util.Observable, {
24249 * @cfg {Roo.data.Store} store Data store to load data from.
24254 * @cfg {String|Roo.Element} el The container element.
24259 * @cfg {String|Roo.Template} tpl The template used by this View
24263 * @cfg {String} dataName the named area of the template to use as the data area
24264 * Works with domtemplates roo-name="name"
24268 * @cfg {String} selectedClass The css class to add to selected nodes
24270 selectedClass : "x-view-selected",
24272 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24277 * @cfg {String} text to display on mask (default Loading)
24281 * @cfg {Boolean} multiSelect Allow multiple selection
24283 multiSelect : false,
24285 * @cfg {Boolean} singleSelect Allow single selection
24287 singleSelect: false,
24290 * @cfg {Boolean} toggleSelect - selecting
24292 toggleSelect : false,
24295 * Returns the element this view is bound to.
24296 * @return {Roo.Element}
24298 getEl : function(){
24303 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24305 refresh : function(){
24308 // if we are using something like 'domtemplate', then
24309 // the what gets used is:
24310 // t.applySubtemplate(NAME, data, wrapping data..)
24311 // the outer template then get' applied with
24312 // the store 'extra data'
24313 // and the body get's added to the
24314 // roo-name="data" node?
24315 // <span class='roo-tpl-{name}'></span> ?????
24319 this.clearSelections();
24320 this.el.update("");
24322 var records = this.store.getRange();
24323 if(records.length < 1) {
24325 // is this valid?? = should it render a template??
24327 this.el.update(this.emptyText);
24331 if (this.dataName) {
24332 this.el.update(t.apply(this.store.meta)); //????
24333 el = this.el.child('.roo-tpl-' + this.dataName);
24336 for(var i = 0, len = records.length; i < len; i++){
24337 var data = this.prepareData(records[i].data, i, records[i]);
24338 this.fireEvent("preparedata", this, data, i, records[i]);
24339 html[html.length] = Roo.util.Format.trim(
24341 t.applySubtemplate(this.dataName, data, this.store.meta) :
24348 el.update(html.join(""));
24349 this.nodes = el.dom.childNodes;
24350 this.updateIndexes(0);
24354 * Function to override to reformat the data that is sent to
24355 * the template for each node.
24356 * DEPRICATED - use the preparedata event handler.
24357 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24358 * a JSON object for an UpdateManager bound view).
24360 prepareData : function(data, index, record)
24362 this.fireEvent("preparedata", this, data, index, record);
24366 onUpdate : function(ds, record){
24367 this.clearSelections();
24368 var index = this.store.indexOf(record);
24369 var n = this.nodes[index];
24370 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24371 n.parentNode.removeChild(n);
24372 this.updateIndexes(index, index);
24378 onAdd : function(ds, records, index)
24380 this.clearSelections();
24381 if(this.nodes.length == 0){
24385 var n = this.nodes[index];
24386 for(var i = 0, len = records.length; i < len; i++){
24387 var d = this.prepareData(records[i].data, i, records[i]);
24389 this.tpl.insertBefore(n, d);
24392 this.tpl.append(this.el, d);
24395 this.updateIndexes(index);
24398 onRemove : function(ds, record, index){
24399 this.clearSelections();
24400 var el = this.dataName ?
24401 this.el.child('.roo-tpl-' + this.dataName) :
24403 el.dom.removeChild(this.nodes[index]);
24404 this.updateIndexes(index);
24408 * Refresh an individual node.
24409 * @param {Number} index
24411 refreshNode : function(index){
24412 this.onUpdate(this.store, this.store.getAt(index));
24415 updateIndexes : function(startIndex, endIndex){
24416 var ns = this.nodes;
24417 startIndex = startIndex || 0;
24418 endIndex = endIndex || ns.length - 1;
24419 for(var i = startIndex; i <= endIndex; i++){
24420 ns[i].nodeIndex = i;
24425 * Changes the data store this view uses and refresh the view.
24426 * @param {Store} store
24428 setStore : function(store, initial){
24429 if(!initial && this.store){
24430 this.store.un("datachanged", this.refresh);
24431 this.store.un("add", this.onAdd);
24432 this.store.un("remove", this.onRemove);
24433 this.store.un("update", this.onUpdate);
24434 this.store.un("clear", this.refresh);
24435 this.store.un("beforeload", this.onBeforeLoad);
24436 this.store.un("load", this.onLoad);
24437 this.store.un("loadexception", this.onLoad);
24441 store.on("datachanged", this.refresh, this);
24442 store.on("add", this.onAdd, this);
24443 store.on("remove", this.onRemove, this);
24444 store.on("update", this.onUpdate, this);
24445 store.on("clear", this.refresh, this);
24446 store.on("beforeload", this.onBeforeLoad, this);
24447 store.on("load", this.onLoad, this);
24448 store.on("loadexception", this.onLoad, this);
24456 * onbeforeLoad - masks the loading area.
24459 onBeforeLoad : function()
24461 this.el.update("");
24462 this.el.mask(this.mask ? this.mask : "Loading" );
24464 onLoad : function ()
24471 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24472 * @param {HTMLElement} node
24473 * @return {HTMLElement} The template node
24475 findItemFromChild : function(node){
24476 var el = this.dataName ?
24477 this.el.child('.roo-tpl-' + this.dataName,true) :
24480 if(!node || node.parentNode == el){
24483 var p = node.parentNode;
24484 while(p && p != el){
24485 if(p.parentNode == el){
24494 onClick : function(e){
24495 var item = this.findItemFromChild(e.getTarget());
24497 var index = this.indexOf(item);
24498 if(this.onItemClick(item, index, e) !== false){
24499 this.fireEvent("click", this, index, item, e);
24502 this.clearSelections();
24507 onContextMenu : function(e){
24508 var item = this.findItemFromChild(e.getTarget());
24510 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24515 onDblClick : function(e){
24516 var item = this.findItemFromChild(e.getTarget());
24518 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24522 onItemClick : function(item, index, e)
24524 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24527 if (this.toggleSelect) {
24528 var m = this.isSelected(item) ? 'unselect' : 'select';
24531 _t[m](item, true, false);
24534 if(this.multiSelect || this.singleSelect){
24535 if(this.multiSelect && e.shiftKey && this.lastSelection){
24536 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24538 this.select(item, this.multiSelect && e.ctrlKey);
24539 this.lastSelection = item;
24541 e.preventDefault();
24547 * Get the number of selected nodes.
24550 getSelectionCount : function(){
24551 return this.selections.length;
24555 * Get the currently selected nodes.
24556 * @return {Array} An array of HTMLElements
24558 getSelectedNodes : function(){
24559 return this.selections;
24563 * Get the indexes of the selected nodes.
24566 getSelectedIndexes : function(){
24567 var indexes = [], s = this.selections;
24568 for(var i = 0, len = s.length; i < len; i++){
24569 indexes.push(s[i].nodeIndex);
24575 * Clear all selections
24576 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24578 clearSelections : function(suppressEvent){
24579 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24580 this.cmp.elements = this.selections;
24581 this.cmp.removeClass(this.selectedClass);
24582 this.selections = [];
24583 if(!suppressEvent){
24584 this.fireEvent("selectionchange", this, this.selections);
24590 * Returns true if the passed node is selected
24591 * @param {HTMLElement/Number} node The node or node index
24592 * @return {Boolean}
24594 isSelected : function(node){
24595 var s = this.selections;
24599 node = this.getNode(node);
24600 return s.indexOf(node) !== -1;
24605 * @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
24606 * @param {Boolean} keepExisting (optional) true to keep existing selections
24607 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24609 select : function(nodeInfo, keepExisting, suppressEvent){
24610 if(nodeInfo instanceof Array){
24612 this.clearSelections(true);
24614 for(var i = 0, len = nodeInfo.length; i < len; i++){
24615 this.select(nodeInfo[i], true, true);
24619 var node = this.getNode(nodeInfo);
24620 if(!node || this.isSelected(node)){
24621 return; // already selected.
24624 this.clearSelections(true);
24626 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24627 Roo.fly(node).addClass(this.selectedClass);
24628 this.selections.push(node);
24629 if(!suppressEvent){
24630 this.fireEvent("selectionchange", this, this.selections);
24638 * @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
24639 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24640 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24642 unselect : function(nodeInfo, keepExisting, suppressEvent)
24644 if(nodeInfo instanceof Array){
24645 Roo.each(this.selections, function(s) {
24646 this.unselect(s, nodeInfo);
24650 var node = this.getNode(nodeInfo);
24651 if(!node || !this.isSelected(node)){
24652 Roo.log("not selected");
24653 return; // not selected.
24657 Roo.each(this.selections, function(s) {
24659 Roo.fly(node).removeClass(this.selectedClass);
24666 this.selections= ns;
24667 this.fireEvent("selectionchange", this, this.selections);
24671 * Gets a template node.
24672 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24673 * @return {HTMLElement} The node or null if it wasn't found
24675 getNode : function(nodeInfo){
24676 if(typeof nodeInfo == "string"){
24677 return document.getElementById(nodeInfo);
24678 }else if(typeof nodeInfo == "number"){
24679 return this.nodes[nodeInfo];
24685 * Gets a range template nodes.
24686 * @param {Number} startIndex
24687 * @param {Number} endIndex
24688 * @return {Array} An array of nodes
24690 getNodes : function(start, end){
24691 var ns = this.nodes;
24692 start = start || 0;
24693 end = typeof end == "undefined" ? ns.length - 1 : end;
24696 for(var i = start; i <= end; i++){
24700 for(var i = start; i >= end; i--){
24708 * Finds the index of the passed node
24709 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24710 * @return {Number} The index of the node or -1
24712 indexOf : function(node){
24713 node = this.getNode(node);
24714 if(typeof node.nodeIndex == "number"){
24715 return node.nodeIndex;
24717 var ns = this.nodes;
24718 for(var i = 0, len = ns.length; i < len; i++){
24728 * Ext JS Library 1.1.1
24729 * Copyright(c) 2006-2007, Ext JS, LLC.
24731 * Originally Released Under LGPL - original licence link has changed is not relivant.
24734 * <script type="text/javascript">
24738 * @class Roo.JsonView
24739 * @extends Roo.View
24740 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24742 var view = new Roo.JsonView({
24743 container: "my-element",
24744 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24749 // listen for node click?
24750 view.on("click", function(vw, index, node, e){
24751 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24754 // direct load of JSON data
24755 view.load("foobar.php");
24757 // Example from my blog list
24758 var tpl = new Roo.Template(
24759 '<div class="entry">' +
24760 '<a class="entry-title" href="{link}">{title}</a>' +
24761 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24762 "</div><hr />"
24765 var moreView = new Roo.JsonView({
24766 container : "entry-list",
24770 moreView.on("beforerender", this.sortEntries, this);
24772 url: "/blog/get-posts.php",
24773 params: "allposts=true",
24774 text: "Loading Blog Entries..."
24778 * Note: old code is supported with arguments : (container, template, config)
24782 * Create a new JsonView
24784 * @param {Object} config The config object
24787 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24790 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24792 var um = this.el.getUpdateManager();
24793 um.setRenderer(this);
24794 um.on("update", this.onLoad, this);
24795 um.on("failure", this.onLoadException, this);
24798 * @event beforerender
24799 * Fires before rendering of the downloaded JSON data.
24800 * @param {Roo.JsonView} this
24801 * @param {Object} data The JSON data loaded
24805 * Fires when data is loaded.
24806 * @param {Roo.JsonView} this
24807 * @param {Object} data The JSON data loaded
24808 * @param {Object} response The raw Connect response object
24811 * @event loadexception
24812 * Fires when loading fails.
24813 * @param {Roo.JsonView} this
24814 * @param {Object} response The raw Connect response object
24817 'beforerender' : true,
24819 'loadexception' : true
24822 Roo.extend(Roo.JsonView, Roo.View, {
24824 * @type {String} The root property in the loaded JSON object that contains the data
24829 * Refreshes the view.
24831 refresh : function(){
24832 this.clearSelections();
24833 this.el.update("");
24835 var o = this.jsonData;
24836 if(o && o.length > 0){
24837 for(var i = 0, len = o.length; i < len; i++){
24838 var data = this.prepareData(o[i], i, o);
24839 html[html.length] = this.tpl.apply(data);
24842 html.push(this.emptyText);
24844 this.el.update(html.join(""));
24845 this.nodes = this.el.dom.childNodes;
24846 this.updateIndexes(0);
24850 * 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.
24851 * @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:
24854 url: "your-url.php",
24855 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24856 callback: yourFunction,
24857 scope: yourObject, //(optional scope)
24860 text: "Loading...",
24865 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24866 * 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.
24867 * @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}
24868 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24869 * @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.
24872 var um = this.el.getUpdateManager();
24873 um.update.apply(um, arguments);
24876 render : function(el, response){
24877 this.clearSelections();
24878 this.el.update("");
24881 o = Roo.util.JSON.decode(response.responseText);
24884 o = o[this.jsonRoot];
24889 * The current JSON data or null
24892 this.beforeRender();
24897 * Get the number of records in the current JSON dataset
24900 getCount : function(){
24901 return this.jsonData ? this.jsonData.length : 0;
24905 * Returns the JSON object for the specified node(s)
24906 * @param {HTMLElement/Array} node The node or an array of nodes
24907 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24908 * you get the JSON object for the node
24910 getNodeData : function(node){
24911 if(node instanceof Array){
24913 for(var i = 0, len = node.length; i < len; i++){
24914 data.push(this.getNodeData(node[i]));
24918 return this.jsonData[this.indexOf(node)] || null;
24921 beforeRender : function(){
24922 this.snapshot = this.jsonData;
24924 this.sort.apply(this, this.sortInfo);
24926 this.fireEvent("beforerender", this, this.jsonData);
24929 onLoad : function(el, o){
24930 this.fireEvent("load", this, this.jsonData, o);
24933 onLoadException : function(el, o){
24934 this.fireEvent("loadexception", this, o);
24938 * Filter the data by a specific property.
24939 * @param {String} property A property on your JSON objects
24940 * @param {String/RegExp} value Either string that the property values
24941 * should start with, or a RegExp to test against the property
24943 filter : function(property, value){
24946 var ss = this.snapshot;
24947 if(typeof value == "string"){
24948 var vlen = value.length;
24950 this.clearFilter();
24953 value = value.toLowerCase();
24954 for(var i = 0, len = ss.length; i < len; i++){
24956 if(o[property].substr(0, vlen).toLowerCase() == value){
24960 } else if(value.exec){ // regex?
24961 for(var i = 0, len = ss.length; i < len; i++){
24963 if(value.test(o[property])){
24970 this.jsonData = data;
24976 * Filter by a function. The passed function will be called with each
24977 * object in the current dataset. If the function returns true the value is kept,
24978 * otherwise it is filtered.
24979 * @param {Function} fn
24980 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24982 filterBy : function(fn, scope){
24985 var ss = this.snapshot;
24986 for(var i = 0, len = ss.length; i < len; i++){
24988 if(fn.call(scope || this, o)){
24992 this.jsonData = data;
24998 * Clears the current filter.
25000 clearFilter : function(){
25001 if(this.snapshot && this.jsonData != this.snapshot){
25002 this.jsonData = this.snapshot;
25009 * Sorts the data for this view and refreshes it.
25010 * @param {String} property A property on your JSON objects to sort on
25011 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25012 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25014 sort : function(property, dir, sortType){
25015 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25018 var dsc = dir && dir.toLowerCase() == "desc";
25019 var f = function(o1, o2){
25020 var v1 = sortType ? sortType(o1[p]) : o1[p];
25021 var v2 = sortType ? sortType(o2[p]) : o2[p];
25024 return dsc ? +1 : -1;
25025 } else if(v1 > v2){
25026 return dsc ? -1 : +1;
25031 this.jsonData.sort(f);
25033 if(this.jsonData != this.snapshot){
25034 this.snapshot.sort(f);
25040 * Ext JS Library 1.1.1
25041 * Copyright(c) 2006-2007, Ext JS, LLC.
25043 * Originally Released Under LGPL - original licence link has changed is not relivant.
25046 * <script type="text/javascript">
25051 * @class Roo.ColorPalette
25052 * @extends Roo.Component
25053 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25054 * Here's an example of typical usage:
25056 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25057 cp.render('my-div');
25059 cp.on('select', function(palette, selColor){
25060 // do something with selColor
25064 * Create a new ColorPalette
25065 * @param {Object} config The config object
25067 Roo.ColorPalette = function(config){
25068 Roo.ColorPalette.superclass.constructor.call(this, config);
25072 * Fires when a color is selected
25073 * @param {ColorPalette} this
25074 * @param {String} color The 6-digit color hex code (without the # symbol)
25080 this.on("select", this.handler, this.scope, true);
25083 Roo.extend(Roo.ColorPalette, Roo.Component, {
25085 * @cfg {String} itemCls
25086 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25088 itemCls : "x-color-palette",
25090 * @cfg {String} value
25091 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25092 * the hex codes are case-sensitive.
25095 clickEvent:'click',
25097 ctype: "Roo.ColorPalette",
25100 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25102 allowReselect : false,
25105 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25106 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25107 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25108 * of colors with the width setting until the box is symmetrical.</p>
25109 * <p>You can override individual colors if needed:</p>
25111 var cp = new Roo.ColorPalette();
25112 cp.colors[0] = "FF0000"; // change the first box to red
25115 Or you can provide a custom array of your own for complete control:
25117 var cp = new Roo.ColorPalette();
25118 cp.colors = ["000000", "993300", "333300"];
25123 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25124 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25125 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25126 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25127 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25131 onRender : function(container, position){
25132 var t = new Roo.MasterTemplate(
25133 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25135 var c = this.colors;
25136 for(var i = 0, len = c.length; i < len; i++){
25139 var el = document.createElement("div");
25140 el.className = this.itemCls;
25142 container.dom.insertBefore(el, position);
25143 this.el = Roo.get(el);
25144 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25145 if(this.clickEvent != 'click'){
25146 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25151 afterRender : function(){
25152 Roo.ColorPalette.superclass.afterRender.call(this);
25154 var s = this.value;
25161 handleClick : function(e, t){
25162 e.preventDefault();
25163 if(!this.disabled){
25164 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25165 this.select(c.toUpperCase());
25170 * Selects the specified color in the palette (fires the select event)
25171 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25173 select : function(color){
25174 color = color.replace("#", "");
25175 if(color != this.value || this.allowReselect){
25178 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25180 el.child("a.color-"+color).addClass("x-color-palette-sel");
25181 this.value = color;
25182 this.fireEvent("select", this, color);
25187 * Ext JS Library 1.1.1
25188 * Copyright(c) 2006-2007, Ext JS, LLC.
25190 * Originally Released Under LGPL - original licence link has changed is not relivant.
25193 * <script type="text/javascript">
25197 * @class Roo.DatePicker
25198 * @extends Roo.Component
25199 * Simple date picker class.
25201 * Create a new DatePicker
25202 * @param {Object} config The config object
25204 Roo.DatePicker = function(config){
25205 Roo.DatePicker.superclass.constructor.call(this, config);
25207 this.value = config && config.value ?
25208 config.value.clearTime() : new Date().clearTime();
25213 * Fires when a date is selected
25214 * @param {DatePicker} this
25215 * @param {Date} date The selected date
25219 * @event monthchange
25220 * Fires when the displayed month changes
25221 * @param {DatePicker} this
25222 * @param {Date} date The selected month
25224 'monthchange': true
25228 this.on("select", this.handler, this.scope || this);
25230 // build the disabledDatesRE
25231 if(!this.disabledDatesRE && this.disabledDates){
25232 var dd = this.disabledDates;
25234 for(var i = 0; i < dd.length; i++){
25236 if(i != dd.length-1) re += "|";
25238 this.disabledDatesRE = new RegExp(re + ")");
25242 Roo.extend(Roo.DatePicker, Roo.Component, {
25244 * @cfg {String} todayText
25245 * The text to display on the button that selects the current date (defaults to "Today")
25247 todayText : "Today",
25249 * @cfg {String} okText
25250 * The text to display on the ok button
25252 okText : " OK ", //   to give the user extra clicking room
25254 * @cfg {String} cancelText
25255 * The text to display on the cancel button
25257 cancelText : "Cancel",
25259 * @cfg {String} todayTip
25260 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25262 todayTip : "{0} (Spacebar)",
25264 * @cfg {Date} minDate
25265 * Minimum allowable date (JavaScript date object, defaults to null)
25269 * @cfg {Date} maxDate
25270 * Maximum allowable date (JavaScript date object, defaults to null)
25274 * @cfg {String} minText
25275 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25277 minText : "This date is before the minimum date",
25279 * @cfg {String} maxText
25280 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25282 maxText : "This date is after the maximum date",
25284 * @cfg {String} format
25285 * The default date format string which can be overriden for localization support. The format must be
25286 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25290 * @cfg {Array} disabledDays
25291 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25293 disabledDays : null,
25295 * @cfg {String} disabledDaysText
25296 * The tooltip to display when the date falls on a disabled day (defaults to "")
25298 disabledDaysText : "",
25300 * @cfg {RegExp} disabledDatesRE
25301 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25303 disabledDatesRE : null,
25305 * @cfg {String} disabledDatesText
25306 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25308 disabledDatesText : "",
25310 * @cfg {Boolean} constrainToViewport
25311 * True to constrain the date picker to the viewport (defaults to true)
25313 constrainToViewport : true,
25315 * @cfg {Array} monthNames
25316 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25318 monthNames : Date.monthNames,
25320 * @cfg {Array} dayNames
25321 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25323 dayNames : Date.dayNames,
25325 * @cfg {String} nextText
25326 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25328 nextText: 'Next Month (Control+Right)',
25330 * @cfg {String} prevText
25331 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25333 prevText: 'Previous Month (Control+Left)',
25335 * @cfg {String} monthYearText
25336 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25338 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25340 * @cfg {Number} startDay
25341 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25345 * @cfg {Bool} showClear
25346 * Show a clear button (usefull for date form elements that can be blank.)
25352 * Sets the value of the date field
25353 * @param {Date} value The date to set
25355 setValue : function(value){
25356 var old = this.value;
25358 if (typeof(value) == 'string') {
25360 value = Date.parseDate(value, this.format);
25363 value = new Date();
25366 this.value = value.clearTime(true);
25368 this.update(this.value);
25373 * Gets the current selected value of the date field
25374 * @return {Date} The selected date
25376 getValue : function(){
25381 focus : function(){
25383 this.update(this.activeDate);
25388 onRender : function(container, position){
25391 '<table cellspacing="0">',
25392 '<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>',
25393 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25394 var dn = this.dayNames;
25395 for(var i = 0; i < 7; i++){
25396 var d = this.startDay+i;
25400 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25402 m[m.length] = "</tr></thead><tbody><tr>";
25403 for(var i = 0; i < 42; i++) {
25404 if(i % 7 == 0 && i != 0){
25405 m[m.length] = "</tr><tr>";
25407 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25409 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25410 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25412 var el = document.createElement("div");
25413 el.className = "x-date-picker";
25414 el.innerHTML = m.join("");
25416 container.dom.insertBefore(el, position);
25418 this.el = Roo.get(el);
25419 this.eventEl = Roo.get(el.firstChild);
25421 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25422 handler: this.showPrevMonth,
25424 preventDefault:true,
25428 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25429 handler: this.showNextMonth,
25431 preventDefault:true,
25435 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25437 this.monthPicker = this.el.down('div.x-date-mp');
25438 this.monthPicker.enableDisplayMode('block');
25440 var kn = new Roo.KeyNav(this.eventEl, {
25441 "left" : function(e){
25443 this.showPrevMonth() :
25444 this.update(this.activeDate.add("d", -1));
25447 "right" : function(e){
25449 this.showNextMonth() :
25450 this.update(this.activeDate.add("d", 1));
25453 "up" : function(e){
25455 this.showNextYear() :
25456 this.update(this.activeDate.add("d", -7));
25459 "down" : function(e){
25461 this.showPrevYear() :
25462 this.update(this.activeDate.add("d", 7));
25465 "pageUp" : function(e){
25466 this.showNextMonth();
25469 "pageDown" : function(e){
25470 this.showPrevMonth();
25473 "enter" : function(e){
25474 e.stopPropagation();
25481 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25483 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25485 this.el.unselectable();
25487 this.cells = this.el.select("table.x-date-inner tbody td");
25488 this.textNodes = this.el.query("table.x-date-inner tbody span");
25490 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25492 tooltip: this.monthYearText
25495 this.mbtn.on('click', this.showMonthPicker, this);
25496 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25499 var today = (new Date()).dateFormat(this.format);
25501 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25502 if (this.showClear) {
25503 baseTb.add( new Roo.Toolbar.Fill());
25506 text: String.format(this.todayText, today),
25507 tooltip: String.format(this.todayTip, today),
25508 handler: this.selectToday,
25512 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25515 if (this.showClear) {
25517 baseTb.add( new Roo.Toolbar.Fill());
25520 cls: 'x-btn-icon x-btn-clear',
25521 handler: function() {
25523 this.fireEvent("select", this, '');
25533 this.update(this.value);
25536 createMonthPicker : function(){
25537 if(!this.monthPicker.dom.firstChild){
25538 var buf = ['<table border="0" cellspacing="0">'];
25539 for(var i = 0; i < 6; i++){
25541 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25542 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25544 '<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>' :
25545 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25549 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25551 '</button><button type="button" class="x-date-mp-cancel">',
25553 '</button></td></tr>',
25556 this.monthPicker.update(buf.join(''));
25557 this.monthPicker.on('click', this.onMonthClick, this);
25558 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25560 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25561 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25563 this.mpMonths.each(function(m, a, i){
25566 m.dom.xmonth = 5 + Math.round(i * .5);
25568 m.dom.xmonth = Math.round((i-1) * .5);
25574 showMonthPicker : function(){
25575 this.createMonthPicker();
25576 var size = this.el.getSize();
25577 this.monthPicker.setSize(size);
25578 this.monthPicker.child('table').setSize(size);
25580 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25581 this.updateMPMonth(this.mpSelMonth);
25582 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25583 this.updateMPYear(this.mpSelYear);
25585 this.monthPicker.slideIn('t', {duration:.2});
25588 updateMPYear : function(y){
25590 var ys = this.mpYears.elements;
25591 for(var i = 1; i <= 10; i++){
25592 var td = ys[i-1], y2;
25594 y2 = y + Math.round(i * .5);
25595 td.firstChild.innerHTML = y2;
25598 y2 = y - (5-Math.round(i * .5));
25599 td.firstChild.innerHTML = y2;
25602 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25606 updateMPMonth : function(sm){
25607 this.mpMonths.each(function(m, a, i){
25608 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25612 selectMPMonth: function(m){
25616 onMonthClick : function(e, t){
25618 var el = new Roo.Element(t), pn;
25619 if(el.is('button.x-date-mp-cancel')){
25620 this.hideMonthPicker();
25622 else if(el.is('button.x-date-mp-ok')){
25623 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25624 this.hideMonthPicker();
25626 else if(pn = el.up('td.x-date-mp-month', 2)){
25627 this.mpMonths.removeClass('x-date-mp-sel');
25628 pn.addClass('x-date-mp-sel');
25629 this.mpSelMonth = pn.dom.xmonth;
25631 else if(pn = el.up('td.x-date-mp-year', 2)){
25632 this.mpYears.removeClass('x-date-mp-sel');
25633 pn.addClass('x-date-mp-sel');
25634 this.mpSelYear = pn.dom.xyear;
25636 else if(el.is('a.x-date-mp-prev')){
25637 this.updateMPYear(this.mpyear-10);
25639 else if(el.is('a.x-date-mp-next')){
25640 this.updateMPYear(this.mpyear+10);
25644 onMonthDblClick : function(e, t){
25646 var el = new Roo.Element(t), pn;
25647 if(pn = el.up('td.x-date-mp-month', 2)){
25648 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25649 this.hideMonthPicker();
25651 else if(pn = el.up('td.x-date-mp-year', 2)){
25652 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25653 this.hideMonthPicker();
25657 hideMonthPicker : function(disableAnim){
25658 if(this.monthPicker){
25659 if(disableAnim === true){
25660 this.monthPicker.hide();
25662 this.monthPicker.slideOut('t', {duration:.2});
25668 showPrevMonth : function(e){
25669 this.update(this.activeDate.add("mo", -1));
25673 showNextMonth : function(e){
25674 this.update(this.activeDate.add("mo", 1));
25678 showPrevYear : function(){
25679 this.update(this.activeDate.add("y", -1));
25683 showNextYear : function(){
25684 this.update(this.activeDate.add("y", 1));
25688 handleMouseWheel : function(e){
25689 var delta = e.getWheelDelta();
25691 this.showPrevMonth();
25693 } else if(delta < 0){
25694 this.showNextMonth();
25700 handleDateClick : function(e, t){
25702 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25703 this.setValue(new Date(t.dateValue));
25704 this.fireEvent("select", this, this.value);
25709 selectToday : function(){
25710 this.setValue(new Date().clearTime());
25711 this.fireEvent("select", this, this.value);
25715 update : function(date)
25717 var vd = this.activeDate;
25718 this.activeDate = date;
25720 var t = date.getTime();
25721 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25722 this.cells.removeClass("x-date-selected");
25723 this.cells.each(function(c){
25724 if(c.dom.firstChild.dateValue == t){
25725 c.addClass("x-date-selected");
25726 setTimeout(function(){
25727 try{c.dom.firstChild.focus();}catch(e){}
25736 var days = date.getDaysInMonth();
25737 var firstOfMonth = date.getFirstDateOfMonth();
25738 var startingPos = firstOfMonth.getDay()-this.startDay;
25740 if(startingPos <= this.startDay){
25744 var pm = date.add("mo", -1);
25745 var prevStart = pm.getDaysInMonth()-startingPos;
25747 var cells = this.cells.elements;
25748 var textEls = this.textNodes;
25749 days += startingPos;
25751 // convert everything to numbers so it's fast
25752 var day = 86400000;
25753 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25754 var today = new Date().clearTime().getTime();
25755 var sel = date.clearTime().getTime();
25756 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25757 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25758 var ddMatch = this.disabledDatesRE;
25759 var ddText = this.disabledDatesText;
25760 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25761 var ddaysText = this.disabledDaysText;
25762 var format = this.format;
25764 var setCellClass = function(cal, cell){
25766 var t = d.getTime();
25767 cell.firstChild.dateValue = t;
25769 cell.className += " x-date-today";
25770 cell.title = cal.todayText;
25773 cell.className += " x-date-selected";
25774 setTimeout(function(){
25775 try{cell.firstChild.focus();}catch(e){}
25780 cell.className = " x-date-disabled";
25781 cell.title = cal.minText;
25785 cell.className = " x-date-disabled";
25786 cell.title = cal.maxText;
25790 if(ddays.indexOf(d.getDay()) != -1){
25791 cell.title = ddaysText;
25792 cell.className = " x-date-disabled";
25795 if(ddMatch && format){
25796 var fvalue = d.dateFormat(format);
25797 if(ddMatch.test(fvalue)){
25798 cell.title = ddText.replace("%0", fvalue);
25799 cell.className = " x-date-disabled";
25805 for(; i < startingPos; i++) {
25806 textEls[i].innerHTML = (++prevStart);
25807 d.setDate(d.getDate()+1);
25808 cells[i].className = "x-date-prevday";
25809 setCellClass(this, cells[i]);
25811 for(; i < days; i++){
25812 intDay = i - startingPos + 1;
25813 textEls[i].innerHTML = (intDay);
25814 d.setDate(d.getDate()+1);
25815 cells[i].className = "x-date-active";
25816 setCellClass(this, cells[i]);
25819 for(; i < 42; i++) {
25820 textEls[i].innerHTML = (++extraDays);
25821 d.setDate(d.getDate()+1);
25822 cells[i].className = "x-date-nextday";
25823 setCellClass(this, cells[i]);
25826 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25827 this.fireEvent('monthchange', this, date);
25829 if(!this.internalRender){
25830 var main = this.el.dom.firstChild;
25831 var w = main.offsetWidth;
25832 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25833 Roo.fly(main).setWidth(w);
25834 this.internalRender = true;
25835 // opera does not respect the auto grow header center column
25836 // then, after it gets a width opera refuses to recalculate
25837 // without a second pass
25838 if(Roo.isOpera && !this.secondPass){
25839 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25840 this.secondPass = true;
25841 this.update.defer(10, this, [date]);
25849 * Ext JS Library 1.1.1
25850 * Copyright(c) 2006-2007, Ext JS, LLC.
25852 * Originally Released Under LGPL - original licence link has changed is not relivant.
25855 * <script type="text/javascript">
25858 * @class Roo.TabPanel
25859 * @extends Roo.util.Observable
25860 * A lightweight tab container.
25864 // basic tabs 1, built from existing content
25865 var tabs = new Roo.TabPanel("tabs1");
25866 tabs.addTab("script", "View Script");
25867 tabs.addTab("markup", "View Markup");
25868 tabs.activate("script");
25870 // more advanced tabs, built from javascript
25871 var jtabs = new Roo.TabPanel("jtabs");
25872 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25874 // set up the UpdateManager
25875 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25876 var updater = tab2.getUpdateManager();
25877 updater.setDefaultUrl("ajax1.htm");
25878 tab2.on('activate', updater.refresh, updater, true);
25880 // Use setUrl for Ajax loading
25881 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25882 tab3.setUrl("ajax2.htm", null, true);
25885 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25888 jtabs.activate("jtabs-1");
25891 * Create a new TabPanel.
25892 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25893 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25895 Roo.TabPanel = function(container, config){
25897 * The container element for this TabPanel.
25898 * @type Roo.Element
25900 this.el = Roo.get(container, true);
25902 if(typeof config == "boolean"){
25903 this.tabPosition = config ? "bottom" : "top";
25905 Roo.apply(this, config);
25908 if(this.tabPosition == "bottom"){
25909 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25910 this.el.addClass("x-tabs-bottom");
25912 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25913 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25914 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25916 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25918 if(this.tabPosition != "bottom"){
25919 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25920 * @type Roo.Element
25922 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25923 this.el.addClass("x-tabs-top");
25927 this.bodyEl.setStyle("position", "relative");
25929 this.active = null;
25930 this.activateDelegate = this.activate.createDelegate(this);
25935 * Fires when the active tab changes
25936 * @param {Roo.TabPanel} this
25937 * @param {Roo.TabPanelItem} activePanel The new active tab
25941 * @event beforetabchange
25942 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25943 * @param {Roo.TabPanel} this
25944 * @param {Object} e Set cancel to true on this object to cancel the tab change
25945 * @param {Roo.TabPanelItem} tab The tab being changed to
25947 "beforetabchange" : true
25950 Roo.EventManager.onWindowResize(this.onResize, this);
25951 this.cpad = this.el.getPadding("lr");
25952 this.hiddenCount = 0;
25955 // toolbar on the tabbar support...
25956 if (this.toolbar) {
25957 var tcfg = this.toolbar;
25958 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25959 this.toolbar = new Roo.Toolbar(tcfg);
25960 if (Roo.isSafari) {
25961 var tbl = tcfg.container.child('table', true);
25962 tbl.setAttribute('width', '100%');
25969 Roo.TabPanel.superclass.constructor.call(this);
25972 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25974 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25976 tabPosition : "top",
25978 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25980 currentTabWidth : 0,
25982 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25986 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25990 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25992 preferredTabWidth : 175,
25994 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25996 resizeTabs : false,
25998 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26000 monitorResize : true,
26002 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26007 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26008 * @param {String} id The id of the div to use <b>or create</b>
26009 * @param {String} text The text for the tab
26010 * @param {String} content (optional) Content to put in the TabPanelItem body
26011 * @param {Boolean} closable (optional) True to create a close icon on the tab
26012 * @return {Roo.TabPanelItem} The created TabPanelItem
26014 addTab : function(id, text, content, closable){
26015 var item = new Roo.TabPanelItem(this, id, text, closable);
26016 this.addTabItem(item);
26018 item.setContent(content);
26024 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26025 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26026 * @return {Roo.TabPanelItem}
26028 getTab : function(id){
26029 return this.items[id];
26033 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26034 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26036 hideTab : function(id){
26037 var t = this.items[id];
26040 this.hiddenCount++;
26041 this.autoSizeTabs();
26046 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26047 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26049 unhideTab : function(id){
26050 var t = this.items[id];
26052 t.setHidden(false);
26053 this.hiddenCount--;
26054 this.autoSizeTabs();
26059 * Adds an existing {@link Roo.TabPanelItem}.
26060 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26062 addTabItem : function(item){
26063 this.items[item.id] = item;
26064 this.items.push(item);
26065 if(this.resizeTabs){
26066 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26067 this.autoSizeTabs();
26074 * Removes a {@link Roo.TabPanelItem}.
26075 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26077 removeTab : function(id){
26078 var items = this.items;
26079 var tab = items[id];
26080 if(!tab) { return; }
26081 var index = items.indexOf(tab);
26082 if(this.active == tab && items.length > 1){
26083 var newTab = this.getNextAvailable(index);
26088 this.stripEl.dom.removeChild(tab.pnode.dom);
26089 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26090 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26092 items.splice(index, 1);
26093 delete this.items[tab.id];
26094 tab.fireEvent("close", tab);
26095 tab.purgeListeners();
26096 this.autoSizeTabs();
26099 getNextAvailable : function(start){
26100 var items = this.items;
26102 // look for a next tab that will slide over to
26103 // replace the one being removed
26104 while(index < items.length){
26105 var item = items[++index];
26106 if(item && !item.isHidden()){
26110 // if one isn't found select the previous tab (on the left)
26113 var item = items[--index];
26114 if(item && !item.isHidden()){
26122 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26123 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26125 disableTab : function(id){
26126 var tab = this.items[id];
26127 if(tab && this.active != tab){
26133 * Enables a {@link Roo.TabPanelItem} that is disabled.
26134 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26136 enableTab : function(id){
26137 var tab = this.items[id];
26142 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26143 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26144 * @return {Roo.TabPanelItem} The TabPanelItem.
26146 activate : function(id){
26147 var tab = this.items[id];
26151 if(tab == this.active || tab.disabled){
26155 this.fireEvent("beforetabchange", this, e, tab);
26156 if(e.cancel !== true && !tab.disabled){
26158 this.active.hide();
26160 this.active = this.items[id];
26161 this.active.show();
26162 this.fireEvent("tabchange", this, this.active);
26168 * Gets the active {@link Roo.TabPanelItem}.
26169 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26171 getActiveTab : function(){
26172 return this.active;
26176 * Updates the tab body element to fit the height of the container element
26177 * for overflow scrolling
26178 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26180 syncHeight : function(targetHeight){
26181 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26182 var bm = this.bodyEl.getMargins();
26183 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26184 this.bodyEl.setHeight(newHeight);
26188 onResize : function(){
26189 if(this.monitorResize){
26190 this.autoSizeTabs();
26195 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26197 beginUpdate : function(){
26198 this.updating = true;
26202 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26204 endUpdate : function(){
26205 this.updating = false;
26206 this.autoSizeTabs();
26210 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26212 autoSizeTabs : function(){
26213 var count = this.items.length;
26214 var vcount = count - this.hiddenCount;
26215 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26216 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26217 var availWidth = Math.floor(w / vcount);
26218 var b = this.stripBody;
26219 if(b.getWidth() > w){
26220 var tabs = this.items;
26221 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26222 if(availWidth < this.minTabWidth){
26223 /*if(!this.sleft){ // incomplete scrolling code
26224 this.createScrollButtons();
26227 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26230 if(this.currentTabWidth < this.preferredTabWidth){
26231 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26237 * Returns the number of tabs in this TabPanel.
26240 getCount : function(){
26241 return this.items.length;
26245 * Resizes all the tabs to the passed width
26246 * @param {Number} The new width
26248 setTabWidth : function(width){
26249 this.currentTabWidth = width;
26250 for(var i = 0, len = this.items.length; i < len; i++) {
26251 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26256 * Destroys this TabPanel
26257 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26259 destroy : function(removeEl){
26260 Roo.EventManager.removeResizeListener(this.onResize, this);
26261 for(var i = 0, len = this.items.length; i < len; i++){
26262 this.items[i].purgeListeners();
26264 if(removeEl === true){
26265 this.el.update("");
26272 * @class Roo.TabPanelItem
26273 * @extends Roo.util.Observable
26274 * Represents an individual item (tab plus body) in a TabPanel.
26275 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26276 * @param {String} id The id of this TabPanelItem
26277 * @param {String} text The text for the tab of this TabPanelItem
26278 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26280 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26282 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26283 * @type Roo.TabPanel
26285 this.tabPanel = tabPanel;
26287 * The id for this TabPanelItem
26292 this.disabled = false;
26296 this.loaded = false;
26297 this.closable = closable;
26300 * The body element for this TabPanelItem.
26301 * @type Roo.Element
26303 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26304 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26305 this.bodyEl.setStyle("display", "block");
26306 this.bodyEl.setStyle("zoom", "1");
26309 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26311 this.el = Roo.get(els.el, true);
26312 this.inner = Roo.get(els.inner, true);
26313 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26314 this.pnode = Roo.get(els.el.parentNode, true);
26315 this.el.on("mousedown", this.onTabMouseDown, this);
26316 this.el.on("click", this.onTabClick, this);
26319 var c = Roo.get(els.close, true);
26320 c.dom.title = this.closeText;
26321 c.addClassOnOver("close-over");
26322 c.on("click", this.closeClick, this);
26328 * Fires when this tab becomes the active tab.
26329 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26330 * @param {Roo.TabPanelItem} this
26334 * @event beforeclose
26335 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26336 * @param {Roo.TabPanelItem} this
26337 * @param {Object} e Set cancel to true on this object to cancel the close.
26339 "beforeclose": true,
26342 * Fires when this tab is closed.
26343 * @param {Roo.TabPanelItem} this
26347 * @event deactivate
26348 * Fires when this tab is no longer the active tab.
26349 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26350 * @param {Roo.TabPanelItem} this
26352 "deactivate" : true
26354 this.hidden = false;
26356 Roo.TabPanelItem.superclass.constructor.call(this);
26359 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26360 purgeListeners : function(){
26361 Roo.util.Observable.prototype.purgeListeners.call(this);
26362 this.el.removeAllListeners();
26365 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26368 this.pnode.addClass("on");
26371 this.tabPanel.stripWrap.repaint();
26373 this.fireEvent("activate", this.tabPanel, this);
26377 * Returns true if this tab is the active tab.
26378 * @return {Boolean}
26380 isActive : function(){
26381 return this.tabPanel.getActiveTab() == this;
26385 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26388 this.pnode.removeClass("on");
26390 this.fireEvent("deactivate", this.tabPanel, this);
26393 hideAction : function(){
26394 this.bodyEl.hide();
26395 this.bodyEl.setStyle("position", "absolute");
26396 this.bodyEl.setLeft("-20000px");
26397 this.bodyEl.setTop("-20000px");
26400 showAction : function(){
26401 this.bodyEl.setStyle("position", "relative");
26402 this.bodyEl.setTop("");
26403 this.bodyEl.setLeft("");
26404 this.bodyEl.show();
26408 * Set the tooltip for the tab.
26409 * @param {String} tooltip The tab's tooltip
26411 setTooltip : function(text){
26412 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26413 this.textEl.dom.qtip = text;
26414 this.textEl.dom.removeAttribute('title');
26416 this.textEl.dom.title = text;
26420 onTabClick : function(e){
26421 e.preventDefault();
26422 this.tabPanel.activate(this.id);
26425 onTabMouseDown : function(e){
26426 e.preventDefault();
26427 this.tabPanel.activate(this.id);
26430 getWidth : function(){
26431 return this.inner.getWidth();
26434 setWidth : function(width){
26435 var iwidth = width - this.pnode.getPadding("lr");
26436 this.inner.setWidth(iwidth);
26437 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26438 this.pnode.setWidth(width);
26442 * Show or hide the tab
26443 * @param {Boolean} hidden True to hide or false to show.
26445 setHidden : function(hidden){
26446 this.hidden = hidden;
26447 this.pnode.setStyle("display", hidden ? "none" : "");
26451 * Returns true if this tab is "hidden"
26452 * @return {Boolean}
26454 isHidden : function(){
26455 return this.hidden;
26459 * Returns the text for this tab
26462 getText : function(){
26466 autoSize : function(){
26467 //this.el.beginMeasure();
26468 this.textEl.setWidth(1);
26469 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26470 //this.el.endMeasure();
26474 * Sets the text for the tab (Note: this also sets the tooltip text)
26475 * @param {String} text The tab's text and tooltip
26477 setText : function(text){
26479 this.textEl.update(text);
26480 this.setTooltip(text);
26481 if(!this.tabPanel.resizeTabs){
26486 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26488 activate : function(){
26489 this.tabPanel.activate(this.id);
26493 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26495 disable : function(){
26496 if(this.tabPanel.active != this){
26497 this.disabled = true;
26498 this.pnode.addClass("disabled");
26503 * Enables this TabPanelItem if it was previously disabled.
26505 enable : function(){
26506 this.disabled = false;
26507 this.pnode.removeClass("disabled");
26511 * Sets the content for this TabPanelItem.
26512 * @param {String} content The content
26513 * @param {Boolean} loadScripts true to look for and load scripts
26515 setContent : function(content, loadScripts){
26516 this.bodyEl.update(content, loadScripts);
26520 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26521 * @return {Roo.UpdateManager} The UpdateManager
26523 getUpdateManager : function(){
26524 return this.bodyEl.getUpdateManager();
26528 * Set a URL to be used to load the content for this TabPanelItem.
26529 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26530 * @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)
26531 * @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)
26532 * @return {Roo.UpdateManager} The UpdateManager
26534 setUrl : function(url, params, loadOnce){
26535 if(this.refreshDelegate){
26536 this.un('activate', this.refreshDelegate);
26538 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26539 this.on("activate", this.refreshDelegate);
26540 return this.bodyEl.getUpdateManager();
26544 _handleRefresh : function(url, params, loadOnce){
26545 if(!loadOnce || !this.loaded){
26546 var updater = this.bodyEl.getUpdateManager();
26547 updater.update(url, params, this._setLoaded.createDelegate(this));
26552 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26553 * Will fail silently if the setUrl method has not been called.
26554 * This does not activate the panel, just updates its content.
26556 refresh : function(){
26557 if(this.refreshDelegate){
26558 this.loaded = false;
26559 this.refreshDelegate();
26564 _setLoaded : function(){
26565 this.loaded = true;
26569 closeClick : function(e){
26572 this.fireEvent("beforeclose", this, o);
26573 if(o.cancel !== true){
26574 this.tabPanel.removeTab(this.id);
26578 * The text displayed in the tooltip for the close icon.
26581 closeText : "Close this tab"
26585 Roo.TabPanel.prototype.createStrip = function(container){
26586 var strip = document.createElement("div");
26587 strip.className = "x-tabs-wrap";
26588 container.appendChild(strip);
26592 Roo.TabPanel.prototype.createStripList = function(strip){
26593 // div wrapper for retard IE
26594 // returns the "tr" element.
26595 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26596 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26597 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26598 return strip.firstChild.firstChild.firstChild.firstChild;
26601 Roo.TabPanel.prototype.createBody = function(container){
26602 var body = document.createElement("div");
26603 Roo.id(body, "tab-body");
26604 Roo.fly(body).addClass("x-tabs-body");
26605 container.appendChild(body);
26609 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26610 var body = Roo.getDom(id);
26612 body = document.createElement("div");
26615 Roo.fly(body).addClass("x-tabs-item-body");
26616 bodyEl.insertBefore(body, bodyEl.firstChild);
26620 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26621 var td = document.createElement("td");
26622 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26623 //stripEl.appendChild(td);
26625 td.className = "x-tabs-closable";
26626 if(!this.closeTpl){
26627 this.closeTpl = new Roo.Template(
26628 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26629 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26630 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26633 var el = this.closeTpl.overwrite(td, {"text": text});
26634 var close = el.getElementsByTagName("div")[0];
26635 var inner = el.getElementsByTagName("em")[0];
26636 return {"el": el, "close": close, "inner": inner};
26639 this.tabTpl = new Roo.Template(
26640 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26641 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26644 var el = this.tabTpl.overwrite(td, {"text": text});
26645 var inner = el.getElementsByTagName("em")[0];
26646 return {"el": el, "inner": inner};
26650 * Ext JS Library 1.1.1
26651 * Copyright(c) 2006-2007, Ext JS, LLC.
26653 * Originally Released Under LGPL - original licence link has changed is not relivant.
26656 * <script type="text/javascript">
26660 * @class Roo.Button
26661 * @extends Roo.util.Observable
26662 * Simple Button class
26663 * @cfg {String} text The button text
26664 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26665 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26666 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26667 * @cfg {Object} scope The scope of the handler
26668 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26669 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26670 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26671 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26672 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26673 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26674 applies if enableToggle = true)
26675 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26676 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26677 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26679 * Create a new button
26680 * @param {Object} config The config object
26682 Roo.Button = function(renderTo, config)
26686 renderTo = config.renderTo || false;
26689 Roo.apply(this, config);
26693 * Fires when this button is clicked
26694 * @param {Button} this
26695 * @param {EventObject} e The click event
26700 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26701 * @param {Button} this
26702 * @param {Boolean} pressed
26707 * Fires when the mouse hovers over the button
26708 * @param {Button} this
26709 * @param {Event} e The event object
26711 'mouseover' : true,
26714 * Fires when the mouse exits the button
26715 * @param {Button} this
26716 * @param {Event} e The event object
26721 * Fires when the button is rendered
26722 * @param {Button} this
26727 this.menu = Roo.menu.MenuMgr.get(this.menu);
26729 // register listeners first!! - so render can be captured..
26730 Roo.util.Observable.call(this);
26732 this.render(renderTo);
26738 Roo.extend(Roo.Button, Roo.util.Observable, {
26744 * Read-only. True if this button is hidden
26749 * Read-only. True if this button is disabled
26754 * Read-only. True if this button is pressed (only if enableToggle = true)
26760 * @cfg {Number} tabIndex
26761 * The DOM tabIndex for this button (defaults to undefined)
26763 tabIndex : undefined,
26766 * @cfg {Boolean} enableToggle
26767 * True to enable pressed/not pressed toggling (defaults to false)
26769 enableToggle: false,
26771 * @cfg {Mixed} menu
26772 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26776 * @cfg {String} menuAlign
26777 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26779 menuAlign : "tl-bl?",
26782 * @cfg {String} iconCls
26783 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26785 iconCls : undefined,
26787 * @cfg {String} type
26788 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26793 menuClassTarget: 'tr',
26796 * @cfg {String} clickEvent
26797 * The type of event to map to the button's event handler (defaults to 'click')
26799 clickEvent : 'click',
26802 * @cfg {Boolean} handleMouseEvents
26803 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26805 handleMouseEvents : true,
26808 * @cfg {String} tooltipType
26809 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26811 tooltipType : 'qtip',
26814 * @cfg {String} cls
26815 * A CSS class to apply to the button's main element.
26819 * @cfg {Roo.Template} template (Optional)
26820 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26821 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26822 * require code modifications if required elements (e.g. a button) aren't present.
26826 render : function(renderTo){
26828 if(this.hideParent){
26829 this.parentEl = Roo.get(renderTo);
26831 if(!this.dhconfig){
26832 if(!this.template){
26833 if(!Roo.Button.buttonTemplate){
26834 // hideous table template
26835 Roo.Button.buttonTemplate = new Roo.Template(
26836 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26837 '<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>',
26838 "</tr></tbody></table>");
26840 this.template = Roo.Button.buttonTemplate;
26842 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26843 var btnEl = btn.child("button:first");
26844 btnEl.on('focus', this.onFocus, this);
26845 btnEl.on('blur', this.onBlur, this);
26847 btn.addClass(this.cls);
26850 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26853 btnEl.addClass(this.iconCls);
26855 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26858 if(this.tabIndex !== undefined){
26859 btnEl.dom.tabIndex = this.tabIndex;
26862 if(typeof this.tooltip == 'object'){
26863 Roo.QuickTips.tips(Roo.apply({
26867 btnEl.dom[this.tooltipType] = this.tooltip;
26871 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26875 this.el.dom.id = this.el.id = this.id;
26878 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26879 this.menu.on("show", this.onMenuShow, this);
26880 this.menu.on("hide", this.onMenuHide, this);
26882 btn.addClass("x-btn");
26883 if(Roo.isIE && !Roo.isIE7){
26884 this.autoWidth.defer(1, this);
26888 if(this.handleMouseEvents){
26889 btn.on("mouseover", this.onMouseOver, this);
26890 btn.on("mouseout", this.onMouseOut, this);
26891 btn.on("mousedown", this.onMouseDown, this);
26893 btn.on(this.clickEvent, this.onClick, this);
26894 //btn.on("mouseup", this.onMouseUp, this);
26901 Roo.ButtonToggleMgr.register(this);
26903 this.el.addClass("x-btn-pressed");
26906 var repeater = new Roo.util.ClickRepeater(btn,
26907 typeof this.repeat == "object" ? this.repeat : {}
26909 repeater.on("click", this.onClick, this);
26912 this.fireEvent('render', this);
26916 * Returns the button's underlying element
26917 * @return {Roo.Element} The element
26919 getEl : function(){
26924 * Destroys this Button and removes any listeners.
26926 destroy : function(){
26927 Roo.ButtonToggleMgr.unregister(this);
26928 this.el.removeAllListeners();
26929 this.purgeListeners();
26934 autoWidth : function(){
26936 this.el.setWidth("auto");
26937 if(Roo.isIE7 && Roo.isStrict){
26938 var ib = this.el.child('button');
26939 if(ib && ib.getWidth() > 20){
26941 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26946 this.el.beginMeasure();
26948 if(this.el.getWidth() < this.minWidth){
26949 this.el.setWidth(this.minWidth);
26952 this.el.endMeasure();
26959 * Assigns this button's click handler
26960 * @param {Function} handler The function to call when the button is clicked
26961 * @param {Object} scope (optional) Scope for the function passed in
26963 setHandler : function(handler, scope){
26964 this.handler = handler;
26965 this.scope = scope;
26969 * Sets this button's text
26970 * @param {String} text The button text
26972 setText : function(text){
26975 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26981 * Gets the text for this button
26982 * @return {String} The button text
26984 getText : function(){
26992 this.hidden = false;
26994 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27002 this.hidden = true;
27004 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27009 * Convenience function for boolean show/hide
27010 * @param {Boolean} visible True to show, false to hide
27012 setVisible: function(visible){
27021 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27022 * @param {Boolean} state (optional) Force a particular state
27024 toggle : function(state){
27025 state = state === undefined ? !this.pressed : state;
27026 if(state != this.pressed){
27028 this.el.addClass("x-btn-pressed");
27029 this.pressed = true;
27030 this.fireEvent("toggle", this, true);
27032 this.el.removeClass("x-btn-pressed");
27033 this.pressed = false;
27034 this.fireEvent("toggle", this, false);
27036 if(this.toggleHandler){
27037 this.toggleHandler.call(this.scope || this, this, state);
27045 focus : function(){
27046 this.el.child('button:first').focus();
27050 * Disable this button
27052 disable : function(){
27054 this.el.addClass("x-btn-disabled");
27056 this.disabled = true;
27060 * Enable this button
27062 enable : function(){
27064 this.el.removeClass("x-btn-disabled");
27066 this.disabled = false;
27070 * Convenience function for boolean enable/disable
27071 * @param {Boolean} enabled True to enable, false to disable
27073 setDisabled : function(v){
27074 this[v !== true ? "enable" : "disable"]();
27078 onClick : function(e){
27080 e.preventDefault();
27085 if(!this.disabled){
27086 if(this.enableToggle){
27089 if(this.menu && !this.menu.isVisible()){
27090 this.menu.show(this.el, this.menuAlign);
27092 this.fireEvent("click", this, e);
27094 this.el.removeClass("x-btn-over");
27095 this.handler.call(this.scope || this, this, e);
27100 onMouseOver : function(e){
27101 if(!this.disabled){
27102 this.el.addClass("x-btn-over");
27103 this.fireEvent('mouseover', this, e);
27107 onMouseOut : function(e){
27108 if(!e.within(this.el, true)){
27109 this.el.removeClass("x-btn-over");
27110 this.fireEvent('mouseout', this, e);
27114 onFocus : function(e){
27115 if(!this.disabled){
27116 this.el.addClass("x-btn-focus");
27120 onBlur : function(e){
27121 this.el.removeClass("x-btn-focus");
27124 onMouseDown : function(e){
27125 if(!this.disabled && e.button == 0){
27126 this.el.addClass("x-btn-click");
27127 Roo.get(document).on('mouseup', this.onMouseUp, this);
27131 onMouseUp : function(e){
27133 this.el.removeClass("x-btn-click");
27134 Roo.get(document).un('mouseup', this.onMouseUp, this);
27138 onMenuShow : function(e){
27139 this.el.addClass("x-btn-menu-active");
27142 onMenuHide : function(e){
27143 this.el.removeClass("x-btn-menu-active");
27147 // Private utility class used by Button
27148 Roo.ButtonToggleMgr = function(){
27151 function toggleGroup(btn, state){
27153 var g = groups[btn.toggleGroup];
27154 for(var i = 0, l = g.length; i < l; i++){
27156 g[i].toggle(false);
27163 register : function(btn){
27164 if(!btn.toggleGroup){
27167 var g = groups[btn.toggleGroup];
27169 g = groups[btn.toggleGroup] = [];
27172 btn.on("toggle", toggleGroup);
27175 unregister : function(btn){
27176 if(!btn.toggleGroup){
27179 var g = groups[btn.toggleGroup];
27182 btn.un("toggle", toggleGroup);
27188 * Ext JS Library 1.1.1
27189 * Copyright(c) 2006-2007, Ext JS, LLC.
27191 * Originally Released Under LGPL - original licence link has changed is not relivant.
27194 * <script type="text/javascript">
27198 * @class Roo.SplitButton
27199 * @extends Roo.Button
27200 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27201 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27202 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27203 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27204 * @cfg {String} arrowTooltip The title attribute of the arrow
27206 * Create a new menu button
27207 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27208 * @param {Object} config The config object
27210 Roo.SplitButton = function(renderTo, config){
27211 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27213 * @event arrowclick
27214 * Fires when this button's arrow is clicked
27215 * @param {SplitButton} this
27216 * @param {EventObject} e The click event
27218 this.addEvents({"arrowclick":true});
27221 Roo.extend(Roo.SplitButton, Roo.Button, {
27222 render : function(renderTo){
27223 // this is one sweet looking template!
27224 var tpl = new Roo.Template(
27225 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27226 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27227 '<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>',
27228 "</tbody></table></td><td>",
27229 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27230 '<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>',
27231 "</tbody></table></td></tr></table>"
27233 var btn = tpl.append(renderTo, [this.text, this.type], true);
27234 var btnEl = btn.child("button");
27236 btn.addClass(this.cls);
27239 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27242 btnEl.addClass(this.iconCls);
27244 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27248 if(this.handleMouseEvents){
27249 btn.on("mouseover", this.onMouseOver, this);
27250 btn.on("mouseout", this.onMouseOut, this);
27251 btn.on("mousedown", this.onMouseDown, this);
27252 btn.on("mouseup", this.onMouseUp, this);
27254 btn.on(this.clickEvent, this.onClick, this);
27256 if(typeof this.tooltip == 'object'){
27257 Roo.QuickTips.tips(Roo.apply({
27261 btnEl.dom[this.tooltipType] = this.tooltip;
27264 if(this.arrowTooltip){
27265 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27274 this.el.addClass("x-btn-pressed");
27276 if(Roo.isIE && !Roo.isIE7){
27277 this.autoWidth.defer(1, this);
27282 this.menu.on("show", this.onMenuShow, this);
27283 this.menu.on("hide", this.onMenuHide, this);
27285 this.fireEvent('render', this);
27289 autoWidth : function(){
27291 var tbl = this.el.child("table:first");
27292 var tbl2 = this.el.child("table:last");
27293 this.el.setWidth("auto");
27294 tbl.setWidth("auto");
27295 if(Roo.isIE7 && Roo.isStrict){
27296 var ib = this.el.child('button:first');
27297 if(ib && ib.getWidth() > 20){
27299 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27304 this.el.beginMeasure();
27306 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27307 tbl.setWidth(this.minWidth-tbl2.getWidth());
27310 this.el.endMeasure();
27313 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27317 * Sets this button's click handler
27318 * @param {Function} handler The function to call when the button is clicked
27319 * @param {Object} scope (optional) Scope for the function passed above
27321 setHandler : function(handler, scope){
27322 this.handler = handler;
27323 this.scope = scope;
27327 * Sets this button's arrow click handler
27328 * @param {Function} handler The function to call when the arrow is clicked
27329 * @param {Object} scope (optional) Scope for the function passed above
27331 setArrowHandler : function(handler, scope){
27332 this.arrowHandler = handler;
27333 this.scope = scope;
27339 focus : function(){
27341 this.el.child("button:first").focus();
27346 onClick : function(e){
27347 e.preventDefault();
27348 if(!this.disabled){
27349 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27350 if(this.menu && !this.menu.isVisible()){
27351 this.menu.show(this.el, this.menuAlign);
27353 this.fireEvent("arrowclick", this, e);
27354 if(this.arrowHandler){
27355 this.arrowHandler.call(this.scope || this, this, e);
27358 this.fireEvent("click", this, e);
27360 this.handler.call(this.scope || this, this, e);
27366 onMouseDown : function(e){
27367 if(!this.disabled){
27368 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27372 onMouseUp : function(e){
27373 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27378 // backwards compat
27379 Roo.MenuButton = Roo.SplitButton;/*
27381 * Ext JS Library 1.1.1
27382 * Copyright(c) 2006-2007, Ext JS, LLC.
27384 * Originally Released Under LGPL - original licence link has changed is not relivant.
27387 * <script type="text/javascript">
27391 * @class Roo.Toolbar
27392 * Basic Toolbar class.
27394 * Creates a new Toolbar
27395 * @param {Object} container The config object
27397 Roo.Toolbar = function(container, buttons, config)
27399 /// old consturctor format still supported..
27400 if(container instanceof Array){ // omit the container for later rendering
27401 buttons = container;
27405 if (typeof(container) == 'object' && container.xtype) {
27406 config = container;
27407 container = config.container;
27408 buttons = config.buttons || []; // not really - use items!!
27411 if (config && config.items) {
27412 xitems = config.items;
27413 delete config.items;
27415 Roo.apply(this, config);
27416 this.buttons = buttons;
27419 this.render(container);
27421 this.xitems = xitems;
27422 Roo.each(xitems, function(b) {
27428 Roo.Toolbar.prototype = {
27430 * @cfg {Array} items
27431 * array of button configs or elements to add (will be converted to a MixedCollection)
27435 * @cfg {String/HTMLElement/Element} container
27436 * The id or element that will contain the toolbar
27439 render : function(ct){
27440 this.el = Roo.get(ct);
27442 this.el.addClass(this.cls);
27444 // using a table allows for vertical alignment
27445 // 100% width is needed by Safari...
27446 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27447 this.tr = this.el.child("tr", true);
27449 this.items = new Roo.util.MixedCollection(false, function(o){
27450 return o.id || ("item" + (++autoId));
27453 this.add.apply(this, this.buttons);
27454 delete this.buttons;
27459 * Adds element(s) to the toolbar -- this function takes a variable number of
27460 * arguments of mixed type and adds them to the toolbar.
27461 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27463 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27464 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27465 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27466 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27467 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27468 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27469 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27470 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27471 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27473 * @param {Mixed} arg2
27474 * @param {Mixed} etc.
27477 var a = arguments, l = a.length;
27478 for(var i = 0; i < l; i++){
27483 _add : function(el) {
27486 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27489 if (el.applyTo){ // some kind of form field
27490 return this.addField(el);
27492 if (el.render){ // some kind of Toolbar.Item
27493 return this.addItem(el);
27495 if (typeof el == "string"){ // string
27496 if(el == "separator" || el == "-"){
27497 return this.addSeparator();
27500 return this.addSpacer();
27503 return this.addFill();
27505 return this.addText(el);
27508 if(el.tagName){ // element
27509 return this.addElement(el);
27511 if(typeof el == "object"){ // must be button config?
27512 return this.addButton(el);
27514 // and now what?!?!
27520 * Add an Xtype element
27521 * @param {Object} xtype Xtype Object
27522 * @return {Object} created Object
27524 addxtype : function(e){
27525 return this.add(e);
27529 * Returns the Element for this toolbar.
27530 * @return {Roo.Element}
27532 getEl : function(){
27538 * @return {Roo.Toolbar.Item} The separator item
27540 addSeparator : function(){
27541 return this.addItem(new Roo.Toolbar.Separator());
27545 * Adds a spacer element
27546 * @return {Roo.Toolbar.Spacer} The spacer item
27548 addSpacer : function(){
27549 return this.addItem(new Roo.Toolbar.Spacer());
27553 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27554 * @return {Roo.Toolbar.Fill} The fill item
27556 addFill : function(){
27557 return this.addItem(new Roo.Toolbar.Fill());
27561 * Adds any standard HTML element to the toolbar
27562 * @param {String/HTMLElement/Element} el The element or id of the element to add
27563 * @return {Roo.Toolbar.Item} The element's item
27565 addElement : function(el){
27566 return this.addItem(new Roo.Toolbar.Item(el));
27569 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27570 * @type Roo.util.MixedCollection
27575 * Adds any Toolbar.Item or subclass
27576 * @param {Roo.Toolbar.Item} item
27577 * @return {Roo.Toolbar.Item} The item
27579 addItem : function(item){
27580 var td = this.nextBlock();
27582 this.items.add(item);
27587 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27588 * @param {Object/Array} config A button config or array of configs
27589 * @return {Roo.Toolbar.Button/Array}
27591 addButton : function(config){
27592 if(config instanceof Array){
27594 for(var i = 0, len = config.length; i < len; i++) {
27595 buttons.push(this.addButton(config[i]));
27600 if(!(config instanceof Roo.Toolbar.Button)){
27602 new Roo.Toolbar.SplitButton(config) :
27603 new Roo.Toolbar.Button(config);
27605 var td = this.nextBlock();
27612 * Adds text to the toolbar
27613 * @param {String} text The text to add
27614 * @return {Roo.Toolbar.Item} The element's item
27616 addText : function(text){
27617 return this.addItem(new Roo.Toolbar.TextItem(text));
27621 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27622 * @param {Number} index The index where the item is to be inserted
27623 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27624 * @return {Roo.Toolbar.Button/Item}
27626 insertButton : function(index, item){
27627 if(item instanceof Array){
27629 for(var i = 0, len = item.length; i < len; i++) {
27630 buttons.push(this.insertButton(index + i, item[i]));
27634 if (!(item instanceof Roo.Toolbar.Button)){
27635 item = new Roo.Toolbar.Button(item);
27637 var td = document.createElement("td");
27638 this.tr.insertBefore(td, this.tr.childNodes[index]);
27640 this.items.insert(index, item);
27645 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27646 * @param {Object} config
27647 * @return {Roo.Toolbar.Item} The element's item
27649 addDom : function(config, returnEl){
27650 var td = this.nextBlock();
27651 Roo.DomHelper.overwrite(td, config);
27652 var ti = new Roo.Toolbar.Item(td.firstChild);
27654 this.items.add(ti);
27659 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27660 * @type Roo.util.MixedCollection
27665 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27666 * Note: the field should not have been rendered yet. For a field that has already been
27667 * rendered, use {@link #addElement}.
27668 * @param {Roo.form.Field} field
27669 * @return {Roo.ToolbarItem}
27673 addField : function(field) {
27674 if (!this.fields) {
27676 this.fields = new Roo.util.MixedCollection(false, function(o){
27677 return o.id || ("item" + (++autoId));
27682 var td = this.nextBlock();
27684 var ti = new Roo.Toolbar.Item(td.firstChild);
27686 this.items.add(ti);
27687 this.fields.add(field);
27698 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27699 this.el.child('div').hide();
27707 this.el.child('div').show();
27711 nextBlock : function(){
27712 var td = document.createElement("td");
27713 this.tr.appendChild(td);
27718 destroy : function(){
27719 if(this.items){ // rendered?
27720 Roo.destroy.apply(Roo, this.items.items);
27722 if(this.fields){ // rendered?
27723 Roo.destroy.apply(Roo, this.fields.items);
27725 Roo.Element.uncache(this.el, this.tr);
27730 * @class Roo.Toolbar.Item
27731 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27733 * Creates a new Item
27734 * @param {HTMLElement} el
27736 Roo.Toolbar.Item = function(el){
27737 this.el = Roo.getDom(el);
27738 this.id = Roo.id(this.el);
27739 this.hidden = false;
27742 Roo.Toolbar.Item.prototype = {
27745 * Get this item's HTML Element
27746 * @return {HTMLElement}
27748 getEl : function(){
27753 render : function(td){
27755 td.appendChild(this.el);
27759 * Removes and destroys this item.
27761 destroy : function(){
27762 this.td.parentNode.removeChild(this.td);
27769 this.hidden = false;
27770 this.td.style.display = "";
27777 this.hidden = true;
27778 this.td.style.display = "none";
27782 * Convenience function for boolean show/hide.
27783 * @param {Boolean} visible true to show/false to hide
27785 setVisible: function(visible){
27794 * Try to focus this item.
27796 focus : function(){
27797 Roo.fly(this.el).focus();
27801 * Disables this item.
27803 disable : function(){
27804 Roo.fly(this.td).addClass("x-item-disabled");
27805 this.disabled = true;
27806 this.el.disabled = true;
27810 * Enables this item.
27812 enable : function(){
27813 Roo.fly(this.td).removeClass("x-item-disabled");
27814 this.disabled = false;
27815 this.el.disabled = false;
27821 * @class Roo.Toolbar.Separator
27822 * @extends Roo.Toolbar.Item
27823 * A simple toolbar separator class
27825 * Creates a new Separator
27827 Roo.Toolbar.Separator = function(){
27828 var s = document.createElement("span");
27829 s.className = "ytb-sep";
27830 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27832 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27833 enable:Roo.emptyFn,
27834 disable:Roo.emptyFn,
27839 * @class Roo.Toolbar.Spacer
27840 * @extends Roo.Toolbar.Item
27841 * A simple element that adds extra horizontal space to a toolbar.
27843 * Creates a new Spacer
27845 Roo.Toolbar.Spacer = function(){
27846 var s = document.createElement("div");
27847 s.className = "ytb-spacer";
27848 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27850 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27851 enable:Roo.emptyFn,
27852 disable:Roo.emptyFn,
27857 * @class Roo.Toolbar.Fill
27858 * @extends Roo.Toolbar.Spacer
27859 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27861 * Creates a new Spacer
27863 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27865 render : function(td){
27866 td.style.width = '100%';
27867 Roo.Toolbar.Fill.superclass.render.call(this, td);
27872 * @class Roo.Toolbar.TextItem
27873 * @extends Roo.Toolbar.Item
27874 * A simple class that renders text directly into a toolbar.
27876 * Creates a new TextItem
27877 * @param {String} text
27879 Roo.Toolbar.TextItem = function(text){
27880 if (typeof(text) == 'object') {
27883 var s = document.createElement("span");
27884 s.className = "ytb-text";
27885 s.innerHTML = text;
27886 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27888 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27889 enable:Roo.emptyFn,
27890 disable:Roo.emptyFn,
27895 * @class Roo.Toolbar.Button
27896 * @extends Roo.Button
27897 * A button that renders into a toolbar.
27899 * Creates a new Button
27900 * @param {Object} config A standard {@link Roo.Button} config object
27902 Roo.Toolbar.Button = function(config){
27903 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27905 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27906 render : function(td){
27908 Roo.Toolbar.Button.superclass.render.call(this, td);
27912 * Removes and destroys this button
27914 destroy : function(){
27915 Roo.Toolbar.Button.superclass.destroy.call(this);
27916 this.td.parentNode.removeChild(this.td);
27920 * Shows this button
27923 this.hidden = false;
27924 this.td.style.display = "";
27928 * Hides this button
27931 this.hidden = true;
27932 this.td.style.display = "none";
27936 * Disables this item
27938 disable : function(){
27939 Roo.fly(this.td).addClass("x-item-disabled");
27940 this.disabled = true;
27944 * Enables this item
27946 enable : function(){
27947 Roo.fly(this.td).removeClass("x-item-disabled");
27948 this.disabled = false;
27951 // backwards compat
27952 Roo.ToolbarButton = Roo.Toolbar.Button;
27955 * @class Roo.Toolbar.SplitButton
27956 * @extends Roo.SplitButton
27957 * A menu button that renders into a toolbar.
27959 * Creates a new SplitButton
27960 * @param {Object} config A standard {@link Roo.SplitButton} config object
27962 Roo.Toolbar.SplitButton = function(config){
27963 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27965 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27966 render : function(td){
27968 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27972 * Removes and destroys this button
27974 destroy : function(){
27975 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27976 this.td.parentNode.removeChild(this.td);
27980 * Shows this button
27983 this.hidden = false;
27984 this.td.style.display = "";
27988 * Hides this button
27991 this.hidden = true;
27992 this.td.style.display = "none";
27996 // backwards compat
27997 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27999 * Ext JS Library 1.1.1
28000 * Copyright(c) 2006-2007, Ext JS, LLC.
28002 * Originally Released Under LGPL - original licence link has changed is not relivant.
28005 * <script type="text/javascript">
28009 * @class Roo.PagingToolbar
28010 * @extends Roo.Toolbar
28011 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28013 * Create a new PagingToolbar
28014 * @param {Object} config The config object
28016 Roo.PagingToolbar = function(el, ds, config)
28018 // old args format still supported... - xtype is prefered..
28019 if (typeof(el) == 'object' && el.xtype) {
28020 // created from xtype...
28022 ds = el.dataSource;
28023 el = config.container;
28026 if (config.items) {
28027 items = config.items;
28031 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28034 this.renderButtons(this.el);
28037 // supprot items array.
28039 Roo.each(items, function(e) {
28040 this.add(Roo.factory(e));
28045 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28047 * @cfg {Roo.data.Store} dataSource
28048 * The underlying data store providing the paged data
28051 * @cfg {String/HTMLElement/Element} container
28052 * container The id or element that will contain the toolbar
28055 * @cfg {Boolean} displayInfo
28056 * True to display the displayMsg (defaults to false)
28059 * @cfg {Number} pageSize
28060 * The number of records to display per page (defaults to 20)
28064 * @cfg {String} displayMsg
28065 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28067 displayMsg : 'Displaying {0} - {1} of {2}',
28069 * @cfg {String} emptyMsg
28070 * The message to display when no records are found (defaults to "No data to display")
28072 emptyMsg : 'No data to display',
28074 * Customizable piece of the default paging text (defaults to "Page")
28077 beforePageText : "Page",
28079 * Customizable piece of the default paging text (defaults to "of %0")
28082 afterPageText : "of {0}",
28084 * Customizable piece of the default paging text (defaults to "First Page")
28087 firstText : "First Page",
28089 * Customizable piece of the default paging text (defaults to "Previous Page")
28092 prevText : "Previous Page",
28094 * Customizable piece of the default paging text (defaults to "Next Page")
28097 nextText : "Next Page",
28099 * Customizable piece of the default paging text (defaults to "Last Page")
28102 lastText : "Last Page",
28104 * Customizable piece of the default paging text (defaults to "Refresh")
28107 refreshText : "Refresh",
28110 renderButtons : function(el){
28111 Roo.PagingToolbar.superclass.render.call(this, el);
28112 this.first = this.addButton({
28113 tooltip: this.firstText,
28114 cls: "x-btn-icon x-grid-page-first",
28116 handler: this.onClick.createDelegate(this, ["first"])
28118 this.prev = this.addButton({
28119 tooltip: this.prevText,
28120 cls: "x-btn-icon x-grid-page-prev",
28122 handler: this.onClick.createDelegate(this, ["prev"])
28124 //this.addSeparator();
28125 this.add(this.beforePageText);
28126 this.field = Roo.get(this.addDom({
28131 cls: "x-grid-page-number"
28133 this.field.on("keydown", this.onPagingKeydown, this);
28134 this.field.on("focus", function(){this.dom.select();});
28135 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28136 this.field.setHeight(18);
28137 //this.addSeparator();
28138 this.next = this.addButton({
28139 tooltip: this.nextText,
28140 cls: "x-btn-icon x-grid-page-next",
28142 handler: this.onClick.createDelegate(this, ["next"])
28144 this.last = this.addButton({
28145 tooltip: this.lastText,
28146 cls: "x-btn-icon x-grid-page-last",
28148 handler: this.onClick.createDelegate(this, ["last"])
28150 //this.addSeparator();
28151 this.loading = this.addButton({
28152 tooltip: this.refreshText,
28153 cls: "x-btn-icon x-grid-loading",
28154 handler: this.onClick.createDelegate(this, ["refresh"])
28157 if(this.displayInfo){
28158 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28163 updateInfo : function(){
28164 if(this.displayEl){
28165 var count = this.ds.getCount();
28166 var msg = count == 0 ?
28170 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28172 this.displayEl.update(msg);
28177 onLoad : function(ds, r, o){
28178 this.cursor = o.params ? o.params.start : 0;
28179 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28181 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28182 this.field.dom.value = ap;
28183 this.first.setDisabled(ap == 1);
28184 this.prev.setDisabled(ap == 1);
28185 this.next.setDisabled(ap == ps);
28186 this.last.setDisabled(ap == ps);
28187 this.loading.enable();
28192 getPageData : function(){
28193 var total = this.ds.getTotalCount();
28196 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28197 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28202 onLoadError : function(){
28203 this.loading.enable();
28207 onPagingKeydown : function(e){
28208 var k = e.getKey();
28209 var d = this.getPageData();
28211 var v = this.field.dom.value, pageNum;
28212 if(!v || isNaN(pageNum = parseInt(v, 10))){
28213 this.field.dom.value = d.activePage;
28216 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28217 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28220 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))
28222 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28223 this.field.dom.value = pageNum;
28224 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28227 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28229 var v = this.field.dom.value, pageNum;
28230 var increment = (e.shiftKey) ? 10 : 1;
28231 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28233 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28234 this.field.dom.value = d.activePage;
28237 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28239 this.field.dom.value = parseInt(v, 10) + increment;
28240 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28241 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28248 beforeLoad : function(){
28250 this.loading.disable();
28255 onClick : function(which){
28259 ds.load({params:{start: 0, limit: this.pageSize}});
28262 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28265 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28268 var total = ds.getTotalCount();
28269 var extra = total % this.pageSize;
28270 var lastStart = extra ? (total - extra) : total-this.pageSize;
28271 ds.load({params:{start: lastStart, limit: this.pageSize}});
28274 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28280 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28281 * @param {Roo.data.Store} store The data store to unbind
28283 unbind : function(ds){
28284 ds.un("beforeload", this.beforeLoad, this);
28285 ds.un("load", this.onLoad, this);
28286 ds.un("loadexception", this.onLoadError, this);
28287 ds.un("remove", this.updateInfo, this);
28288 ds.un("add", this.updateInfo, this);
28289 this.ds = undefined;
28293 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28294 * @param {Roo.data.Store} store The data store to bind
28296 bind : function(ds){
28297 ds.on("beforeload", this.beforeLoad, this);
28298 ds.on("load", this.onLoad, this);
28299 ds.on("loadexception", this.onLoadError, this);
28300 ds.on("remove", this.updateInfo, this);
28301 ds.on("add", this.updateInfo, this);
28306 * Ext JS Library 1.1.1
28307 * Copyright(c) 2006-2007, Ext JS, LLC.
28309 * Originally Released Under LGPL - original licence link has changed is not relivant.
28312 * <script type="text/javascript">
28316 * @class Roo.Resizable
28317 * @extends Roo.util.Observable
28318 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28319 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28320 * 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
28321 * the element will be wrapped for you automatically.</p>
28322 * <p>Here is the list of valid resize handles:</p>
28325 ------ -------------------
28334 'hd' horizontal drag
28337 * <p>Here's an example showing the creation of a typical Resizable:</p>
28339 var resizer = new Roo.Resizable("element-id", {
28347 resizer.on("resize", myHandler);
28349 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28350 * resizer.east.setDisplayed(false);</p>
28351 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28352 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28353 * resize operation's new size (defaults to [0, 0])
28354 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28355 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28356 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28357 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28358 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28359 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28360 * @cfg {Number} width The width of the element in pixels (defaults to null)
28361 * @cfg {Number} height The height of the element in pixels (defaults to null)
28362 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28363 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28364 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28365 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28366 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28367 * in favor of the handles config option (defaults to false)
28368 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28369 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28370 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28371 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28372 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28373 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28374 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28375 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28376 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28377 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28378 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28380 * Create a new resizable component
28381 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28382 * @param {Object} config configuration options
28384 Roo.Resizable = function(el, config)
28386 this.el = Roo.get(el);
28388 if(config && config.wrap){
28389 config.resizeChild = this.el;
28390 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28391 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28392 this.el.setStyle("overflow", "hidden");
28393 this.el.setPositioning(config.resizeChild.getPositioning());
28394 config.resizeChild.clearPositioning();
28395 if(!config.width || !config.height){
28396 var csize = config.resizeChild.getSize();
28397 this.el.setSize(csize.width, csize.height);
28399 if(config.pinned && !config.adjustments){
28400 config.adjustments = "auto";
28404 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28405 this.proxy.unselectable();
28406 this.proxy.enableDisplayMode('block');
28408 Roo.apply(this, config);
28411 this.disableTrackOver = true;
28412 this.el.addClass("x-resizable-pinned");
28414 // if the element isn't positioned, make it relative
28415 var position = this.el.getStyle("position");
28416 if(position != "absolute" && position != "fixed"){
28417 this.el.setStyle("position", "relative");
28419 if(!this.handles){ // no handles passed, must be legacy style
28420 this.handles = 's,e,se';
28421 if(this.multiDirectional){
28422 this.handles += ',n,w';
28425 if(this.handles == "all"){
28426 this.handles = "n s e w ne nw se sw";
28428 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28429 var ps = Roo.Resizable.positions;
28430 for(var i = 0, len = hs.length; i < len; i++){
28431 if(hs[i] && ps[hs[i]]){
28432 var pos = ps[hs[i]];
28433 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28437 this.corner = this.southeast;
28439 // updateBox = the box can move..
28440 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28441 this.updateBox = true;
28444 this.activeHandle = null;
28446 if(this.resizeChild){
28447 if(typeof this.resizeChild == "boolean"){
28448 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28450 this.resizeChild = Roo.get(this.resizeChild, true);
28454 if(this.adjustments == "auto"){
28455 var rc = this.resizeChild;
28456 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28457 if(rc && (hw || hn)){
28458 rc.position("relative");
28459 rc.setLeft(hw ? hw.el.getWidth() : 0);
28460 rc.setTop(hn ? hn.el.getHeight() : 0);
28462 this.adjustments = [
28463 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28464 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28468 if(this.draggable){
28469 this.dd = this.dynamic ?
28470 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28471 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28477 * @event beforeresize
28478 * Fired before resize is allowed. Set enabled to false to cancel resize.
28479 * @param {Roo.Resizable} this
28480 * @param {Roo.EventObject} e The mousedown event
28482 "beforeresize" : true,
28485 * Fired after a resize.
28486 * @param {Roo.Resizable} this
28487 * @param {Number} width The new width
28488 * @param {Number} height The new height
28489 * @param {Roo.EventObject} e The mouseup event
28494 if(this.width !== null && this.height !== null){
28495 this.resizeTo(this.width, this.height);
28497 this.updateChildSize();
28500 this.el.dom.style.zoom = 1;
28502 Roo.Resizable.superclass.constructor.call(this);
28505 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28506 resizeChild : false,
28507 adjustments : [0, 0],
28517 multiDirectional : false,
28518 disableTrackOver : false,
28519 easing : 'easeOutStrong',
28520 widthIncrement : 0,
28521 heightIncrement : 0,
28525 preserveRatio : false,
28526 transparent: false,
28532 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28534 constrainTo: undefined,
28536 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28538 resizeRegion: undefined,
28542 * Perform a manual resize
28543 * @param {Number} width
28544 * @param {Number} height
28546 resizeTo : function(width, height){
28547 this.el.setSize(width, height);
28548 this.updateChildSize();
28549 this.fireEvent("resize", this, width, height, null);
28553 startSizing : function(e, handle){
28554 this.fireEvent("beforeresize", this, e);
28555 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28558 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28559 this.overlay.unselectable();
28560 this.overlay.enableDisplayMode("block");
28561 this.overlay.on("mousemove", this.onMouseMove, this);
28562 this.overlay.on("mouseup", this.onMouseUp, this);
28564 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28566 this.resizing = true;
28567 this.startBox = this.el.getBox();
28568 this.startPoint = e.getXY();
28569 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28570 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28572 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28573 this.overlay.show();
28575 if(this.constrainTo) {
28576 var ct = Roo.get(this.constrainTo);
28577 this.resizeRegion = ct.getRegion().adjust(
28578 ct.getFrameWidth('t'),
28579 ct.getFrameWidth('l'),
28580 -ct.getFrameWidth('b'),
28581 -ct.getFrameWidth('r')
28585 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28587 this.proxy.setBox(this.startBox);
28589 this.proxy.setStyle('visibility', 'visible');
28595 onMouseDown : function(handle, e){
28598 this.activeHandle = handle;
28599 this.startSizing(e, handle);
28604 onMouseUp : function(e){
28605 var size = this.resizeElement();
28606 this.resizing = false;
28608 this.overlay.hide();
28610 this.fireEvent("resize", this, size.width, size.height, e);
28614 updateChildSize : function(){
28615 if(this.resizeChild){
28617 var child = this.resizeChild;
28618 var adj = this.adjustments;
28619 if(el.dom.offsetWidth){
28620 var b = el.getSize(true);
28621 child.setSize(b.width+adj[0], b.height+adj[1]);
28623 // Second call here for IE
28624 // The first call enables instant resizing and
28625 // the second call corrects scroll bars if they
28628 setTimeout(function(){
28629 if(el.dom.offsetWidth){
28630 var b = el.getSize(true);
28631 child.setSize(b.width+adj[0], b.height+adj[1]);
28639 snap : function(value, inc, min){
28640 if(!inc || !value) return value;
28641 var newValue = value;
28642 var m = value % inc;
28645 newValue = value + (inc-m);
28647 newValue = value - m;
28650 return Math.max(min, newValue);
28654 resizeElement : function(){
28655 var box = this.proxy.getBox();
28656 if(this.updateBox){
28657 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28659 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28661 this.updateChildSize();
28669 constrain : function(v, diff, m, mx){
28672 }else if(v - diff > mx){
28679 onMouseMove : function(e){
28681 try{// try catch so if something goes wrong the user doesn't get hung
28683 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28687 //var curXY = this.startPoint;
28688 var curSize = this.curSize || this.startBox;
28689 var x = this.startBox.x, y = this.startBox.y;
28690 var ox = x, oy = y;
28691 var w = curSize.width, h = curSize.height;
28692 var ow = w, oh = h;
28693 var mw = this.minWidth, mh = this.minHeight;
28694 var mxw = this.maxWidth, mxh = this.maxHeight;
28695 var wi = this.widthIncrement;
28696 var hi = this.heightIncrement;
28698 var eventXY = e.getXY();
28699 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28700 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28702 var pos = this.activeHandle.position;
28707 w = Math.min(Math.max(mw, w), mxw);
28712 h = Math.min(Math.max(mh, h), mxh);
28717 w = Math.min(Math.max(mw, w), mxw);
28718 h = Math.min(Math.max(mh, h), mxh);
28721 diffY = this.constrain(h, diffY, mh, mxh);
28728 var adiffX = Math.abs(diffX);
28729 var sub = (adiffX % wi); // how much
28730 if (sub > (wi/2)) { // far enough to snap
28731 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28733 // remove difference..
28734 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28738 x = Math.max(this.minX, x);
28741 diffX = this.constrain(w, diffX, mw, mxw);
28747 w = Math.min(Math.max(mw, w), mxw);
28748 diffY = this.constrain(h, diffY, mh, mxh);
28753 diffX = this.constrain(w, diffX, mw, mxw);
28754 diffY = this.constrain(h, diffY, mh, mxh);
28761 diffX = this.constrain(w, diffX, mw, mxw);
28763 h = Math.min(Math.max(mh, h), mxh);
28769 var sw = this.snap(w, wi, mw);
28770 var sh = this.snap(h, hi, mh);
28771 if(sw != w || sh != h){
28794 if(this.preserveRatio){
28799 h = Math.min(Math.max(mh, h), mxh);
28804 w = Math.min(Math.max(mw, w), mxw);
28809 w = Math.min(Math.max(mw, w), mxw);
28815 w = Math.min(Math.max(mw, w), mxw);
28821 h = Math.min(Math.max(mh, h), mxh);
28829 h = Math.min(Math.max(mh, h), mxh);
28839 h = Math.min(Math.max(mh, h), mxh);
28847 if (pos == 'hdrag') {
28850 this.proxy.setBounds(x, y, w, h);
28852 this.resizeElement();
28859 handleOver : function(){
28861 this.el.addClass("x-resizable-over");
28866 handleOut : function(){
28867 if(!this.resizing){
28868 this.el.removeClass("x-resizable-over");
28873 * Returns the element this component is bound to.
28874 * @return {Roo.Element}
28876 getEl : function(){
28881 * Returns the resizeChild element (or null).
28882 * @return {Roo.Element}
28884 getResizeChild : function(){
28885 return this.resizeChild;
28889 * Destroys this resizable. If the element was wrapped and
28890 * removeEl is not true then the element remains.
28891 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28893 destroy : function(removeEl){
28894 this.proxy.remove();
28896 this.overlay.removeAllListeners();
28897 this.overlay.remove();
28899 var ps = Roo.Resizable.positions;
28901 if(typeof ps[k] != "function" && this[ps[k]]){
28902 var h = this[ps[k]];
28903 h.el.removeAllListeners();
28908 this.el.update("");
28915 // hash to map config positions to true positions
28916 Roo.Resizable.positions = {
28917 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28922 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28924 // only initialize the template if resizable is used
28925 var tpl = Roo.DomHelper.createTemplate(
28926 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28929 Roo.Resizable.Handle.prototype.tpl = tpl;
28931 this.position = pos;
28933 // show north drag fro topdra
28934 var handlepos = pos == 'hdrag' ? 'north' : pos;
28936 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28937 if (pos == 'hdrag') {
28938 this.el.setStyle('cursor', 'pointer');
28940 this.el.unselectable();
28942 this.el.setOpacity(0);
28944 this.el.on("mousedown", this.onMouseDown, this);
28945 if(!disableTrackOver){
28946 this.el.on("mouseover", this.onMouseOver, this);
28947 this.el.on("mouseout", this.onMouseOut, this);
28952 Roo.Resizable.Handle.prototype = {
28953 afterResize : function(rz){
28957 onMouseDown : function(e){
28958 this.rz.onMouseDown(this, e);
28961 onMouseOver : function(e){
28962 this.rz.handleOver(this, e);
28965 onMouseOut : function(e){
28966 this.rz.handleOut(this, e);
28970 * Ext JS Library 1.1.1
28971 * Copyright(c) 2006-2007, Ext JS, LLC.
28973 * Originally Released Under LGPL - original licence link has changed is not relivant.
28976 * <script type="text/javascript">
28980 * @class Roo.Editor
28981 * @extends Roo.Component
28982 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28984 * Create a new Editor
28985 * @param {Roo.form.Field} field The Field object (or descendant)
28986 * @param {Object} config The config object
28988 Roo.Editor = function(field, config){
28989 Roo.Editor.superclass.constructor.call(this, config);
28990 this.field = field;
28993 * @event beforestartedit
28994 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28995 * false from the handler of this event.
28996 * @param {Editor} this
28997 * @param {Roo.Element} boundEl The underlying element bound to this editor
28998 * @param {Mixed} value The field value being set
29000 "beforestartedit" : true,
29003 * Fires when this editor is displayed
29004 * @param {Roo.Element} boundEl The underlying element bound to this editor
29005 * @param {Mixed} value The starting field value
29007 "startedit" : true,
29009 * @event beforecomplete
29010 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29011 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29012 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29013 * event will not fire since no edit actually occurred.
29014 * @param {Editor} this
29015 * @param {Mixed} value The current field value
29016 * @param {Mixed} startValue The original field value
29018 "beforecomplete" : true,
29021 * Fires after editing is complete and any changed value has been written to the underlying field.
29022 * @param {Editor} this
29023 * @param {Mixed} value The current field value
29024 * @param {Mixed} startValue The original field value
29028 * @event specialkey
29029 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29030 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29031 * @param {Roo.form.Field} this
29032 * @param {Roo.EventObject} e The event object
29034 "specialkey" : true
29038 Roo.extend(Roo.Editor, Roo.Component, {
29040 * @cfg {Boolean/String} autosize
29041 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29042 * or "height" to adopt the height only (defaults to false)
29045 * @cfg {Boolean} revertInvalid
29046 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29047 * validation fails (defaults to true)
29050 * @cfg {Boolean} ignoreNoChange
29051 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29052 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29053 * will never be ignored.
29056 * @cfg {Boolean} hideEl
29057 * False to keep the bound element visible while the editor is displayed (defaults to true)
29060 * @cfg {Mixed} value
29061 * The data value of the underlying field (defaults to "")
29065 * @cfg {String} alignment
29066 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29070 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29071 * for bottom-right shadow (defaults to "frame")
29075 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29079 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29081 completeOnEnter : false,
29083 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29085 cancelOnEsc : false,
29087 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29092 onRender : function(ct, position){
29093 this.el = new Roo.Layer({
29094 shadow: this.shadow,
29100 constrain: this.constrain
29102 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29103 if(this.field.msgTarget != 'title'){
29104 this.field.msgTarget = 'qtip';
29106 this.field.render(this.el);
29108 this.field.el.dom.setAttribute('autocomplete', 'off');
29110 this.field.on("specialkey", this.onSpecialKey, this);
29111 if(this.swallowKeys){
29112 this.field.el.swallowEvent(['keydown','keypress']);
29115 this.field.on("blur", this.onBlur, this);
29116 if(this.field.grow){
29117 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29121 onSpecialKey : function(field, e)
29123 //Roo.log('editor onSpecialKey');
29124 if(this.completeOnEnter && e.getKey() == e.ENTER){
29126 this.completeEdit();
29129 // do not fire special key otherwise it might hide close the editor...
29130 if(e.getKey() == e.ENTER){
29133 if(this.cancelOnEsc && e.getKey() == e.ESC){
29137 this.fireEvent('specialkey', field, e);
29142 * Starts the editing process and shows the editor.
29143 * @param {String/HTMLElement/Element} el The element to edit
29144 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29145 * to the innerHTML of el.
29147 startEdit : function(el, value){
29149 this.completeEdit();
29151 this.boundEl = Roo.get(el);
29152 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29153 if(!this.rendered){
29154 this.render(this.parentEl || document.body);
29156 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29159 this.startValue = v;
29160 this.field.setValue(v);
29162 var sz = this.boundEl.getSize();
29163 switch(this.autoSize){
29165 this.setSize(sz.width, "");
29168 this.setSize("", sz.height);
29171 this.setSize(sz.width, sz.height);
29174 this.el.alignTo(this.boundEl, this.alignment);
29175 this.editing = true;
29177 Roo.QuickTips.disable();
29183 * Sets the height and width of this editor.
29184 * @param {Number} width The new width
29185 * @param {Number} height The new height
29187 setSize : function(w, h){
29188 this.field.setSize(w, h);
29195 * Realigns the editor to the bound field based on the current alignment config value.
29197 realign : function(){
29198 this.el.alignTo(this.boundEl, this.alignment);
29202 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29203 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29205 completeEdit : function(remainVisible){
29209 var v = this.getValue();
29210 if(this.revertInvalid !== false && !this.field.isValid()){
29211 v = this.startValue;
29212 this.cancelEdit(true);
29214 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29215 this.editing = false;
29219 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29220 this.editing = false;
29221 if(this.updateEl && this.boundEl){
29222 this.boundEl.update(v);
29224 if(remainVisible !== true){
29227 this.fireEvent("complete", this, v, this.startValue);
29232 onShow : function(){
29234 if(this.hideEl !== false){
29235 this.boundEl.hide();
29238 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29239 this.fixIEFocus = true;
29240 this.deferredFocus.defer(50, this);
29242 this.field.focus();
29244 this.fireEvent("startedit", this.boundEl, this.startValue);
29247 deferredFocus : function(){
29249 this.field.focus();
29254 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29255 * reverted to the original starting value.
29256 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29257 * cancel (defaults to false)
29259 cancelEdit : function(remainVisible){
29261 this.setValue(this.startValue);
29262 if(remainVisible !== true){
29269 onBlur : function(){
29270 if(this.allowBlur !== true && this.editing){
29271 this.completeEdit();
29276 onHide : function(){
29278 this.completeEdit();
29282 if(this.field.collapse){
29283 this.field.collapse();
29286 if(this.hideEl !== false){
29287 this.boundEl.show();
29290 Roo.QuickTips.enable();
29295 * Sets the data value of the editor
29296 * @param {Mixed} value Any valid value supported by the underlying field
29298 setValue : function(v){
29299 this.field.setValue(v);
29303 * Gets the data value of the editor
29304 * @return {Mixed} The data value
29306 getValue : function(){
29307 return this.field.getValue();
29311 * Ext JS Library 1.1.1
29312 * Copyright(c) 2006-2007, Ext JS, LLC.
29314 * Originally Released Under LGPL - original licence link has changed is not relivant.
29317 * <script type="text/javascript">
29321 * @class Roo.BasicDialog
29322 * @extends Roo.util.Observable
29323 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29325 var dlg = new Roo.BasicDialog("my-dlg", {
29334 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29335 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29336 dlg.addButton('Cancel', dlg.hide, dlg);
29339 <b>A Dialog should always be a direct child of the body element.</b>
29340 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29341 * @cfg {String} title Default text to display in the title bar (defaults to null)
29342 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29343 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29344 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29345 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29346 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29347 * (defaults to null with no animation)
29348 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29349 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29350 * property for valid values (defaults to 'all')
29351 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29352 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29353 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29354 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29355 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29356 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29357 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29358 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29359 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29360 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29361 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29362 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29363 * draggable = true (defaults to false)
29364 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29365 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29366 * shadow (defaults to false)
29367 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29368 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29369 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29370 * @cfg {Array} buttons Array of buttons
29371 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29373 * Create a new BasicDialog.
29374 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29375 * @param {Object} config Configuration options
29377 Roo.BasicDialog = function(el, config){
29378 this.el = Roo.get(el);
29379 var dh = Roo.DomHelper;
29380 if(!this.el && config && config.autoCreate){
29381 if(typeof config.autoCreate == "object"){
29382 if(!config.autoCreate.id){
29383 config.autoCreate.id = el;
29385 this.el = dh.append(document.body,
29386 config.autoCreate, true);
29388 this.el = dh.append(document.body,
29389 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29393 el.setDisplayed(true);
29394 el.hide = this.hideAction;
29396 el.addClass("x-dlg");
29398 Roo.apply(this, config);
29400 this.proxy = el.createProxy("x-dlg-proxy");
29401 this.proxy.hide = this.hideAction;
29402 this.proxy.setOpacity(.5);
29406 el.setWidth(config.width);
29409 el.setHeight(config.height);
29411 this.size = el.getSize();
29412 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29413 this.xy = [config.x,config.y];
29415 this.xy = el.getCenterXY(true);
29417 /** The header element @type Roo.Element */
29418 this.header = el.child("> .x-dlg-hd");
29419 /** The body element @type Roo.Element */
29420 this.body = el.child("> .x-dlg-bd");
29421 /** The footer element @type Roo.Element */
29422 this.footer = el.child("> .x-dlg-ft");
29425 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29428 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29431 this.header.unselectable();
29433 this.header.update(this.title);
29435 // this element allows the dialog to be focused for keyboard event
29436 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29437 this.focusEl.swallowEvent("click", true);
29439 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29441 // wrap the body and footer for special rendering
29442 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29444 this.bwrap.dom.appendChild(this.footer.dom);
29447 this.bg = this.el.createChild({
29448 tag: "div", cls:"x-dlg-bg",
29449 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29451 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29454 if(this.autoScroll !== false && !this.autoTabs){
29455 this.body.setStyle("overflow", "auto");
29458 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29460 if(this.closable !== false){
29461 this.el.addClass("x-dlg-closable");
29462 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29463 this.close.on("click", this.closeClick, this);
29464 this.close.addClassOnOver("x-dlg-close-over");
29466 if(this.collapsible !== false){
29467 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29468 this.collapseBtn.on("click", this.collapseClick, this);
29469 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29470 this.header.on("dblclick", this.collapseClick, this);
29472 if(this.resizable !== false){
29473 this.el.addClass("x-dlg-resizable");
29474 this.resizer = new Roo.Resizable(el, {
29475 minWidth: this.minWidth || 80,
29476 minHeight:this.minHeight || 80,
29477 handles: this.resizeHandles || "all",
29480 this.resizer.on("beforeresize", this.beforeResize, this);
29481 this.resizer.on("resize", this.onResize, this);
29483 if(this.draggable !== false){
29484 el.addClass("x-dlg-draggable");
29485 if (!this.proxyDrag) {
29486 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29489 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29491 dd.setHandleElId(this.header.id);
29492 dd.endDrag = this.endMove.createDelegate(this);
29493 dd.startDrag = this.startMove.createDelegate(this);
29494 dd.onDrag = this.onDrag.createDelegate(this);
29499 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29500 this.mask.enableDisplayMode("block");
29502 this.el.addClass("x-dlg-modal");
29505 this.shadow = new Roo.Shadow({
29506 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29507 offset : this.shadowOffset
29510 this.shadowOffset = 0;
29512 if(Roo.useShims && this.shim !== false){
29513 this.shim = this.el.createShim();
29514 this.shim.hide = this.hideAction;
29522 if (this.buttons) {
29523 var bts= this.buttons;
29525 Roo.each(bts, function(b) {
29534 * Fires when a key is pressed
29535 * @param {Roo.BasicDialog} this
29536 * @param {Roo.EventObject} e
29541 * Fires when this dialog is moved by the user.
29542 * @param {Roo.BasicDialog} this
29543 * @param {Number} x The new page X
29544 * @param {Number} y The new page Y
29549 * Fires when this dialog is resized by the user.
29550 * @param {Roo.BasicDialog} this
29551 * @param {Number} width The new width
29552 * @param {Number} height The new height
29556 * @event beforehide
29557 * Fires before this dialog is hidden.
29558 * @param {Roo.BasicDialog} this
29560 "beforehide" : true,
29563 * Fires when this dialog is hidden.
29564 * @param {Roo.BasicDialog} this
29568 * @event beforeshow
29569 * Fires before this dialog is shown.
29570 * @param {Roo.BasicDialog} this
29572 "beforeshow" : true,
29575 * Fires when this dialog is shown.
29576 * @param {Roo.BasicDialog} this
29580 el.on("keydown", this.onKeyDown, this);
29581 el.on("mousedown", this.toFront, this);
29582 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29584 Roo.DialogManager.register(this);
29585 Roo.BasicDialog.superclass.constructor.call(this);
29588 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29589 shadowOffset: Roo.isIE ? 6 : 5,
29592 minButtonWidth: 75,
29593 defaultButton: null,
29594 buttonAlign: "right",
29599 * Sets the dialog title text
29600 * @param {String} text The title text to display
29601 * @return {Roo.BasicDialog} this
29603 setTitle : function(text){
29604 this.header.update(text);
29609 closeClick : function(){
29614 collapseClick : function(){
29615 this[this.collapsed ? "expand" : "collapse"]();
29619 * Collapses the dialog to its minimized state (only the title bar is visible).
29620 * Equivalent to the user clicking the collapse dialog button.
29622 collapse : function(){
29623 if(!this.collapsed){
29624 this.collapsed = true;
29625 this.el.addClass("x-dlg-collapsed");
29626 this.restoreHeight = this.el.getHeight();
29627 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29632 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29633 * clicking the expand dialog button.
29635 expand : function(){
29636 if(this.collapsed){
29637 this.collapsed = false;
29638 this.el.removeClass("x-dlg-collapsed");
29639 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29644 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29645 * @return {Roo.TabPanel} The tabs component
29647 initTabs : function(){
29648 var tabs = this.getTabs();
29649 while(tabs.getTab(0)){
29652 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29654 tabs.addTab(Roo.id(dom), dom.title);
29662 beforeResize : function(){
29663 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29667 onResize : function(){
29668 this.refreshSize();
29669 this.syncBodyHeight();
29670 this.adjustAssets();
29672 this.fireEvent("resize", this, this.size.width, this.size.height);
29676 onKeyDown : function(e){
29677 if(this.isVisible()){
29678 this.fireEvent("keydown", this, e);
29683 * Resizes the dialog.
29684 * @param {Number} width
29685 * @param {Number} height
29686 * @return {Roo.BasicDialog} this
29688 resizeTo : function(width, height){
29689 this.el.setSize(width, height);
29690 this.size = {width: width, height: height};
29691 this.syncBodyHeight();
29692 if(this.fixedcenter){
29695 if(this.isVisible()){
29696 this.constrainXY();
29697 this.adjustAssets();
29699 this.fireEvent("resize", this, width, height);
29705 * Resizes the dialog to fit the specified content size.
29706 * @param {Number} width
29707 * @param {Number} height
29708 * @return {Roo.BasicDialog} this
29710 setContentSize : function(w, h){
29711 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29712 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29713 //if(!this.el.isBorderBox()){
29714 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29715 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29718 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29719 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29721 this.resizeTo(w, h);
29726 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29727 * executed in response to a particular key being pressed while the dialog is active.
29728 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29729 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29730 * @param {Function} fn The function to call
29731 * @param {Object} scope (optional) The scope of the function
29732 * @return {Roo.BasicDialog} this
29734 addKeyListener : function(key, fn, scope){
29735 var keyCode, shift, ctrl, alt;
29736 if(typeof key == "object" && !(key instanceof Array)){
29737 keyCode = key["key"];
29738 shift = key["shift"];
29739 ctrl = key["ctrl"];
29744 var handler = function(dlg, e){
29745 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29746 var k = e.getKey();
29747 if(keyCode instanceof Array){
29748 for(var i = 0, len = keyCode.length; i < len; i++){
29749 if(keyCode[i] == k){
29750 fn.call(scope || window, dlg, k, e);
29756 fn.call(scope || window, dlg, k, e);
29761 this.on("keydown", handler);
29766 * Returns the TabPanel component (creates it if it doesn't exist).
29767 * Note: If you wish to simply check for the existence of tabs without creating them,
29768 * check for a null 'tabs' property.
29769 * @return {Roo.TabPanel} The tabs component
29771 getTabs : function(){
29773 this.el.addClass("x-dlg-auto-tabs");
29774 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29775 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29781 * Adds a button to the footer section of the dialog.
29782 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29783 * object or a valid Roo.DomHelper element config
29784 * @param {Function} handler The function called when the button is clicked
29785 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29786 * @return {Roo.Button} The new button
29788 addButton : function(config, handler, scope){
29789 var dh = Roo.DomHelper;
29791 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29793 if(!this.btnContainer){
29794 var tb = this.footer.createChild({
29796 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29797 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29799 this.btnContainer = tb.firstChild.firstChild.firstChild;
29804 minWidth: this.minButtonWidth,
29807 if(typeof config == "string"){
29808 bconfig.text = config;
29811 bconfig.dhconfig = config;
29813 Roo.apply(bconfig, config);
29817 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29818 bconfig.position = Math.max(0, bconfig.position);
29819 fc = this.btnContainer.childNodes[bconfig.position];
29822 var btn = new Roo.Button(
29824 this.btnContainer.insertBefore(document.createElement("td"),fc)
29825 : this.btnContainer.appendChild(document.createElement("td")),
29826 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29829 this.syncBodyHeight();
29832 * Array of all the buttons that have been added to this dialog via addButton
29837 this.buttons.push(btn);
29842 * Sets the default button to be focused when the dialog is displayed.
29843 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29844 * @return {Roo.BasicDialog} this
29846 setDefaultButton : function(btn){
29847 this.defaultButton = btn;
29852 getHeaderFooterHeight : function(safe){
29855 height += this.header.getHeight();
29858 var fm = this.footer.getMargins();
29859 height += (this.footer.getHeight()+fm.top+fm.bottom);
29861 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29862 height += this.centerBg.getPadding("tb");
29867 syncBodyHeight : function(){
29868 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29869 var height = this.size.height - this.getHeaderFooterHeight(false);
29870 bd.setHeight(height-bd.getMargins("tb"));
29871 var hh = this.header.getHeight();
29872 var h = this.size.height-hh;
29874 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29875 bw.setHeight(h-cb.getPadding("tb"));
29876 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29877 bd.setWidth(bw.getWidth(true));
29879 this.tabs.syncHeight();
29881 this.tabs.el.repaint();
29887 * Restores the previous state of the dialog if Roo.state is configured.
29888 * @return {Roo.BasicDialog} this
29890 restoreState : function(){
29891 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29892 if(box && box.width){
29893 this.xy = [box.x, box.y];
29894 this.resizeTo(box.width, box.height);
29900 beforeShow : function(){
29902 if(this.fixedcenter){
29903 this.xy = this.el.getCenterXY(true);
29906 Roo.get(document.body).addClass("x-body-masked");
29907 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29910 this.constrainXY();
29914 animShow : function(){
29915 var b = Roo.get(this.animateTarget).getBox();
29916 this.proxy.setSize(b.width, b.height);
29917 this.proxy.setLocation(b.x, b.y);
29919 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29920 true, .35, this.showEl.createDelegate(this));
29924 * Shows the dialog.
29925 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29926 * @return {Roo.BasicDialog} this
29928 show : function(animateTarget){
29929 if (this.fireEvent("beforeshow", this) === false){
29932 if(this.syncHeightBeforeShow){
29933 this.syncBodyHeight();
29934 }else if(this.firstShow){
29935 this.firstShow = false;
29936 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29938 this.animateTarget = animateTarget || this.animateTarget;
29939 if(!this.el.isVisible()){
29941 if(this.animateTarget && Roo.get(this.animateTarget)){
29951 showEl : function(){
29953 this.el.setXY(this.xy);
29955 this.adjustAssets(true);
29958 // IE peekaboo bug - fix found by Dave Fenwick
29962 this.fireEvent("show", this);
29966 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29967 * dialog itself will receive focus.
29969 focus : function(){
29970 if(this.defaultButton){
29971 this.defaultButton.focus();
29973 this.focusEl.focus();
29978 constrainXY : function(){
29979 if(this.constraintoviewport !== false){
29980 if(!this.viewSize){
29981 if(this.container){
29982 var s = this.container.getSize();
29983 this.viewSize = [s.width, s.height];
29985 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29988 var s = Roo.get(this.container||document).getScroll();
29990 var x = this.xy[0], y = this.xy[1];
29991 var w = this.size.width, h = this.size.height;
29992 var vw = this.viewSize[0], vh = this.viewSize[1];
29993 // only move it if it needs it
29995 // first validate right/bottom
29996 if(x + w > vw+s.left){
30000 if(y + h > vh+s.top){
30004 // then make sure top/left isn't negative
30016 if(this.isVisible()){
30017 this.el.setLocation(x, y);
30018 this.adjustAssets();
30025 onDrag : function(){
30026 if(!this.proxyDrag){
30027 this.xy = this.el.getXY();
30028 this.adjustAssets();
30033 adjustAssets : function(doShow){
30034 var x = this.xy[0], y = this.xy[1];
30035 var w = this.size.width, h = this.size.height;
30036 if(doShow === true){
30038 this.shadow.show(this.el);
30044 if(this.shadow && this.shadow.isVisible()){
30045 this.shadow.show(this.el);
30047 if(this.shim && this.shim.isVisible()){
30048 this.shim.setBounds(x, y, w, h);
30053 adjustViewport : function(w, h){
30055 w = Roo.lib.Dom.getViewWidth();
30056 h = Roo.lib.Dom.getViewHeight();
30059 this.viewSize = [w, h];
30060 if(this.modal && this.mask.isVisible()){
30061 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30062 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30064 if(this.isVisible()){
30065 this.constrainXY();
30070 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30071 * shadow, proxy, mask, etc.) Also removes all event listeners.
30072 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30074 destroy : function(removeEl){
30075 if(this.isVisible()){
30076 this.animateTarget = null;
30079 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30081 this.tabs.destroy(removeEl);
30094 for(var i = 0, len = this.buttons.length; i < len; i++){
30095 this.buttons[i].destroy();
30098 this.el.removeAllListeners();
30099 if(removeEl === true){
30100 this.el.update("");
30103 Roo.DialogManager.unregister(this);
30107 startMove : function(){
30108 if(this.proxyDrag){
30111 if(this.constraintoviewport !== false){
30112 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30117 endMove : function(){
30118 if(!this.proxyDrag){
30119 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30121 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30124 this.refreshSize();
30125 this.adjustAssets();
30127 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30131 * Brings this dialog to the front of any other visible dialogs
30132 * @return {Roo.BasicDialog} this
30134 toFront : function(){
30135 Roo.DialogManager.bringToFront(this);
30140 * Sends this dialog to the back (under) of any other visible dialogs
30141 * @return {Roo.BasicDialog} this
30143 toBack : function(){
30144 Roo.DialogManager.sendToBack(this);
30149 * Centers this dialog in the viewport
30150 * @return {Roo.BasicDialog} this
30152 center : function(){
30153 var xy = this.el.getCenterXY(true);
30154 this.moveTo(xy[0], xy[1]);
30159 * Moves the dialog's top-left corner to the specified point
30160 * @param {Number} x
30161 * @param {Number} y
30162 * @return {Roo.BasicDialog} this
30164 moveTo : function(x, y){
30166 if(this.isVisible()){
30167 this.el.setXY(this.xy);
30168 this.adjustAssets();
30174 * Aligns the dialog to the specified element
30175 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30176 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30177 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30178 * @return {Roo.BasicDialog} this
30180 alignTo : function(element, position, offsets){
30181 this.xy = this.el.getAlignToXY(element, position, offsets);
30182 if(this.isVisible()){
30183 this.el.setXY(this.xy);
30184 this.adjustAssets();
30190 * Anchors an element to another element and realigns it when the window is resized.
30191 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30192 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30193 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30194 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30195 * is a number, it is used as the buffer delay (defaults to 50ms).
30196 * @return {Roo.BasicDialog} this
30198 anchorTo : function(el, alignment, offsets, monitorScroll){
30199 var action = function(){
30200 this.alignTo(el, alignment, offsets);
30202 Roo.EventManager.onWindowResize(action, this);
30203 var tm = typeof monitorScroll;
30204 if(tm != 'undefined'){
30205 Roo.EventManager.on(window, 'scroll', action, this,
30206 {buffer: tm == 'number' ? monitorScroll : 50});
30213 * Returns true if the dialog is visible
30214 * @return {Boolean}
30216 isVisible : function(){
30217 return this.el.isVisible();
30221 animHide : function(callback){
30222 var b = Roo.get(this.animateTarget).getBox();
30224 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30226 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30227 this.hideEl.createDelegate(this, [callback]));
30231 * Hides the dialog.
30232 * @param {Function} callback (optional) Function to call when the dialog is hidden
30233 * @return {Roo.BasicDialog} this
30235 hide : function(callback){
30236 if (this.fireEvent("beforehide", this) === false){
30240 this.shadow.hide();
30245 // sometimes animateTarget seems to get set.. causing problems...
30246 // this just double checks..
30247 if(this.animateTarget && Roo.get(this.animateTarget)) {
30248 this.animHide(callback);
30251 this.hideEl(callback);
30257 hideEl : function(callback){
30261 Roo.get(document.body).removeClass("x-body-masked");
30263 this.fireEvent("hide", this);
30264 if(typeof callback == "function"){
30270 hideAction : function(){
30271 this.setLeft("-10000px");
30272 this.setTop("-10000px");
30273 this.setStyle("visibility", "hidden");
30277 refreshSize : function(){
30278 this.size = this.el.getSize();
30279 this.xy = this.el.getXY();
30280 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30284 // z-index is managed by the DialogManager and may be overwritten at any time
30285 setZIndex : function(index){
30287 this.mask.setStyle("z-index", index);
30290 this.shim.setStyle("z-index", ++index);
30293 this.shadow.setZIndex(++index);
30295 this.el.setStyle("z-index", ++index);
30297 this.proxy.setStyle("z-index", ++index);
30300 this.resizer.proxy.setStyle("z-index", ++index);
30303 this.lastZIndex = index;
30307 * Returns the element for this dialog
30308 * @return {Roo.Element} The underlying dialog Element
30310 getEl : function(){
30316 * @class Roo.DialogManager
30317 * Provides global access to BasicDialogs that have been created and
30318 * support for z-indexing (layering) multiple open dialogs.
30320 Roo.DialogManager = function(){
30322 var accessList = [];
30326 var sortDialogs = function(d1, d2){
30327 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30331 var orderDialogs = function(){
30332 accessList.sort(sortDialogs);
30333 var seed = Roo.DialogManager.zseed;
30334 for(var i = 0, len = accessList.length; i < len; i++){
30335 var dlg = accessList[i];
30337 dlg.setZIndex(seed + (i*10));
30344 * The starting z-index for BasicDialogs (defaults to 9000)
30345 * @type Number The z-index value
30350 register : function(dlg){
30351 list[dlg.id] = dlg;
30352 accessList.push(dlg);
30356 unregister : function(dlg){
30357 delete list[dlg.id];
30360 if(!accessList.indexOf){
30361 for( i = 0, len = accessList.length; i < len; i++){
30362 if(accessList[i] == dlg){
30363 accessList.splice(i, 1);
30368 i = accessList.indexOf(dlg);
30370 accessList.splice(i, 1);
30376 * Gets a registered dialog by id
30377 * @param {String/Object} id The id of the dialog or a dialog
30378 * @return {Roo.BasicDialog} this
30380 get : function(id){
30381 return typeof id == "object" ? id : list[id];
30385 * Brings the specified dialog to the front
30386 * @param {String/Object} dlg The id of the dialog or a dialog
30387 * @return {Roo.BasicDialog} this
30389 bringToFront : function(dlg){
30390 dlg = this.get(dlg);
30393 dlg._lastAccess = new Date().getTime();
30400 * Sends the specified dialog to the back
30401 * @param {String/Object} dlg The id of the dialog or a dialog
30402 * @return {Roo.BasicDialog} this
30404 sendToBack : function(dlg){
30405 dlg = this.get(dlg);
30406 dlg._lastAccess = -(new Date().getTime());
30412 * Hides all dialogs
30414 hideAll : function(){
30415 for(var id in list){
30416 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30425 * @class Roo.LayoutDialog
30426 * @extends Roo.BasicDialog
30427 * Dialog which provides adjustments for working with a layout in a Dialog.
30428 * Add your necessary layout config options to the dialog's config.<br>
30429 * Example usage (including a nested layout):
30432 dialog = new Roo.LayoutDialog("download-dlg", {
30441 // layout config merges with the dialog config
30443 tabPosition: "top",
30444 alwaysShowTabs: true
30447 dialog.addKeyListener(27, dialog.hide, dialog);
30448 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30449 dialog.addButton("Build It!", this.getDownload, this);
30451 // we can even add nested layouts
30452 var innerLayout = new Roo.BorderLayout("dl-inner", {
30462 innerLayout.beginUpdate();
30463 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30464 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30465 innerLayout.endUpdate(true);
30467 var layout = dialog.getLayout();
30468 layout.beginUpdate();
30469 layout.add("center", new Roo.ContentPanel("standard-panel",
30470 {title: "Download the Source", fitToFrame:true}));
30471 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30472 {title: "Build your own roo.js"}));
30473 layout.getRegion("center").showPanel(sp);
30474 layout.endUpdate();
30478 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30479 * @param {Object} config configuration options
30481 Roo.LayoutDialog = function(el, cfg){
30484 if (typeof(cfg) == 'undefined') {
30485 config = Roo.apply({}, el);
30486 // not sure why we use documentElement here.. - it should always be body.
30487 // IE7 borks horribly if we use documentElement.
30488 // webkit also does not like documentElement - it creates a body element...
30489 el = Roo.get( document.body || document.documentElement ).createChild();
30490 //config.autoCreate = true;
30494 config.autoTabs = false;
30495 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30496 this.body.setStyle({overflow:"hidden", position:"relative"});
30497 this.layout = new Roo.BorderLayout(this.body.dom, config);
30498 this.layout.monitorWindowResize = false;
30499 this.el.addClass("x-dlg-auto-layout");
30500 // fix case when center region overwrites center function
30501 this.center = Roo.BasicDialog.prototype.center;
30502 this.on("show", this.layout.layout, this.layout, true);
30503 if (config.items) {
30504 var xitems = config.items;
30505 delete config.items;
30506 Roo.each(xitems, this.addxtype, this);
30511 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30513 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30516 endUpdate : function(){
30517 this.layout.endUpdate();
30521 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30524 beginUpdate : function(){
30525 this.layout.beginUpdate();
30529 * Get the BorderLayout for this dialog
30530 * @return {Roo.BorderLayout}
30532 getLayout : function(){
30533 return this.layout;
30536 showEl : function(){
30537 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30539 this.layout.layout();
30544 // Use the syncHeightBeforeShow config option to control this automatically
30545 syncBodyHeight : function(){
30546 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30547 if(this.layout){this.layout.layout();}
30551 * Add an xtype element (actually adds to the layout.)
30552 * @return {Object} xdata xtype object data.
30555 addxtype : function(c) {
30556 return this.layout.addxtype(c);
30560 * Ext JS Library 1.1.1
30561 * Copyright(c) 2006-2007, Ext JS, LLC.
30563 * Originally Released Under LGPL - original licence link has changed is not relivant.
30566 * <script type="text/javascript">
30570 * @class Roo.MessageBox
30571 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30575 Roo.Msg.alert('Status', 'Changes saved successfully.');
30577 // Prompt for user data:
30578 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30580 // process text value...
30584 // Show a dialog using config options:
30586 title:'Save Changes?',
30587 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30588 buttons: Roo.Msg.YESNOCANCEL,
30595 Roo.MessageBox = function(){
30596 var dlg, opt, mask, waitTimer;
30597 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30598 var buttons, activeTextEl, bwidth;
30601 var handleButton = function(button){
30603 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30607 var handleHide = function(){
30608 if(opt && opt.cls){
30609 dlg.el.removeClass(opt.cls);
30612 Roo.TaskMgr.stop(waitTimer);
30618 var updateButtons = function(b){
30621 buttons["ok"].hide();
30622 buttons["cancel"].hide();
30623 buttons["yes"].hide();
30624 buttons["no"].hide();
30625 dlg.footer.dom.style.display = 'none';
30628 dlg.footer.dom.style.display = '';
30629 for(var k in buttons){
30630 if(typeof buttons[k] != "function"){
30633 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30634 width += buttons[k].el.getWidth()+15;
30644 var handleEsc = function(d, k, e){
30645 if(opt && opt.closable !== false){
30655 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30656 * @return {Roo.BasicDialog} The BasicDialog element
30658 getDialog : function(){
30660 dlg = new Roo.BasicDialog("x-msg-box", {
30665 constraintoviewport:false,
30667 collapsible : false,
30670 width:400, height:100,
30671 buttonAlign:"center",
30672 closeClick : function(){
30673 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30674 handleButton("no");
30676 handleButton("cancel");
30680 dlg.on("hide", handleHide);
30682 dlg.addKeyListener(27, handleEsc);
30684 var bt = this.buttonText;
30685 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30686 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30687 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30688 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30689 bodyEl = dlg.body.createChild({
30691 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>'
30693 msgEl = bodyEl.dom.firstChild;
30694 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30695 textboxEl.enableDisplayMode();
30696 textboxEl.addKeyListener([10,13], function(){
30697 if(dlg.isVisible() && opt && opt.buttons){
30698 if(opt.buttons.ok){
30699 handleButton("ok");
30700 }else if(opt.buttons.yes){
30701 handleButton("yes");
30705 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30706 textareaEl.enableDisplayMode();
30707 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30708 progressEl.enableDisplayMode();
30709 var pf = progressEl.dom.firstChild;
30711 pp = Roo.get(pf.firstChild);
30712 pp.setHeight(pf.offsetHeight);
30720 * Updates the message box body text
30721 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30722 * the XHTML-compliant non-breaking space character '&#160;')
30723 * @return {Roo.MessageBox} This message box
30725 updateText : function(text){
30726 if(!dlg.isVisible() && !opt.width){
30727 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30729 msgEl.innerHTML = text || ' ';
30731 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30732 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30734 Math.min(opt.width || cw , this.maxWidth),
30735 Math.max(opt.minWidth || this.minWidth, bwidth)
30738 activeTextEl.setWidth(w);
30740 if(dlg.isVisible()){
30741 dlg.fixedcenter = false;
30743 // to big, make it scroll. = But as usual stupid IE does not support
30746 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30747 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30748 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30750 bodyEl.dom.style.height = '';
30751 bodyEl.dom.style.overflowY = '';
30754 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30756 bodyEl.dom.style.overflowX = '';
30759 dlg.setContentSize(w, bodyEl.getHeight());
30760 if(dlg.isVisible()){
30761 dlg.fixedcenter = true;
30767 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30768 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30769 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30770 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30771 * @return {Roo.MessageBox} This message box
30773 updateProgress : function(value, text){
30775 this.updateText(text);
30777 if (pp) { // weird bug on my firefox - for some reason this is not defined
30778 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30784 * Returns true if the message box is currently displayed
30785 * @return {Boolean} True if the message box is visible, else false
30787 isVisible : function(){
30788 return dlg && dlg.isVisible();
30792 * Hides the message box if it is displayed
30795 if(this.isVisible()){
30801 * Displays a new message box, or reinitializes an existing message box, based on the config options
30802 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30803 * The following config object properties are supported:
30805 Property Type Description
30806 ---------- --------------- ------------------------------------------------------------------------------------
30807 animEl String/Element An id or Element from which the message box should animate as it opens and
30808 closes (defaults to undefined)
30809 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30810 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30811 closable Boolean False to hide the top-right close button (defaults to true). Note that
30812 progress and wait dialogs will ignore this property and always hide the
30813 close button as they can only be closed programmatically.
30814 cls String A custom CSS class to apply to the message box element
30815 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30816 displayed (defaults to 75)
30817 fn Function A callback function to execute after closing the dialog. The arguments to the
30818 function will be btn (the name of the button that was clicked, if applicable,
30819 e.g. "ok"), and text (the value of the active text field, if applicable).
30820 Progress and wait dialogs will ignore this option since they do not respond to
30821 user actions and can only be closed programmatically, so any required function
30822 should be called by the same code after it closes the dialog.
30823 icon String A CSS class that provides a background image to be used as an icon for
30824 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30825 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30826 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30827 modal Boolean False to allow user interaction with the page while the message box is
30828 displayed (defaults to true)
30829 msg String A string that will replace the existing message box body text (defaults
30830 to the XHTML-compliant non-breaking space character ' ')
30831 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30832 progress Boolean True to display a progress bar (defaults to false)
30833 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30834 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30835 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30836 title String The title text
30837 value String The string value to set into the active textbox element if displayed
30838 wait Boolean True to display a progress bar (defaults to false)
30839 width Number The width of the dialog in pixels
30846 msg: 'Please enter your address:',
30848 buttons: Roo.MessageBox.OKCANCEL,
30851 animEl: 'addAddressBtn'
30854 * @param {Object} config Configuration options
30855 * @return {Roo.MessageBox} This message box
30857 show : function(options)
30860 // this causes nightmares if you show one dialog after another
30861 // especially on callbacks..
30863 if(this.isVisible()){
30866 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30867 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30868 Roo.log("New Dialog Message:" + options.msg )
30869 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30870 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30873 var d = this.getDialog();
30875 d.setTitle(opt.title || " ");
30876 d.close.setDisplayed(opt.closable !== false);
30877 activeTextEl = textboxEl;
30878 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30883 textareaEl.setHeight(typeof opt.multiline == "number" ?
30884 opt.multiline : this.defaultTextHeight);
30885 activeTextEl = textareaEl;
30894 progressEl.setDisplayed(opt.progress === true);
30895 this.updateProgress(0);
30896 activeTextEl.dom.value = opt.value || "";
30898 dlg.setDefaultButton(activeTextEl);
30900 var bs = opt.buttons;
30903 db = buttons["ok"];
30904 }else if(bs && bs.yes){
30905 db = buttons["yes"];
30907 dlg.setDefaultButton(db);
30909 bwidth = updateButtons(opt.buttons);
30910 this.updateText(opt.msg);
30912 d.el.addClass(opt.cls);
30914 d.proxyDrag = opt.proxyDrag === true;
30915 d.modal = opt.modal !== false;
30916 d.mask = opt.modal !== false ? mask : false;
30917 if(!d.isVisible()){
30918 // force it to the end of the z-index stack so it gets a cursor in FF
30919 document.body.appendChild(dlg.el.dom);
30920 d.animateTarget = null;
30921 d.show(options.animEl);
30927 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30928 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30929 * and closing the message box when the process is complete.
30930 * @param {String} title The title bar text
30931 * @param {String} msg The message box body text
30932 * @return {Roo.MessageBox} This message box
30934 progress : function(title, msg){
30941 minWidth: this.minProgressWidth,
30948 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30949 * If a callback function is passed it will be called after the user clicks the button, and the
30950 * id of the button that was clicked will be passed as the only parameter to the callback
30951 * (could also be the top-right close button).
30952 * @param {String} title The title bar text
30953 * @param {String} msg The message box body text
30954 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30955 * @param {Object} scope (optional) The scope of the callback function
30956 * @return {Roo.MessageBox} This message box
30958 alert : function(title, msg, fn, scope){
30971 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30972 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30973 * You are responsible for closing the message box when the process is complete.
30974 * @param {String} msg The message box body text
30975 * @param {String} title (optional) The title bar text
30976 * @return {Roo.MessageBox} This message box
30978 wait : function(msg, title){
30989 waitTimer = Roo.TaskMgr.start({
30991 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30999 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31000 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31001 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31002 * @param {String} title The title bar text
31003 * @param {String} msg The message box body text
31004 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31005 * @param {Object} scope (optional) The scope of the callback function
31006 * @return {Roo.MessageBox} This message box
31008 confirm : function(title, msg, fn, scope){
31012 buttons: this.YESNO,
31021 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31022 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31023 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31024 * (could also be the top-right close button) and the text that was entered will be passed as the two
31025 * parameters to the callback.
31026 * @param {String} title The title bar text
31027 * @param {String} msg The message box body text
31028 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31029 * @param {Object} scope (optional) The scope of the callback function
31030 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31031 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31032 * @return {Roo.MessageBox} This message box
31034 prompt : function(title, msg, fn, scope, multiline){
31038 buttons: this.OKCANCEL,
31043 multiline: multiline,
31050 * Button config that displays a single OK button
31055 * Button config that displays Yes and No buttons
31058 YESNO : {yes:true, no:true},
31060 * Button config that displays OK and Cancel buttons
31063 OKCANCEL : {ok:true, cancel:true},
31065 * Button config that displays Yes, No and Cancel buttons
31068 YESNOCANCEL : {yes:true, no:true, cancel:true},
31071 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31074 defaultTextHeight : 75,
31076 * The maximum width in pixels of the message box (defaults to 600)
31081 * The minimum width in pixels of the message box (defaults to 100)
31086 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31087 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31090 minProgressWidth : 250,
31092 * An object containing the default button text strings that can be overriden for localized language support.
31093 * Supported properties are: ok, cancel, yes and no.
31094 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31107 * Shorthand for {@link Roo.MessageBox}
31109 Roo.Msg = Roo.MessageBox;/*
31111 * Ext JS Library 1.1.1
31112 * Copyright(c) 2006-2007, Ext JS, LLC.
31114 * Originally Released Under LGPL - original licence link has changed is not relivant.
31117 * <script type="text/javascript">
31120 * @class Roo.QuickTips
31121 * Provides attractive and customizable tooltips for any element.
31124 Roo.QuickTips = function(){
31125 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31126 var ce, bd, xy, dd;
31127 var visible = false, disabled = true, inited = false;
31128 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31130 var onOver = function(e){
31134 var t = e.getTarget();
31135 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31138 if(ce && t == ce.el){
31139 clearTimeout(hideProc);
31142 if(t && tagEls[t.id]){
31143 tagEls[t.id].el = t;
31144 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31147 var ttp, et = Roo.fly(t);
31148 var ns = cfg.namespace;
31149 if(tm.interceptTitles && t.title){
31152 t.removeAttribute("title");
31153 e.preventDefault();
31155 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31158 showProc = show.defer(tm.showDelay, tm, [{
31161 width: et.getAttributeNS(ns, cfg.width),
31162 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31163 title: et.getAttributeNS(ns, cfg.title),
31164 cls: et.getAttributeNS(ns, cfg.cls)
31169 var onOut = function(e){
31170 clearTimeout(showProc);
31171 var t = e.getTarget();
31172 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31173 hideProc = setTimeout(hide, tm.hideDelay);
31177 var onMove = function(e){
31183 if(tm.trackMouse && ce){
31188 var onDown = function(e){
31189 clearTimeout(showProc);
31190 clearTimeout(hideProc);
31192 if(tm.hideOnClick){
31195 tm.enable.defer(100, tm);
31200 var getPad = function(){
31201 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31204 var show = function(o){
31208 clearTimeout(dismissProc);
31210 if(removeCls){ // in case manually hidden
31211 el.removeClass(removeCls);
31215 el.addClass(ce.cls);
31216 removeCls = ce.cls;
31219 tipTitle.update(ce.title);
31222 tipTitle.update('');
31225 el.dom.style.width = tm.maxWidth+'px';
31226 //tipBody.dom.style.width = '';
31227 tipBodyText.update(o.text);
31228 var p = getPad(), w = ce.width;
31230 var td = tipBodyText.dom;
31231 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31232 if(aw > tm.maxWidth){
31234 }else if(aw < tm.minWidth){
31240 //tipBody.setWidth(w);
31241 el.setWidth(parseInt(w, 10) + p);
31242 if(ce.autoHide === false){
31243 close.setDisplayed(true);
31248 close.setDisplayed(false);
31254 el.avoidY = xy[1]-18;
31259 el.setStyle("visibility", "visible");
31260 el.fadeIn({callback: afterShow});
31266 var afterShow = function(){
31270 if(tm.autoDismiss && ce.autoHide !== false){
31271 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31276 var hide = function(noanim){
31277 clearTimeout(dismissProc);
31278 clearTimeout(hideProc);
31280 if(el.isVisible()){
31282 if(noanim !== true && tm.animate){
31283 el.fadeOut({callback: afterHide});
31290 var afterHide = function(){
31293 el.removeClass(removeCls);
31300 * @cfg {Number} minWidth
31301 * The minimum width of the quick tip (defaults to 40)
31305 * @cfg {Number} maxWidth
31306 * The maximum width of the quick tip (defaults to 300)
31310 * @cfg {Boolean} interceptTitles
31311 * True to automatically use the element's DOM title value if available (defaults to false)
31313 interceptTitles : false,
31315 * @cfg {Boolean} trackMouse
31316 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31318 trackMouse : false,
31320 * @cfg {Boolean} hideOnClick
31321 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31323 hideOnClick : true,
31325 * @cfg {Number} showDelay
31326 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31330 * @cfg {Number} hideDelay
31331 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31335 * @cfg {Boolean} autoHide
31336 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31337 * Used in conjunction with hideDelay.
31342 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31343 * (defaults to true). Used in conjunction with autoDismissDelay.
31345 autoDismiss : true,
31348 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31350 autoDismissDelay : 5000,
31352 * @cfg {Boolean} animate
31353 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31358 * @cfg {String} title
31359 * Title text to display (defaults to ''). This can be any valid HTML markup.
31363 * @cfg {String} text
31364 * Body text to display (defaults to ''). This can be any valid HTML markup.
31368 * @cfg {String} cls
31369 * A CSS class to apply to the base quick tip element (defaults to '').
31373 * @cfg {Number} width
31374 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31375 * minWidth or maxWidth.
31380 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31381 * or display QuickTips in a page.
31384 tm = Roo.QuickTips;
31385 cfg = tm.tagConfig;
31387 if(!Roo.isReady){ // allow calling of init() before onReady
31388 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31391 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31392 el.fxDefaults = {stopFx: true};
31393 // maximum custom styling
31394 //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>');
31395 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>');
31396 tipTitle = el.child('h3');
31397 tipTitle.enableDisplayMode("block");
31398 tipBody = el.child('div.x-tip-bd');
31399 tipBodyText = el.child('div.x-tip-bd-inner');
31400 //bdLeft = el.child('div.x-tip-bd-left');
31401 //bdRight = el.child('div.x-tip-bd-right');
31402 close = el.child('div.x-tip-close');
31403 close.enableDisplayMode("block");
31404 close.on("click", hide);
31405 var d = Roo.get(document);
31406 d.on("mousedown", onDown);
31407 d.on("mouseover", onOver);
31408 d.on("mouseout", onOut);
31409 d.on("mousemove", onMove);
31410 esc = d.addKeyListener(27, hide);
31413 dd = el.initDD("default", null, {
31414 onDrag : function(){
31418 dd.setHandleElId(tipTitle.id);
31427 * Configures a new quick tip instance and assigns it to a target element. The following config options
31430 Property Type Description
31431 ---------- --------------------- ------------------------------------------------------------------------
31432 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31434 * @param {Object} config The config object
31436 register : function(config){
31437 var cs = config instanceof Array ? config : arguments;
31438 for(var i = 0, len = cs.length; i < len; i++) {
31440 var target = c.target;
31442 if(target instanceof Array){
31443 for(var j = 0, jlen = target.length; j < jlen; j++){
31444 tagEls[target[j]] = c;
31447 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31454 * Removes this quick tip from its element and destroys it.
31455 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31457 unregister : function(el){
31458 delete tagEls[Roo.id(el)];
31462 * Enable this quick tip.
31464 enable : function(){
31465 if(inited && disabled){
31467 if(locks.length < 1){
31474 * Disable this quick tip.
31476 disable : function(){
31478 clearTimeout(showProc);
31479 clearTimeout(hideProc);
31480 clearTimeout(dismissProc);
31488 * Returns true if the quick tip is enabled, else false.
31490 isEnabled : function(){
31497 attribute : "qtip",
31507 // backwards compat
31508 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31510 * Ext JS Library 1.1.1
31511 * Copyright(c) 2006-2007, Ext JS, LLC.
31513 * Originally Released Under LGPL - original licence link has changed is not relivant.
31516 * <script type="text/javascript">
31521 * @class Roo.tree.TreePanel
31522 * @extends Roo.data.Tree
31524 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31525 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31526 * @cfg {Boolean} enableDD true to enable drag and drop
31527 * @cfg {Boolean} enableDrag true to enable just drag
31528 * @cfg {Boolean} enableDrop true to enable just drop
31529 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31530 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31531 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31532 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31533 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31534 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31535 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31536 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31537 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31538 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31539 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31540 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31541 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31542 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31543 * @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>
31544 * @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>
31547 * @param {String/HTMLElement/Element} el The container element
31548 * @param {Object} config
31550 Roo.tree.TreePanel = function(el, config){
31552 var loader = false;
31554 root = config.root;
31555 delete config.root;
31557 if (config.loader) {
31558 loader = config.loader;
31559 delete config.loader;
31562 Roo.apply(this, config);
31563 Roo.tree.TreePanel.superclass.constructor.call(this);
31564 this.el = Roo.get(el);
31565 this.el.addClass('x-tree');
31566 //console.log(root);
31568 this.setRootNode( Roo.factory(root, Roo.tree));
31571 this.loader = Roo.factory(loader, Roo.tree);
31574 * Read-only. The id of the container element becomes this TreePanel's id.
31576 this.id = this.el.id;
31579 * @event beforeload
31580 * Fires before a node is loaded, return false to cancel
31581 * @param {Node} node The node being loaded
31583 "beforeload" : true,
31586 * Fires when a node is loaded
31587 * @param {Node} node The node that was loaded
31591 * @event textchange
31592 * Fires when the text for a node is changed
31593 * @param {Node} node The node
31594 * @param {String} text The new text
31595 * @param {String} oldText The old text
31597 "textchange" : true,
31599 * @event beforeexpand
31600 * Fires before a node is expanded, return false to cancel.
31601 * @param {Node} node The node
31602 * @param {Boolean} deep
31603 * @param {Boolean} anim
31605 "beforeexpand" : true,
31607 * @event beforecollapse
31608 * Fires before a node is collapsed, return false to cancel.
31609 * @param {Node} node The node
31610 * @param {Boolean} deep
31611 * @param {Boolean} anim
31613 "beforecollapse" : true,
31616 * Fires when a node is expanded
31617 * @param {Node} node The node
31621 * @event disabledchange
31622 * Fires when the disabled status of a node changes
31623 * @param {Node} node The node
31624 * @param {Boolean} disabled
31626 "disabledchange" : true,
31629 * Fires when a node is collapsed
31630 * @param {Node} node The node
31634 * @event beforeclick
31635 * Fires before click processing on a node. Return false to cancel the default action.
31636 * @param {Node} node The node
31637 * @param {Roo.EventObject} e The event object
31639 "beforeclick":true,
31641 * @event checkchange
31642 * Fires when a node with a checkbox's checked property changes
31643 * @param {Node} this This node
31644 * @param {Boolean} checked
31646 "checkchange":true,
31649 * Fires when a node is clicked
31650 * @param {Node} node The node
31651 * @param {Roo.EventObject} e The event object
31656 * Fires when a node is double clicked
31657 * @param {Node} node The node
31658 * @param {Roo.EventObject} e The event object
31662 * @event contextmenu
31663 * Fires when a node is right clicked
31664 * @param {Node} node The node
31665 * @param {Roo.EventObject} e The event object
31667 "contextmenu":true,
31669 * @event beforechildrenrendered
31670 * Fires right before the child nodes for a node are rendered
31671 * @param {Node} node The node
31673 "beforechildrenrendered":true,
31676 * Fires when a node starts being dragged
31677 * @param {Roo.tree.TreePanel} this
31678 * @param {Roo.tree.TreeNode} node
31679 * @param {event} e The raw browser event
31681 "startdrag" : true,
31684 * Fires when a drag operation is complete
31685 * @param {Roo.tree.TreePanel} this
31686 * @param {Roo.tree.TreeNode} node
31687 * @param {event} e The raw browser event
31692 * Fires when a dragged node is dropped on a valid DD target
31693 * @param {Roo.tree.TreePanel} this
31694 * @param {Roo.tree.TreeNode} node
31695 * @param {DD} dd The dd it was dropped on
31696 * @param {event} e The raw browser event
31700 * @event beforenodedrop
31701 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31702 * passed to handlers has the following properties:<br />
31703 * <ul style="padding:5px;padding-left:16px;">
31704 * <li>tree - The TreePanel</li>
31705 * <li>target - The node being targeted for the drop</li>
31706 * <li>data - The drag data from the drag source</li>
31707 * <li>point - The point of the drop - append, above or below</li>
31708 * <li>source - The drag source</li>
31709 * <li>rawEvent - Raw mouse event</li>
31710 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31711 * to be inserted by setting them on this object.</li>
31712 * <li>cancel - Set this to true to cancel the drop.</li>
31714 * @param {Object} dropEvent
31716 "beforenodedrop" : true,
31719 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31720 * passed to handlers has the following properties:<br />
31721 * <ul style="padding:5px;padding-left:16px;">
31722 * <li>tree - The TreePanel</li>
31723 * <li>target - The node being targeted for the drop</li>
31724 * <li>data - The drag data from the drag source</li>
31725 * <li>point - The point of the drop - append, above or below</li>
31726 * <li>source - The drag source</li>
31727 * <li>rawEvent - Raw mouse event</li>
31728 * <li>dropNode - Dropped node(s).</li>
31730 * @param {Object} dropEvent
31734 * @event nodedragover
31735 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31736 * passed to handlers has the following properties:<br />
31737 * <ul style="padding:5px;padding-left:16px;">
31738 * <li>tree - The TreePanel</li>
31739 * <li>target - The node being targeted for the drop</li>
31740 * <li>data - The drag data from the drag source</li>
31741 * <li>point - The point of the drop - append, above or below</li>
31742 * <li>source - The drag source</li>
31743 * <li>rawEvent - Raw mouse event</li>
31744 * <li>dropNode - Drop node(s) provided by the source.</li>
31745 * <li>cancel - Set this to true to signal drop not allowed.</li>
31747 * @param {Object} dragOverEvent
31749 "nodedragover" : true
31752 if(this.singleExpand){
31753 this.on("beforeexpand", this.restrictExpand, this);
31756 this.editor.tree = this;
31757 this.editor = Roo.factory(this.editor, Roo.tree);
31760 if (this.selModel) {
31761 this.selModel = Roo.factory(this.selModel, Roo.tree);
31765 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31766 rootVisible : true,
31767 animate: Roo.enableFx,
31770 hlDrop : Roo.enableFx,
31774 rendererTip: false,
31776 restrictExpand : function(node){
31777 var p = node.parentNode;
31779 if(p.expandedChild && p.expandedChild.parentNode == p){
31780 p.expandedChild.collapse();
31782 p.expandedChild = node;
31786 // private override
31787 setRootNode : function(node){
31788 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31789 if(!this.rootVisible){
31790 node.ui = new Roo.tree.RootTreeNodeUI(node);
31796 * Returns the container element for this TreePanel
31798 getEl : function(){
31803 * Returns the default TreeLoader for this TreePanel
31805 getLoader : function(){
31806 return this.loader;
31812 expandAll : function(){
31813 this.root.expand(true);
31817 * Collapse all nodes
31819 collapseAll : function(){
31820 this.root.collapse(true);
31824 * Returns the selection model used by this TreePanel
31826 getSelectionModel : function(){
31827 if(!this.selModel){
31828 this.selModel = new Roo.tree.DefaultSelectionModel();
31830 return this.selModel;
31834 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31835 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31836 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31839 getChecked : function(a, startNode){
31840 startNode = startNode || this.root;
31842 var f = function(){
31843 if(this.attributes.checked){
31844 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31847 startNode.cascade(f);
31852 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31853 * @param {String} path
31854 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31855 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31856 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31858 expandPath : function(path, attr, callback){
31859 attr = attr || "id";
31860 var keys = path.split(this.pathSeparator);
31861 var curNode = this.root;
31862 if(curNode.attributes[attr] != keys[1]){ // invalid root
31864 callback(false, null);
31869 var f = function(){
31870 if(++index == keys.length){
31872 callback(true, curNode);
31876 var c = curNode.findChild(attr, keys[index]);
31879 callback(false, curNode);
31884 c.expand(false, false, f);
31886 curNode.expand(false, false, f);
31890 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31891 * @param {String} path
31892 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31893 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31894 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31896 selectPath : function(path, attr, callback){
31897 attr = attr || "id";
31898 var keys = path.split(this.pathSeparator);
31899 var v = keys.pop();
31900 if(keys.length > 0){
31901 var f = function(success, node){
31902 if(success && node){
31903 var n = node.findChild(attr, v);
31909 }else if(callback){
31910 callback(false, n);
31914 callback(false, n);
31918 this.expandPath(keys.join(this.pathSeparator), attr, f);
31920 this.root.select();
31922 callback(true, this.root);
31927 getTreeEl : function(){
31932 * Trigger rendering of this TreePanel
31934 render : function(){
31935 if (this.innerCt) {
31936 return this; // stop it rendering more than once!!
31939 this.innerCt = this.el.createChild({tag:"ul",
31940 cls:"x-tree-root-ct " +
31941 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31943 if(this.containerScroll){
31944 Roo.dd.ScrollManager.register(this.el);
31946 if((this.enableDD || this.enableDrop) && !this.dropZone){
31948 * The dropZone used by this tree if drop is enabled
31949 * @type Roo.tree.TreeDropZone
31951 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31952 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31955 if((this.enableDD || this.enableDrag) && !this.dragZone){
31957 * The dragZone used by this tree if drag is enabled
31958 * @type Roo.tree.TreeDragZone
31960 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31961 ddGroup: this.ddGroup || "TreeDD",
31962 scroll: this.ddScroll
31965 this.getSelectionModel().init(this);
31967 Roo.log("ROOT not set in tree");
31970 this.root.render();
31971 if(!this.rootVisible){
31972 this.root.renderChildren();
31978 * Ext JS Library 1.1.1
31979 * Copyright(c) 2006-2007, Ext JS, LLC.
31981 * Originally Released Under LGPL - original licence link has changed is not relivant.
31984 * <script type="text/javascript">
31989 * @class Roo.tree.DefaultSelectionModel
31990 * @extends Roo.util.Observable
31991 * The default single selection for a TreePanel.
31992 * @param {Object} cfg Configuration
31994 Roo.tree.DefaultSelectionModel = function(cfg){
31995 this.selNode = null;
32001 * @event selectionchange
32002 * Fires when the selected node changes
32003 * @param {DefaultSelectionModel} this
32004 * @param {TreeNode} node the new selection
32006 "selectionchange" : true,
32009 * @event beforeselect
32010 * Fires before the selected node changes, return false to cancel the change
32011 * @param {DefaultSelectionModel} this
32012 * @param {TreeNode} node the new selection
32013 * @param {TreeNode} node the old selection
32015 "beforeselect" : true
32018 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32021 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32022 init : function(tree){
32024 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32025 tree.on("click", this.onNodeClick, this);
32028 onNodeClick : function(node, e){
32029 if (e.ctrlKey && this.selNode == node) {
32030 this.unselect(node);
32038 * @param {TreeNode} node The node to select
32039 * @return {TreeNode} The selected node
32041 select : function(node){
32042 var last = this.selNode;
32043 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32045 last.ui.onSelectedChange(false);
32047 this.selNode = node;
32048 node.ui.onSelectedChange(true);
32049 this.fireEvent("selectionchange", this, node, last);
32056 * @param {TreeNode} node The node to unselect
32058 unselect : function(node){
32059 if(this.selNode == node){
32060 this.clearSelections();
32065 * Clear all selections
32067 clearSelections : function(){
32068 var n = this.selNode;
32070 n.ui.onSelectedChange(false);
32071 this.selNode = null;
32072 this.fireEvent("selectionchange", this, null);
32078 * Get the selected node
32079 * @return {TreeNode} The selected node
32081 getSelectedNode : function(){
32082 return this.selNode;
32086 * Returns true if the node is selected
32087 * @param {TreeNode} node The node to check
32088 * @return {Boolean}
32090 isSelected : function(node){
32091 return this.selNode == node;
32095 * Selects the node above the selected node in the tree, intelligently walking the nodes
32096 * @return TreeNode The new selection
32098 selectPrevious : function(){
32099 var s = this.selNode || this.lastSelNode;
32103 var ps = s.previousSibling;
32105 if(!ps.isExpanded() || ps.childNodes.length < 1){
32106 return this.select(ps);
32108 var lc = ps.lastChild;
32109 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32112 return this.select(lc);
32114 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32115 return this.select(s.parentNode);
32121 * Selects the node above the selected node in the tree, intelligently walking the nodes
32122 * @return TreeNode The new selection
32124 selectNext : function(){
32125 var s = this.selNode || this.lastSelNode;
32129 if(s.firstChild && s.isExpanded()){
32130 return this.select(s.firstChild);
32131 }else if(s.nextSibling){
32132 return this.select(s.nextSibling);
32133 }else if(s.parentNode){
32135 s.parentNode.bubble(function(){
32136 if(this.nextSibling){
32137 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32146 onKeyDown : function(e){
32147 var s = this.selNode || this.lastSelNode;
32148 // undesirable, but required
32153 var k = e.getKey();
32161 this.selectPrevious();
32164 e.preventDefault();
32165 if(s.hasChildNodes()){
32166 if(!s.isExpanded()){
32168 }else if(s.firstChild){
32169 this.select(s.firstChild, e);
32174 e.preventDefault();
32175 if(s.hasChildNodes() && s.isExpanded()){
32177 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32178 this.select(s.parentNode, e);
32186 * @class Roo.tree.MultiSelectionModel
32187 * @extends Roo.util.Observable
32188 * Multi selection for a TreePanel.
32189 * @param {Object} cfg Configuration
32191 Roo.tree.MultiSelectionModel = function(){
32192 this.selNodes = [];
32196 * @event selectionchange
32197 * Fires when the selected nodes change
32198 * @param {MultiSelectionModel} this
32199 * @param {Array} nodes Array of the selected nodes
32201 "selectionchange" : true
32203 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32207 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32208 init : function(tree){
32210 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32211 tree.on("click", this.onNodeClick, this);
32214 onNodeClick : function(node, e){
32215 this.select(node, e, e.ctrlKey);
32220 * @param {TreeNode} node The node to select
32221 * @param {EventObject} e (optional) An event associated with the selection
32222 * @param {Boolean} keepExisting True to retain existing selections
32223 * @return {TreeNode} The selected node
32225 select : function(node, e, keepExisting){
32226 if(keepExisting !== true){
32227 this.clearSelections(true);
32229 if(this.isSelected(node)){
32230 this.lastSelNode = node;
32233 this.selNodes.push(node);
32234 this.selMap[node.id] = node;
32235 this.lastSelNode = node;
32236 node.ui.onSelectedChange(true);
32237 this.fireEvent("selectionchange", this, this.selNodes);
32243 * @param {TreeNode} node The node to unselect
32245 unselect : function(node){
32246 if(this.selMap[node.id]){
32247 node.ui.onSelectedChange(false);
32248 var sn = this.selNodes;
32251 index = sn.indexOf(node);
32253 for(var i = 0, len = sn.length; i < len; i++){
32261 this.selNodes.splice(index, 1);
32263 delete this.selMap[node.id];
32264 this.fireEvent("selectionchange", this, this.selNodes);
32269 * Clear all selections
32271 clearSelections : function(suppressEvent){
32272 var sn = this.selNodes;
32274 for(var i = 0, len = sn.length; i < len; i++){
32275 sn[i].ui.onSelectedChange(false);
32277 this.selNodes = [];
32279 if(suppressEvent !== true){
32280 this.fireEvent("selectionchange", this, this.selNodes);
32286 * Returns true if the node is selected
32287 * @param {TreeNode} node The node to check
32288 * @return {Boolean}
32290 isSelected : function(node){
32291 return this.selMap[node.id] ? true : false;
32295 * Returns an array of the selected nodes
32298 getSelectedNodes : function(){
32299 return this.selNodes;
32302 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32304 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32306 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32309 * Ext JS Library 1.1.1
32310 * Copyright(c) 2006-2007, Ext JS, LLC.
32312 * Originally Released Under LGPL - original licence link has changed is not relivant.
32315 * <script type="text/javascript">
32319 * @class Roo.tree.TreeNode
32320 * @extends Roo.data.Node
32321 * @cfg {String} text The text for this node
32322 * @cfg {Boolean} expanded true to start the node expanded
32323 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32324 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32325 * @cfg {Boolean} disabled true to start the node disabled
32326 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32327 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32328 * @cfg {String} cls A css class to be added to the node
32329 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32330 * @cfg {String} href URL of the link used for the node (defaults to #)
32331 * @cfg {String} hrefTarget target frame for the link
32332 * @cfg {String} qtip An Ext QuickTip for the node
32333 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32334 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32335 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32336 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32337 * (defaults to undefined with no checkbox rendered)
32339 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32341 Roo.tree.TreeNode = function(attributes){
32342 attributes = attributes || {};
32343 if(typeof attributes == "string"){
32344 attributes = {text: attributes};
32346 this.childrenRendered = false;
32347 this.rendered = false;
32348 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32349 this.expanded = attributes.expanded === true;
32350 this.isTarget = attributes.isTarget !== false;
32351 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32352 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32355 * Read-only. The text for this node. To change it use setText().
32358 this.text = attributes.text;
32360 * True if this node is disabled.
32363 this.disabled = attributes.disabled === true;
32367 * @event textchange
32368 * Fires when the text for this node is changed
32369 * @param {Node} this This node
32370 * @param {String} text The new text
32371 * @param {String} oldText The old text
32373 "textchange" : true,
32375 * @event beforeexpand
32376 * Fires before this node is expanded, return false to cancel.
32377 * @param {Node} this This node
32378 * @param {Boolean} deep
32379 * @param {Boolean} anim
32381 "beforeexpand" : true,
32383 * @event beforecollapse
32384 * Fires before this node is collapsed, return false to cancel.
32385 * @param {Node} this This node
32386 * @param {Boolean} deep
32387 * @param {Boolean} anim
32389 "beforecollapse" : true,
32392 * Fires when this node is expanded
32393 * @param {Node} this This node
32397 * @event disabledchange
32398 * Fires when the disabled status of this node changes
32399 * @param {Node} this This node
32400 * @param {Boolean} disabled
32402 "disabledchange" : true,
32405 * Fires when this node is collapsed
32406 * @param {Node} this This node
32410 * @event beforeclick
32411 * Fires before click processing. Return false to cancel the default action.
32412 * @param {Node} this This node
32413 * @param {Roo.EventObject} e The event object
32415 "beforeclick":true,
32417 * @event checkchange
32418 * Fires when a node with a checkbox's checked property changes
32419 * @param {Node} this This node
32420 * @param {Boolean} checked
32422 "checkchange":true,
32425 * Fires when this node is clicked
32426 * @param {Node} this This node
32427 * @param {Roo.EventObject} e The event object
32432 * Fires when this node is double clicked
32433 * @param {Node} this This node
32434 * @param {Roo.EventObject} e The event object
32438 * @event contextmenu
32439 * Fires when this node is right clicked
32440 * @param {Node} this This node
32441 * @param {Roo.EventObject} e The event object
32443 "contextmenu":true,
32445 * @event beforechildrenrendered
32446 * Fires right before the child nodes for this node are rendered
32447 * @param {Node} this This node
32449 "beforechildrenrendered":true
32452 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32455 * Read-only. The UI for this node
32458 this.ui = new uiClass(this);
32460 // finally support items[]
32461 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32466 Roo.each(this.attributes.items, function(c) {
32467 this.appendChild(Roo.factory(c,Roo.Tree));
32469 delete this.attributes.items;
32474 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32475 preventHScroll: true,
32477 * Returns true if this node is expanded
32478 * @return {Boolean}
32480 isExpanded : function(){
32481 return this.expanded;
32485 * Returns the UI object for this node
32486 * @return {TreeNodeUI}
32488 getUI : function(){
32492 // private override
32493 setFirstChild : function(node){
32494 var of = this.firstChild;
32495 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32496 if(this.childrenRendered && of && node != of){
32497 of.renderIndent(true, true);
32500 this.renderIndent(true, true);
32504 // private override
32505 setLastChild : function(node){
32506 var ol = this.lastChild;
32507 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32508 if(this.childrenRendered && ol && node != ol){
32509 ol.renderIndent(true, true);
32512 this.renderIndent(true, true);
32516 // these methods are overridden to provide lazy rendering support
32517 // private override
32518 appendChild : function()
32520 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32521 if(node && this.childrenRendered){
32524 this.ui.updateExpandIcon();
32528 // private override
32529 removeChild : function(node){
32530 this.ownerTree.getSelectionModel().unselect(node);
32531 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32532 // if it's been rendered remove dom node
32533 if(this.childrenRendered){
32536 if(this.childNodes.length < 1){
32537 this.collapse(false, false);
32539 this.ui.updateExpandIcon();
32541 if(!this.firstChild) {
32542 this.childrenRendered = false;
32547 // private override
32548 insertBefore : function(node, refNode){
32549 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32550 if(newNode && refNode && this.childrenRendered){
32553 this.ui.updateExpandIcon();
32558 * Sets the text for this node
32559 * @param {String} text
32561 setText : function(text){
32562 var oldText = this.text;
32564 this.attributes.text = text;
32565 if(this.rendered){ // event without subscribing
32566 this.ui.onTextChange(this, text, oldText);
32568 this.fireEvent("textchange", this, text, oldText);
32572 * Triggers selection of this node
32574 select : function(){
32575 this.getOwnerTree().getSelectionModel().select(this);
32579 * Triggers deselection of this node
32581 unselect : function(){
32582 this.getOwnerTree().getSelectionModel().unselect(this);
32586 * Returns true if this node is selected
32587 * @return {Boolean}
32589 isSelected : function(){
32590 return this.getOwnerTree().getSelectionModel().isSelected(this);
32594 * Expand this node.
32595 * @param {Boolean} deep (optional) True to expand all children as well
32596 * @param {Boolean} anim (optional) false to cancel the default animation
32597 * @param {Function} callback (optional) A callback to be called when
32598 * expanding this node completes (does not wait for deep expand to complete).
32599 * Called with 1 parameter, this node.
32601 expand : function(deep, anim, callback){
32602 if(!this.expanded){
32603 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32606 if(!this.childrenRendered){
32607 this.renderChildren();
32609 this.expanded = true;
32610 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32611 this.ui.animExpand(function(){
32612 this.fireEvent("expand", this);
32613 if(typeof callback == "function"){
32617 this.expandChildNodes(true);
32619 }.createDelegate(this));
32623 this.fireEvent("expand", this);
32624 if(typeof callback == "function"){
32629 if(typeof callback == "function"){
32634 this.expandChildNodes(true);
32638 isHiddenRoot : function(){
32639 return this.isRoot && !this.getOwnerTree().rootVisible;
32643 * Collapse this node.
32644 * @param {Boolean} deep (optional) True to collapse all children as well
32645 * @param {Boolean} anim (optional) false to cancel the default animation
32647 collapse : function(deep, anim){
32648 if(this.expanded && !this.isHiddenRoot()){
32649 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32652 this.expanded = false;
32653 if((this.getOwnerTree().animate && anim !== false) || anim){
32654 this.ui.animCollapse(function(){
32655 this.fireEvent("collapse", this);
32657 this.collapseChildNodes(true);
32659 }.createDelegate(this));
32662 this.ui.collapse();
32663 this.fireEvent("collapse", this);
32667 var cs = this.childNodes;
32668 for(var i = 0, len = cs.length; i < len; i++) {
32669 cs[i].collapse(true, false);
32675 delayedExpand : function(delay){
32676 if(!this.expandProcId){
32677 this.expandProcId = this.expand.defer(delay, this);
32682 cancelExpand : function(){
32683 if(this.expandProcId){
32684 clearTimeout(this.expandProcId);
32686 this.expandProcId = false;
32690 * Toggles expanded/collapsed state of the node
32692 toggle : function(){
32701 * Ensures all parent nodes are expanded
32703 ensureVisible : function(callback){
32704 var tree = this.getOwnerTree();
32705 tree.expandPath(this.parentNode.getPath(), false, function(){
32706 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32707 Roo.callback(callback);
32708 }.createDelegate(this));
32712 * Expand all child nodes
32713 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32715 expandChildNodes : function(deep){
32716 var cs = this.childNodes;
32717 for(var i = 0, len = cs.length; i < len; i++) {
32718 cs[i].expand(deep);
32723 * Collapse all child nodes
32724 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32726 collapseChildNodes : function(deep){
32727 var cs = this.childNodes;
32728 for(var i = 0, len = cs.length; i < len; i++) {
32729 cs[i].collapse(deep);
32734 * Disables this node
32736 disable : function(){
32737 this.disabled = true;
32739 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32740 this.ui.onDisableChange(this, true);
32742 this.fireEvent("disabledchange", this, true);
32746 * Enables this node
32748 enable : function(){
32749 this.disabled = false;
32750 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32751 this.ui.onDisableChange(this, false);
32753 this.fireEvent("disabledchange", this, false);
32757 renderChildren : function(suppressEvent){
32758 if(suppressEvent !== false){
32759 this.fireEvent("beforechildrenrendered", this);
32761 var cs = this.childNodes;
32762 for(var i = 0, len = cs.length; i < len; i++){
32763 cs[i].render(true);
32765 this.childrenRendered = true;
32769 sort : function(fn, scope){
32770 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32771 if(this.childrenRendered){
32772 var cs = this.childNodes;
32773 for(var i = 0, len = cs.length; i < len; i++){
32774 cs[i].render(true);
32780 render : function(bulkRender){
32781 this.ui.render(bulkRender);
32782 if(!this.rendered){
32783 this.rendered = true;
32785 this.expanded = false;
32786 this.expand(false, false);
32792 renderIndent : function(deep, refresh){
32794 this.ui.childIndent = null;
32796 this.ui.renderIndent();
32797 if(deep === true && this.childrenRendered){
32798 var cs = this.childNodes;
32799 for(var i = 0, len = cs.length; i < len; i++){
32800 cs[i].renderIndent(true, refresh);
32806 * Ext JS Library 1.1.1
32807 * Copyright(c) 2006-2007, Ext JS, LLC.
32809 * Originally Released Under LGPL - original licence link has changed is not relivant.
32812 * <script type="text/javascript">
32816 * @class Roo.tree.AsyncTreeNode
32817 * @extends Roo.tree.TreeNode
32818 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32820 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32822 Roo.tree.AsyncTreeNode = function(config){
32823 this.loaded = false;
32824 this.loading = false;
32825 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32827 * @event beforeload
32828 * Fires before this node is loaded, return false to cancel
32829 * @param {Node} this This node
32831 this.addEvents({'beforeload':true, 'load': true});
32834 * Fires when this node is loaded
32835 * @param {Node} this This node
32838 * The loader used by this node (defaults to using the tree's defined loader)
32843 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32844 expand : function(deep, anim, callback){
32845 if(this.loading){ // if an async load is already running, waiting til it's done
32847 var f = function(){
32848 if(!this.loading){ // done loading
32849 clearInterval(timer);
32850 this.expand(deep, anim, callback);
32852 }.createDelegate(this);
32853 timer = setInterval(f, 200);
32857 if(this.fireEvent("beforeload", this) === false){
32860 this.loading = true;
32861 this.ui.beforeLoad(this);
32862 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32864 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32868 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32872 * Returns true if this node is currently loading
32873 * @return {Boolean}
32875 isLoading : function(){
32876 return this.loading;
32879 loadComplete : function(deep, anim, callback){
32880 this.loading = false;
32881 this.loaded = true;
32882 this.ui.afterLoad(this);
32883 this.fireEvent("load", this);
32884 this.expand(deep, anim, callback);
32888 * Returns true if this node has been loaded
32889 * @return {Boolean}
32891 isLoaded : function(){
32892 return this.loaded;
32895 hasChildNodes : function(){
32896 if(!this.isLeaf() && !this.loaded){
32899 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32904 * Trigger a reload for this node
32905 * @param {Function} callback
32907 reload : function(callback){
32908 this.collapse(false, false);
32909 while(this.firstChild){
32910 this.removeChild(this.firstChild);
32912 this.childrenRendered = false;
32913 this.loaded = false;
32914 if(this.isHiddenRoot()){
32915 this.expanded = false;
32917 this.expand(false, false, callback);
32921 * Ext JS Library 1.1.1
32922 * Copyright(c) 2006-2007, Ext JS, LLC.
32924 * Originally Released Under LGPL - original licence link has changed is not relivant.
32927 * <script type="text/javascript">
32931 * @class Roo.tree.TreeNodeUI
32933 * @param {Object} node The node to render
32934 * The TreeNode UI implementation is separate from the
32935 * tree implementation. Unless you are customizing the tree UI,
32936 * you should never have to use this directly.
32938 Roo.tree.TreeNodeUI = function(node){
32940 this.rendered = false;
32941 this.animating = false;
32942 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32945 Roo.tree.TreeNodeUI.prototype = {
32946 removeChild : function(node){
32948 this.ctNode.removeChild(node.ui.getEl());
32952 beforeLoad : function(){
32953 this.addClass("x-tree-node-loading");
32956 afterLoad : function(){
32957 this.removeClass("x-tree-node-loading");
32960 onTextChange : function(node, text, oldText){
32962 this.textNode.innerHTML = text;
32966 onDisableChange : function(node, state){
32967 this.disabled = state;
32969 this.addClass("x-tree-node-disabled");
32971 this.removeClass("x-tree-node-disabled");
32975 onSelectedChange : function(state){
32978 this.addClass("x-tree-selected");
32981 this.removeClass("x-tree-selected");
32985 onMove : function(tree, node, oldParent, newParent, index, refNode){
32986 this.childIndent = null;
32988 var targetNode = newParent.ui.getContainer();
32989 if(!targetNode){//target not rendered
32990 this.holder = document.createElement("div");
32991 this.holder.appendChild(this.wrap);
32994 var insertBefore = refNode ? refNode.ui.getEl() : null;
32996 targetNode.insertBefore(this.wrap, insertBefore);
32998 targetNode.appendChild(this.wrap);
33000 this.node.renderIndent(true);
33004 addClass : function(cls){
33006 Roo.fly(this.elNode).addClass(cls);
33010 removeClass : function(cls){
33012 Roo.fly(this.elNode).removeClass(cls);
33016 remove : function(){
33018 this.holder = document.createElement("div");
33019 this.holder.appendChild(this.wrap);
33023 fireEvent : function(){
33024 return this.node.fireEvent.apply(this.node, arguments);
33027 initEvents : function(){
33028 this.node.on("move", this.onMove, this);
33029 var E = Roo.EventManager;
33030 var a = this.anchor;
33032 var el = Roo.fly(a, '_treeui');
33034 if(Roo.isOpera){ // opera render bug ignores the CSS
33035 el.setStyle("text-decoration", "none");
33038 el.on("click", this.onClick, this);
33039 el.on("dblclick", this.onDblClick, this);
33042 Roo.EventManager.on(this.checkbox,
33043 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33046 el.on("contextmenu", this.onContextMenu, this);
33048 var icon = Roo.fly(this.iconNode);
33049 icon.on("click", this.onClick, this);
33050 icon.on("dblclick", this.onDblClick, this);
33051 icon.on("contextmenu", this.onContextMenu, this);
33052 E.on(this.ecNode, "click", this.ecClick, this, true);
33054 if(this.node.disabled){
33055 this.addClass("x-tree-node-disabled");
33057 if(this.node.hidden){
33058 this.addClass("x-tree-node-disabled");
33060 var ot = this.node.getOwnerTree();
33061 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33062 if(dd && (!this.node.isRoot || ot.rootVisible)){
33063 Roo.dd.Registry.register(this.elNode, {
33065 handles: this.getDDHandles(),
33071 getDDHandles : function(){
33072 return [this.iconNode, this.textNode];
33077 this.wrap.style.display = "none";
33083 this.wrap.style.display = "";
33087 onContextMenu : function(e){
33088 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33089 e.preventDefault();
33091 this.fireEvent("contextmenu", this.node, e);
33095 onClick : function(e){
33100 if(this.fireEvent("beforeclick", this.node, e) !== false){
33101 if(!this.disabled && this.node.attributes.href){
33102 this.fireEvent("click", this.node, e);
33105 e.preventDefault();
33110 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33111 this.node.toggle();
33114 this.fireEvent("click", this.node, e);
33120 onDblClick : function(e){
33121 e.preventDefault();
33126 this.toggleCheck();
33128 if(!this.animating && this.node.hasChildNodes()){
33129 this.node.toggle();
33131 this.fireEvent("dblclick", this.node, e);
33134 onCheckChange : function(){
33135 var checked = this.checkbox.checked;
33136 this.node.attributes.checked = checked;
33137 this.fireEvent('checkchange', this.node, checked);
33140 ecClick : function(e){
33141 if(!this.animating && this.node.hasChildNodes()){
33142 this.node.toggle();
33146 startDrop : function(){
33147 this.dropping = true;
33150 // delayed drop so the click event doesn't get fired on a drop
33151 endDrop : function(){
33152 setTimeout(function(){
33153 this.dropping = false;
33154 }.createDelegate(this), 50);
33157 expand : function(){
33158 this.updateExpandIcon();
33159 this.ctNode.style.display = "";
33162 focus : function(){
33163 if(!this.node.preventHScroll){
33164 try{this.anchor.focus();
33166 }else if(!Roo.isIE){
33168 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33169 var l = noscroll.scrollLeft;
33170 this.anchor.focus();
33171 noscroll.scrollLeft = l;
33176 toggleCheck : function(value){
33177 var cb = this.checkbox;
33179 cb.checked = (value === undefined ? !cb.checked : value);
33185 this.anchor.blur();
33189 animExpand : function(callback){
33190 var ct = Roo.get(this.ctNode);
33192 if(!this.node.hasChildNodes()){
33193 this.updateExpandIcon();
33194 this.ctNode.style.display = "";
33195 Roo.callback(callback);
33198 this.animating = true;
33199 this.updateExpandIcon();
33202 callback : function(){
33203 this.animating = false;
33204 Roo.callback(callback);
33207 duration: this.node.ownerTree.duration || .25
33211 highlight : function(){
33212 var tree = this.node.getOwnerTree();
33213 Roo.fly(this.wrap).highlight(
33214 tree.hlColor || "C3DAF9",
33215 {endColor: tree.hlBaseColor}
33219 collapse : function(){
33220 this.updateExpandIcon();
33221 this.ctNode.style.display = "none";
33224 animCollapse : function(callback){
33225 var ct = Roo.get(this.ctNode);
33226 ct.enableDisplayMode('block');
33229 this.animating = true;
33230 this.updateExpandIcon();
33233 callback : function(){
33234 this.animating = false;
33235 Roo.callback(callback);
33238 duration: this.node.ownerTree.duration || .25
33242 getContainer : function(){
33243 return this.ctNode;
33246 getEl : function(){
33250 appendDDGhost : function(ghostNode){
33251 ghostNode.appendChild(this.elNode.cloneNode(true));
33254 getDDRepairXY : function(){
33255 return Roo.lib.Dom.getXY(this.iconNode);
33258 onRender : function(){
33262 render : function(bulkRender){
33263 var n = this.node, a = n.attributes;
33264 var targetNode = n.parentNode ?
33265 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33267 if(!this.rendered){
33268 this.rendered = true;
33270 this.renderElements(n, a, targetNode, bulkRender);
33273 if(this.textNode.setAttributeNS){
33274 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33276 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33279 this.textNode.setAttribute("ext:qtip", a.qtip);
33281 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33284 }else if(a.qtipCfg){
33285 a.qtipCfg.target = Roo.id(this.textNode);
33286 Roo.QuickTips.register(a.qtipCfg);
33289 if(!this.node.expanded){
33290 this.updateExpandIcon();
33293 if(bulkRender === true) {
33294 targetNode.appendChild(this.wrap);
33299 renderElements : function(n, a, targetNode, bulkRender)
33301 // add some indent caching, this helps performance when rendering a large tree
33302 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33303 var t = n.getOwnerTree();
33304 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33305 if (typeof(n.attributes.html) != 'undefined') {
33306 txt = n.attributes.html;
33308 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33309 var cb = typeof a.checked == 'boolean';
33310 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33311 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33312 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33313 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33314 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33315 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33316 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33317 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33318 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33319 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33322 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33323 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33324 n.nextSibling.ui.getEl(), buf.join(""));
33326 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33329 this.elNode = this.wrap.childNodes[0];
33330 this.ctNode = this.wrap.childNodes[1];
33331 var cs = this.elNode.childNodes;
33332 this.indentNode = cs[0];
33333 this.ecNode = cs[1];
33334 this.iconNode = cs[2];
33337 this.checkbox = cs[3];
33340 this.anchor = cs[index];
33341 this.textNode = cs[index].firstChild;
33344 getAnchor : function(){
33345 return this.anchor;
33348 getTextEl : function(){
33349 return this.textNode;
33352 getIconEl : function(){
33353 return this.iconNode;
33356 isChecked : function(){
33357 return this.checkbox ? this.checkbox.checked : false;
33360 updateExpandIcon : function(){
33362 var n = this.node, c1, c2;
33363 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33364 var hasChild = n.hasChildNodes();
33368 c1 = "x-tree-node-collapsed";
33369 c2 = "x-tree-node-expanded";
33372 c1 = "x-tree-node-expanded";
33373 c2 = "x-tree-node-collapsed";
33376 this.removeClass("x-tree-node-leaf");
33377 this.wasLeaf = false;
33379 if(this.c1 != c1 || this.c2 != c2){
33380 Roo.fly(this.elNode).replaceClass(c1, c2);
33381 this.c1 = c1; this.c2 = c2;
33384 // this changes non-leafs into leafs if they have no children.
33385 // it's not very rational behaviour..
33387 if(!this.wasLeaf && this.node.leaf){
33388 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33391 this.wasLeaf = true;
33394 var ecc = "x-tree-ec-icon "+cls;
33395 if(this.ecc != ecc){
33396 this.ecNode.className = ecc;
33402 getChildIndent : function(){
33403 if(!this.childIndent){
33407 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33409 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33411 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33416 this.childIndent = buf.join("");
33418 return this.childIndent;
33421 renderIndent : function(){
33424 var p = this.node.parentNode;
33426 indent = p.ui.getChildIndent();
33428 if(this.indentMarkup != indent){ // don't rerender if not required
33429 this.indentNode.innerHTML = indent;
33430 this.indentMarkup = indent;
33432 this.updateExpandIcon();
33437 Roo.tree.RootTreeNodeUI = function(){
33438 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33440 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33441 render : function(){
33442 if(!this.rendered){
33443 var targetNode = this.node.ownerTree.innerCt.dom;
33444 this.node.expanded = true;
33445 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33446 this.wrap = this.ctNode = targetNode.firstChild;
33449 collapse : function(){
33451 expand : function(){
33455 * Ext JS Library 1.1.1
33456 * Copyright(c) 2006-2007, Ext JS, LLC.
33458 * Originally Released Under LGPL - original licence link has changed is not relivant.
33461 * <script type="text/javascript">
33464 * @class Roo.tree.TreeLoader
33465 * @extends Roo.util.Observable
33466 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33467 * nodes from a specified URL. The response must be a javascript Array definition
33468 * who's elements are node definition objects. eg:
33473 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33474 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33481 * The old style respose with just an array is still supported, but not recommended.
33484 * A server request is sent, and child nodes are loaded only when a node is expanded.
33485 * The loading node's id is passed to the server under the parameter name "node" to
33486 * enable the server to produce the correct child nodes.
33488 * To pass extra parameters, an event handler may be attached to the "beforeload"
33489 * event, and the parameters specified in the TreeLoader's baseParams property:
33491 myTreeLoader.on("beforeload", function(treeLoader, node) {
33492 this.baseParams.category = node.attributes.category;
33495 * This would pass an HTTP parameter called "category" to the server containing
33496 * the value of the Node's "category" attribute.
33498 * Creates a new Treeloader.
33499 * @param {Object} config A config object containing config properties.
33501 Roo.tree.TreeLoader = function(config){
33502 this.baseParams = {};
33503 this.requestMethod = "POST";
33504 Roo.apply(this, config);
33509 * @event beforeload
33510 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33511 * @param {Object} This TreeLoader object.
33512 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33513 * @param {Object} callback The callback function specified in the {@link #load} call.
33518 * Fires when the node has been successfuly loaded.
33519 * @param {Object} This TreeLoader object.
33520 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33521 * @param {Object} response The response object containing the data from the server.
33525 * @event loadexception
33526 * Fires if the network request failed.
33527 * @param {Object} This TreeLoader object.
33528 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33529 * @param {Object} response The response object containing the data from the server.
33531 loadexception : true,
33534 * Fires before a node is created, enabling you to return custom Node types
33535 * @param {Object} This TreeLoader object.
33536 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33541 Roo.tree.TreeLoader.superclass.constructor.call(this);
33544 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33546 * @cfg {String} dataUrl The URL from which to request a Json string which
33547 * specifies an array of node definition object representing the child nodes
33551 * @cfg {String} requestMethod either GET or POST
33552 * defaults to POST (due to BC)
33556 * @cfg {Object} baseParams (optional) An object containing properties which
33557 * specify HTTP parameters to be passed to each request for child nodes.
33560 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33561 * created by this loader. If the attributes sent by the server have an attribute in this object,
33562 * they take priority.
33565 * @cfg {Object} uiProviders (optional) An object containing properties which
33567 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33568 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33569 * <i>uiProvider</i> attribute of a returned child node is a string rather
33570 * than a reference to a TreeNodeUI implementation, this that string value
33571 * is used as a property name in the uiProviders object. You can define the provider named
33572 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33577 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33578 * child nodes before loading.
33580 clearOnLoad : true,
33583 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33584 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33585 * Grid query { data : [ .....] }
33590 * @cfg {String} queryParam (optional)
33591 * Name of the query as it will be passed on the querystring (defaults to 'node')
33592 * eg. the request will be ?node=[id]
33599 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33600 * This is called automatically when a node is expanded, but may be used to reload
33601 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33602 * @param {Roo.tree.TreeNode} node
33603 * @param {Function} callback
33605 load : function(node, callback){
33606 if(this.clearOnLoad){
33607 while(node.firstChild){
33608 node.removeChild(node.firstChild);
33611 if(node.attributes.children){ // preloaded json children
33612 var cs = node.attributes.children;
33613 for(var i = 0, len = cs.length; i < len; i++){
33614 node.appendChild(this.createNode(cs[i]));
33616 if(typeof callback == "function"){
33619 }else if(this.dataUrl){
33620 this.requestData(node, callback);
33624 getParams: function(node){
33625 var buf = [], bp = this.baseParams;
33626 for(var key in bp){
33627 if(typeof bp[key] != "function"){
33628 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33631 var n = this.queryParam === false ? 'node' : this.queryParam;
33632 buf.push(n + "=", encodeURIComponent(node.id));
33633 return buf.join("");
33636 requestData : function(node, callback){
33637 if(this.fireEvent("beforeload", this, node, callback) !== false){
33638 this.transId = Roo.Ajax.request({
33639 method:this.requestMethod,
33640 url: this.dataUrl||this.url,
33641 success: this.handleResponse,
33642 failure: this.handleFailure,
33644 argument: {callback: callback, node: node},
33645 params: this.getParams(node)
33648 // if the load is cancelled, make sure we notify
33649 // the node that we are done
33650 if(typeof callback == "function"){
33656 isLoading : function(){
33657 return this.transId ? true : false;
33660 abort : function(){
33661 if(this.isLoading()){
33662 Roo.Ajax.abort(this.transId);
33667 createNode : function(attr)
33669 // apply baseAttrs, nice idea Corey!
33670 if(this.baseAttrs){
33671 Roo.applyIf(attr, this.baseAttrs);
33673 if(this.applyLoader !== false){
33674 attr.loader = this;
33676 // uiProvider = depreciated..
33678 if(typeof(attr.uiProvider) == 'string'){
33679 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33680 /** eval:var:attr */ eval(attr.uiProvider);
33682 if(typeof(this.uiProviders['default']) != 'undefined') {
33683 attr.uiProvider = this.uiProviders['default'];
33686 this.fireEvent('create', this, attr);
33688 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33690 new Roo.tree.TreeNode(attr) :
33691 new Roo.tree.AsyncTreeNode(attr));
33694 processResponse : function(response, node, callback)
33696 var json = response.responseText;
33699 var o = Roo.decode(json);
33701 if (this.root === false && typeof(o.success) != undefined) {
33702 this.root = 'data'; // the default behaviour for list like data..
33705 if (this.root !== false && !o.success) {
33706 // it's a failure condition.
33707 var a = response.argument;
33708 this.fireEvent("loadexception", this, a.node, response);
33709 Roo.log("Load failed - should have a handler really");
33715 if (this.root !== false) {
33719 for(var i = 0, len = o.length; i < len; i++){
33720 var n = this.createNode(o[i]);
33722 node.appendChild(n);
33725 if(typeof callback == "function"){
33726 callback(this, node);
33729 this.handleFailure(response);
33733 handleResponse : function(response){
33734 this.transId = false;
33735 var a = response.argument;
33736 this.processResponse(response, a.node, a.callback);
33737 this.fireEvent("load", this, a.node, response);
33740 handleFailure : function(response)
33742 // should handle failure better..
33743 this.transId = false;
33744 var a = response.argument;
33745 this.fireEvent("loadexception", this, a.node, response);
33746 if(typeof a.callback == "function"){
33747 a.callback(this, a.node);
33752 * Ext JS Library 1.1.1
33753 * Copyright(c) 2006-2007, Ext JS, LLC.
33755 * Originally Released Under LGPL - original licence link has changed is not relivant.
33758 * <script type="text/javascript">
33762 * @class Roo.tree.TreeFilter
33763 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33764 * @param {TreePanel} tree
33765 * @param {Object} config (optional)
33767 Roo.tree.TreeFilter = function(tree, config){
33769 this.filtered = {};
33770 Roo.apply(this, config);
33773 Roo.tree.TreeFilter.prototype = {
33780 * Filter the data by a specific attribute.
33781 * @param {String/RegExp} value Either string that the attribute value
33782 * should start with or a RegExp to test against the attribute
33783 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33784 * @param {TreeNode} startNode (optional) The node to start the filter at.
33786 filter : function(value, attr, startNode){
33787 attr = attr || "text";
33789 if(typeof value == "string"){
33790 var vlen = value.length;
33791 // auto clear empty filter
33792 if(vlen == 0 && this.clearBlank){
33796 value = value.toLowerCase();
33798 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33800 }else if(value.exec){ // regex?
33802 return value.test(n.attributes[attr]);
33805 throw 'Illegal filter type, must be string or regex';
33807 this.filterBy(f, null, startNode);
33811 * Filter by a function. The passed function will be called with each
33812 * node in the tree (or from the startNode). If the function returns true, the node is kept
33813 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33814 * @param {Function} fn The filter function
33815 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33817 filterBy : function(fn, scope, startNode){
33818 startNode = startNode || this.tree.root;
33819 if(this.autoClear){
33822 var af = this.filtered, rv = this.reverse;
33823 var f = function(n){
33824 if(n == startNode){
33830 var m = fn.call(scope || n, n);
33838 startNode.cascade(f);
33841 if(typeof id != "function"){
33843 if(n && n.parentNode){
33844 n.parentNode.removeChild(n);
33852 * Clears the current filter. Note: with the "remove" option
33853 * set a filter cannot be cleared.
33855 clear : function(){
33857 var af = this.filtered;
33859 if(typeof id != "function"){
33866 this.filtered = {};
33871 * Ext JS Library 1.1.1
33872 * Copyright(c) 2006-2007, Ext JS, LLC.
33874 * Originally Released Under LGPL - original licence link has changed is not relivant.
33877 * <script type="text/javascript">
33882 * @class Roo.tree.TreeSorter
33883 * Provides sorting of nodes in a TreePanel
33885 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33886 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33887 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33888 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33889 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33890 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33892 * @param {TreePanel} tree
33893 * @param {Object} config
33895 Roo.tree.TreeSorter = function(tree, config){
33896 Roo.apply(this, config);
33897 tree.on("beforechildrenrendered", this.doSort, this);
33898 tree.on("append", this.updateSort, this);
33899 tree.on("insert", this.updateSort, this);
33901 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33902 var p = this.property || "text";
33903 var sortType = this.sortType;
33904 var fs = this.folderSort;
33905 var cs = this.caseSensitive === true;
33906 var leafAttr = this.leafAttr || 'leaf';
33908 this.sortFn = function(n1, n2){
33910 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33913 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33917 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33918 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33920 return dsc ? +1 : -1;
33922 return dsc ? -1 : +1;
33929 Roo.tree.TreeSorter.prototype = {
33930 doSort : function(node){
33931 node.sort(this.sortFn);
33934 compareNodes : function(n1, n2){
33935 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33938 updateSort : function(tree, node){
33939 if(node.childrenRendered){
33940 this.doSort.defer(1, this, [node]);
33945 * Ext JS Library 1.1.1
33946 * Copyright(c) 2006-2007, Ext JS, LLC.
33948 * Originally Released Under LGPL - original licence link has changed is not relivant.
33951 * <script type="text/javascript">
33954 if(Roo.dd.DropZone){
33956 Roo.tree.TreeDropZone = function(tree, config){
33957 this.allowParentInsert = false;
33958 this.allowContainerDrop = false;
33959 this.appendOnly = false;
33960 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33962 this.lastInsertClass = "x-tree-no-status";
33963 this.dragOverData = {};
33966 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33967 ddGroup : "TreeDD",
33970 expandDelay : 1000,
33972 expandNode : function(node){
33973 if(node.hasChildNodes() && !node.isExpanded()){
33974 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33978 queueExpand : function(node){
33979 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33982 cancelExpand : function(){
33983 if(this.expandProcId){
33984 clearTimeout(this.expandProcId);
33985 this.expandProcId = false;
33989 isValidDropPoint : function(n, pt, dd, e, data){
33990 if(!n || !data){ return false; }
33991 var targetNode = n.node;
33992 var dropNode = data.node;
33993 // default drop rules
33994 if(!(targetNode && targetNode.isTarget && pt)){
33997 if(pt == "append" && targetNode.allowChildren === false){
34000 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34003 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34006 // reuse the object
34007 var overEvent = this.dragOverData;
34008 overEvent.tree = this.tree;
34009 overEvent.target = targetNode;
34010 overEvent.data = data;
34011 overEvent.point = pt;
34012 overEvent.source = dd;
34013 overEvent.rawEvent = e;
34014 overEvent.dropNode = dropNode;
34015 overEvent.cancel = false;
34016 var result = this.tree.fireEvent("nodedragover", overEvent);
34017 return overEvent.cancel === false && result !== false;
34020 getDropPoint : function(e, n, dd)
34024 return tn.allowChildren !== false ? "append" : false; // always append for root
34026 var dragEl = n.ddel;
34027 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34028 var y = Roo.lib.Event.getPageY(e);
34029 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34031 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34032 var noAppend = tn.allowChildren === false;
34033 if(this.appendOnly || tn.parentNode.allowChildren === false){
34034 return noAppend ? false : "append";
34036 var noBelow = false;
34037 if(!this.allowParentInsert){
34038 noBelow = tn.hasChildNodes() && tn.isExpanded();
34040 var q = (b - t) / (noAppend ? 2 : 3);
34041 if(y >= t && y < (t + q)){
34043 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34050 onNodeEnter : function(n, dd, e, data)
34052 this.cancelExpand();
34055 onNodeOver : function(n, dd, e, data)
34058 var pt = this.getDropPoint(e, n, dd);
34061 // auto node expand check
34062 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34063 this.queueExpand(node);
34064 }else if(pt != "append"){
34065 this.cancelExpand();
34068 // set the insert point style on the target node
34069 var returnCls = this.dropNotAllowed;
34070 if(this.isValidDropPoint(n, pt, dd, e, data)){
34075 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34076 cls = "x-tree-drag-insert-above";
34077 }else if(pt == "below"){
34078 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34079 cls = "x-tree-drag-insert-below";
34081 returnCls = "x-tree-drop-ok-append";
34082 cls = "x-tree-drag-append";
34084 if(this.lastInsertClass != cls){
34085 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34086 this.lastInsertClass = cls;
34093 onNodeOut : function(n, dd, e, data){
34095 this.cancelExpand();
34096 this.removeDropIndicators(n);
34099 onNodeDrop : function(n, dd, e, data){
34100 var point = this.getDropPoint(e, n, dd);
34101 var targetNode = n.node;
34102 targetNode.ui.startDrop();
34103 if(!this.isValidDropPoint(n, point, dd, e, data)){
34104 targetNode.ui.endDrop();
34107 // first try to find the drop node
34108 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34111 target: targetNode,
34116 dropNode: dropNode,
34119 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34120 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34121 targetNode.ui.endDrop();
34124 // allow target changing
34125 targetNode = dropEvent.target;
34126 if(point == "append" && !targetNode.isExpanded()){
34127 targetNode.expand(false, null, function(){
34128 this.completeDrop(dropEvent);
34129 }.createDelegate(this));
34131 this.completeDrop(dropEvent);
34136 completeDrop : function(de){
34137 var ns = de.dropNode, p = de.point, t = de.target;
34138 if(!(ns instanceof Array)){
34142 for(var i = 0, len = ns.length; i < len; i++){
34145 t.parentNode.insertBefore(n, t);
34146 }else if(p == "below"){
34147 t.parentNode.insertBefore(n, t.nextSibling);
34153 if(this.tree.hlDrop){
34157 this.tree.fireEvent("nodedrop", de);
34160 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34161 if(this.tree.hlDrop){
34162 dropNode.ui.focus();
34163 dropNode.ui.highlight();
34165 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34168 getTree : function(){
34172 removeDropIndicators : function(n){
34175 Roo.fly(el).removeClass([
34176 "x-tree-drag-insert-above",
34177 "x-tree-drag-insert-below",
34178 "x-tree-drag-append"]);
34179 this.lastInsertClass = "_noclass";
34183 beforeDragDrop : function(target, e, id){
34184 this.cancelExpand();
34188 afterRepair : function(data){
34189 if(data && Roo.enableFx){
34190 data.node.ui.highlight();
34200 * Ext JS Library 1.1.1
34201 * Copyright(c) 2006-2007, Ext JS, LLC.
34203 * Originally Released Under LGPL - original licence link has changed is not relivant.
34206 * <script type="text/javascript">
34210 if(Roo.dd.DragZone){
34211 Roo.tree.TreeDragZone = function(tree, config){
34212 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34216 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34217 ddGroup : "TreeDD",
34219 onBeforeDrag : function(data, e){
34221 return n && n.draggable && !n.disabled;
34225 onInitDrag : function(e){
34226 var data = this.dragData;
34227 this.tree.getSelectionModel().select(data.node);
34228 this.proxy.update("");
34229 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34230 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34233 getRepairXY : function(e, data){
34234 return data.node.ui.getDDRepairXY();
34237 onEndDrag : function(data, e){
34238 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34243 onValidDrop : function(dd, e, id){
34244 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34248 beforeInvalidDrop : function(e, id){
34249 // this scrolls the original position back into view
34250 var sm = this.tree.getSelectionModel();
34251 sm.clearSelections();
34252 sm.select(this.dragData.node);
34257 * Ext JS Library 1.1.1
34258 * Copyright(c) 2006-2007, Ext JS, LLC.
34260 * Originally Released Under LGPL - original licence link has changed is not relivant.
34263 * <script type="text/javascript">
34266 * @class Roo.tree.TreeEditor
34267 * @extends Roo.Editor
34268 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34269 * as the editor field.
34271 * @param {Object} config (used to be the tree panel.)
34272 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34274 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34275 * @cfg {Roo.form.TextField|Object} field The field configuration
34279 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34282 if (oldconfig) { // old style..
34283 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34286 tree = config.tree;
34287 config.field = config.field || {};
34288 config.field.xtype = 'TextField';
34289 field = Roo.factory(config.field, Roo.form);
34291 config = config || {};
34296 * @event beforenodeedit
34297 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34298 * false from the handler of this event.
34299 * @param {Editor} this
34300 * @param {Roo.tree.Node} node
34302 "beforenodeedit" : true
34306 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34310 tree.on('beforeclick', this.beforeNodeClick, this);
34311 tree.getTreeEl().on('mousedown', this.hide, this);
34312 this.on('complete', this.updateNode, this);
34313 this.on('beforestartedit', this.fitToTree, this);
34314 this.on('startedit', this.bindScroll, this, {delay:10});
34315 this.on('specialkey', this.onSpecialKey, this);
34318 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34320 * @cfg {String} alignment
34321 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34327 * @cfg {Boolean} hideEl
34328 * True to hide the bound element while the editor is displayed (defaults to false)
34332 * @cfg {String} cls
34333 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34335 cls: "x-small-editor x-tree-editor",
34337 * @cfg {Boolean} shim
34338 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34344 * @cfg {Number} maxWidth
34345 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34346 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34347 * scroll and client offsets into account prior to each edit.
34354 fitToTree : function(ed, el){
34355 var td = this.tree.getTreeEl().dom, nd = el.dom;
34356 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34357 td.scrollLeft = nd.offsetLeft;
34361 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34362 this.setSize(w, '');
34364 return this.fireEvent('beforenodeedit', this, this.editNode);
34369 triggerEdit : function(node){
34370 this.completeEdit();
34371 this.editNode = node;
34372 this.startEdit(node.ui.textNode, node.text);
34376 bindScroll : function(){
34377 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34381 beforeNodeClick : function(node, e){
34382 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34383 this.lastClick = new Date();
34384 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34386 this.triggerEdit(node);
34393 updateNode : function(ed, value){
34394 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34395 this.editNode.setText(value);
34399 onHide : function(){
34400 Roo.tree.TreeEditor.superclass.onHide.call(this);
34402 this.editNode.ui.focus();
34407 onSpecialKey : function(field, e){
34408 var k = e.getKey();
34412 }else if(k == e.ENTER && !e.hasModifier()){
34414 this.completeEdit();
34417 });//<Script type="text/javascript">
34420 * Ext JS Library 1.1.1
34421 * Copyright(c) 2006-2007, Ext JS, LLC.
34423 * Originally Released Under LGPL - original licence link has changed is not relivant.
34426 * <script type="text/javascript">
34430 * Not documented??? - probably should be...
34433 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34434 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34436 renderElements : function(n, a, targetNode, bulkRender){
34437 //consel.log("renderElements?");
34438 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34440 var t = n.getOwnerTree();
34441 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34443 var cols = t.columns;
34444 var bw = t.borderWidth;
34446 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34447 var cb = typeof a.checked == "boolean";
34448 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34449 var colcls = 'x-t-' + tid + '-c0';
34451 '<li class="x-tree-node">',
34454 '<div class="x-tree-node-el ', a.cls,'">',
34456 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34459 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34460 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34461 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34462 (a.icon ? ' x-tree-node-inline-icon' : ''),
34463 (a.iconCls ? ' '+a.iconCls : ''),
34464 '" unselectable="on" />',
34465 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34466 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34468 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34469 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34470 '<span unselectable="on" qtip="' + tx + '">',
34474 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34475 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34477 for(var i = 1, len = cols.length; i < len; i++){
34479 colcls = 'x-t-' + tid + '-c' +i;
34480 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34481 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34482 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34488 '<div class="x-clear"></div></div>',
34489 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34492 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34493 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34494 n.nextSibling.ui.getEl(), buf.join(""));
34496 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34498 var el = this.wrap.firstChild;
34500 this.elNode = el.firstChild;
34501 this.ranchor = el.childNodes[1];
34502 this.ctNode = this.wrap.childNodes[1];
34503 var cs = el.firstChild.childNodes;
34504 this.indentNode = cs[0];
34505 this.ecNode = cs[1];
34506 this.iconNode = cs[2];
34509 this.checkbox = cs[3];
34512 this.anchor = cs[index];
34514 this.textNode = cs[index].firstChild;
34516 //el.on("click", this.onClick, this);
34517 //el.on("dblclick", this.onDblClick, this);
34520 // console.log(this);
34522 initEvents : function(){
34523 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34526 var a = this.ranchor;
34528 var el = Roo.get(a);
34530 if(Roo.isOpera){ // opera render bug ignores the CSS
34531 el.setStyle("text-decoration", "none");
34534 el.on("click", this.onClick, this);
34535 el.on("dblclick", this.onDblClick, this);
34536 el.on("contextmenu", this.onContextMenu, this);
34540 /*onSelectedChange : function(state){
34543 this.addClass("x-tree-selected");
34546 this.removeClass("x-tree-selected");
34549 addClass : function(cls){
34551 Roo.fly(this.elRow).addClass(cls);
34557 removeClass : function(cls){
34559 Roo.fly(this.elRow).removeClass(cls);
34565 });//<Script type="text/javascript">
34569 * Ext JS Library 1.1.1
34570 * Copyright(c) 2006-2007, Ext JS, LLC.
34572 * Originally Released Under LGPL - original licence link has changed is not relivant.
34575 * <script type="text/javascript">
34580 * @class Roo.tree.ColumnTree
34581 * @extends Roo.data.TreePanel
34582 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34583 * @cfg {int} borderWidth compined right/left border allowance
34585 * @param {String/HTMLElement/Element} el The container element
34586 * @param {Object} config
34588 Roo.tree.ColumnTree = function(el, config)
34590 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34594 * Fire this event on a container when it resizes
34595 * @param {int} w Width
34596 * @param {int} h Height
34600 this.on('resize', this.onResize, this);
34603 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34607 borderWidth: Roo.isBorderBox ? 0 : 2,
34610 render : function(){
34611 // add the header.....
34613 Roo.tree.ColumnTree.superclass.render.apply(this);
34615 this.el.addClass('x-column-tree');
34617 this.headers = this.el.createChild(
34618 {cls:'x-tree-headers'},this.innerCt.dom);
34620 var cols = this.columns, c;
34621 var totalWidth = 0;
34623 var len = cols.length;
34624 for(var i = 0; i < len; i++){
34626 totalWidth += c.width;
34627 this.headEls.push(this.headers.createChild({
34628 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34630 cls:'x-tree-hd-text',
34633 style:'width:'+(c.width-this.borderWidth)+'px;'
34636 this.headers.createChild({cls:'x-clear'});
34637 // prevent floats from wrapping when clipped
34638 this.headers.setWidth(totalWidth);
34639 //this.innerCt.setWidth(totalWidth);
34640 this.innerCt.setStyle({ overflow: 'auto' });
34641 this.onResize(this.width, this.height);
34645 onResize : function(w,h)
34650 this.innerCt.setWidth(this.width);
34651 this.innerCt.setHeight(this.height-20);
34654 var cols = this.columns, c;
34655 var totalWidth = 0;
34657 var len = cols.length;
34658 for(var i = 0; i < len; i++){
34660 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34661 // it's the expander..
34662 expEl = this.headEls[i];
34665 totalWidth += c.width;
34669 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34671 this.headers.setWidth(w-20);
34680 * Ext JS Library 1.1.1
34681 * Copyright(c) 2006-2007, Ext JS, LLC.
34683 * Originally Released Under LGPL - original licence link has changed is not relivant.
34686 * <script type="text/javascript">
34690 * @class Roo.menu.Menu
34691 * @extends Roo.util.Observable
34692 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34693 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34695 * Creates a new Menu
34696 * @param {Object} config Configuration options
34698 Roo.menu.Menu = function(config){
34699 Roo.apply(this, config);
34700 this.id = this.id || Roo.id();
34703 * @event beforeshow
34704 * Fires before this menu is displayed
34705 * @param {Roo.menu.Menu} this
34709 * @event beforehide
34710 * Fires before this menu is hidden
34711 * @param {Roo.menu.Menu} this
34716 * Fires after this menu is displayed
34717 * @param {Roo.menu.Menu} this
34722 * Fires after this menu is hidden
34723 * @param {Roo.menu.Menu} this
34728 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34729 * @param {Roo.menu.Menu} this
34730 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34731 * @param {Roo.EventObject} e
34736 * Fires when the mouse is hovering over this menu
34737 * @param {Roo.menu.Menu} this
34738 * @param {Roo.EventObject} e
34739 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34744 * Fires when the mouse exits this menu
34745 * @param {Roo.menu.Menu} this
34746 * @param {Roo.EventObject} e
34747 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34752 * Fires when a menu item contained in this menu is clicked
34753 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34754 * @param {Roo.EventObject} e
34758 if (this.registerMenu) {
34759 Roo.menu.MenuMgr.register(this);
34762 var mis = this.items;
34763 this.items = new Roo.util.MixedCollection();
34765 this.add.apply(this, mis);
34769 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34771 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34775 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34776 * for bottom-right shadow (defaults to "sides")
34780 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34781 * this menu (defaults to "tl-tr?")
34783 subMenuAlign : "tl-tr?",
34785 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34786 * relative to its element of origin (defaults to "tl-bl?")
34788 defaultAlign : "tl-bl?",
34790 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34792 allowOtherMenus : false,
34794 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34796 registerMenu : true,
34801 render : function(){
34805 var el = this.el = new Roo.Layer({
34807 shadow:this.shadow,
34809 parentEl: this.parentEl || document.body,
34813 this.keyNav = new Roo.menu.MenuNav(this);
34816 el.addClass("x-menu-plain");
34819 el.addClass(this.cls);
34821 // generic focus element
34822 this.focusEl = el.createChild({
34823 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34825 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34826 ul.on("click", this.onClick, this);
34827 ul.on("mouseover", this.onMouseOver, this);
34828 ul.on("mouseout", this.onMouseOut, this);
34829 this.items.each(function(item){
34830 var li = document.createElement("li");
34831 li.className = "x-menu-list-item";
34832 ul.dom.appendChild(li);
34833 item.render(li, this);
34840 autoWidth : function(){
34841 var el = this.el, ul = this.ul;
34845 var w = this.width;
34848 }else if(Roo.isIE){
34849 el.setWidth(this.minWidth);
34850 var t = el.dom.offsetWidth; // force recalc
34851 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34856 delayAutoWidth : function(){
34859 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34861 this.awTask.delay(20);
34866 findTargetItem : function(e){
34867 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34868 if(t && t.menuItemId){
34869 return this.items.get(t.menuItemId);
34874 onClick : function(e){
34876 if(t = this.findTargetItem(e)){
34878 this.fireEvent("click", this, t, e);
34883 setActiveItem : function(item, autoExpand){
34884 if(item != this.activeItem){
34885 if(this.activeItem){
34886 this.activeItem.deactivate();
34888 this.activeItem = item;
34889 item.activate(autoExpand);
34890 }else if(autoExpand){
34896 tryActivate : function(start, step){
34897 var items = this.items;
34898 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34899 var item = items.get(i);
34900 if(!item.disabled && item.canActivate){
34901 this.setActiveItem(item, false);
34909 onMouseOver : function(e){
34911 if(t = this.findTargetItem(e)){
34912 if(t.canActivate && !t.disabled){
34913 this.setActiveItem(t, true);
34916 this.fireEvent("mouseover", this, e, t);
34920 onMouseOut : function(e){
34922 if(t = this.findTargetItem(e)){
34923 if(t == this.activeItem && t.shouldDeactivate(e)){
34924 this.activeItem.deactivate();
34925 delete this.activeItem;
34928 this.fireEvent("mouseout", this, e, t);
34932 * Read-only. Returns true if the menu is currently displayed, else false.
34935 isVisible : function(){
34936 return this.el && !this.hidden;
34940 * Displays this menu relative to another element
34941 * @param {String/HTMLElement/Roo.Element} element The element to align to
34942 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34943 * the element (defaults to this.defaultAlign)
34944 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34946 show : function(el, pos, parentMenu){
34947 this.parentMenu = parentMenu;
34951 this.fireEvent("beforeshow", this);
34952 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34956 * Displays this menu at a specific xy position
34957 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34958 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34960 showAt : function(xy, parentMenu, /* private: */_e){
34961 this.parentMenu = parentMenu;
34966 this.fireEvent("beforeshow", this);
34967 xy = this.el.adjustForConstraints(xy);
34971 this.hidden = false;
34973 this.fireEvent("show", this);
34976 focus : function(){
34978 this.doFocus.defer(50, this);
34982 doFocus : function(){
34984 this.focusEl.focus();
34989 * Hides this menu and optionally all parent menus
34990 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34992 hide : function(deep){
34993 if(this.el && this.isVisible()){
34994 this.fireEvent("beforehide", this);
34995 if(this.activeItem){
34996 this.activeItem.deactivate();
34997 this.activeItem = null;
35000 this.hidden = true;
35001 this.fireEvent("hide", this);
35003 if(deep === true && this.parentMenu){
35004 this.parentMenu.hide(true);
35009 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35010 * Any of the following are valid:
35012 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35013 * <li>An HTMLElement object which will be converted to a menu item</li>
35014 * <li>A menu item config object that will be created as a new menu item</li>
35015 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35016 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35021 var menu = new Roo.menu.Menu();
35023 // Create a menu item to add by reference
35024 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35026 // Add a bunch of items at once using different methods.
35027 // Only the last item added will be returned.
35028 var item = menu.add(
35029 menuItem, // add existing item by ref
35030 'Dynamic Item', // new TextItem
35031 '-', // new separator
35032 { text: 'Config Item' } // new item by config
35035 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35036 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35039 var a = arguments, l = a.length, item;
35040 for(var i = 0; i < l; i++){
35042 if ((typeof(el) == "object") && el.xtype && el.xns) {
35043 el = Roo.factory(el, Roo.menu);
35046 if(el.render){ // some kind of Item
35047 item = this.addItem(el);
35048 }else if(typeof el == "string"){ // string
35049 if(el == "separator" || el == "-"){
35050 item = this.addSeparator();
35052 item = this.addText(el);
35054 }else if(el.tagName || el.el){ // element
35055 item = this.addElement(el);
35056 }else if(typeof el == "object"){ // must be menu item config?
35057 item = this.addMenuItem(el);
35064 * Returns this menu's underlying {@link Roo.Element} object
35065 * @return {Roo.Element} The element
35067 getEl : function(){
35075 * Adds a separator bar to the menu
35076 * @return {Roo.menu.Item} The menu item that was added
35078 addSeparator : function(){
35079 return this.addItem(new Roo.menu.Separator());
35083 * Adds an {@link Roo.Element} object to the menu
35084 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35085 * @return {Roo.menu.Item} The menu item that was added
35087 addElement : function(el){
35088 return this.addItem(new Roo.menu.BaseItem(el));
35092 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35093 * @param {Roo.menu.Item} item The menu item to add
35094 * @return {Roo.menu.Item} The menu item that was added
35096 addItem : function(item){
35097 this.items.add(item);
35099 var li = document.createElement("li");
35100 li.className = "x-menu-list-item";
35101 this.ul.dom.appendChild(li);
35102 item.render(li, this);
35103 this.delayAutoWidth();
35109 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35110 * @param {Object} config A MenuItem config object
35111 * @return {Roo.menu.Item} The menu item that was added
35113 addMenuItem : function(config){
35114 if(!(config instanceof Roo.menu.Item)){
35115 if(typeof config.checked == "boolean"){ // must be check menu item config?
35116 config = new Roo.menu.CheckItem(config);
35118 config = new Roo.menu.Item(config);
35121 return this.addItem(config);
35125 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35126 * @param {String} text The text to display in the menu item
35127 * @return {Roo.menu.Item} The menu item that was added
35129 addText : function(text){
35130 return this.addItem(new Roo.menu.TextItem({ text : text }));
35134 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35135 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35136 * @param {Roo.menu.Item} item The menu item to add
35137 * @return {Roo.menu.Item} The menu item that was added
35139 insert : function(index, item){
35140 this.items.insert(index, item);
35142 var li = document.createElement("li");
35143 li.className = "x-menu-list-item";
35144 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35145 item.render(li, this);
35146 this.delayAutoWidth();
35152 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35153 * @param {Roo.menu.Item} item The menu item to remove
35155 remove : function(item){
35156 this.items.removeKey(item.id);
35161 * Removes and destroys all items in the menu
35163 removeAll : function(){
35165 while(f = this.items.first()){
35171 // MenuNav is a private utility class used internally by the Menu
35172 Roo.menu.MenuNav = function(menu){
35173 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35174 this.scope = this.menu = menu;
35177 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35178 doRelay : function(e, h){
35179 var k = e.getKey();
35180 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35181 this.menu.tryActivate(0, 1);
35184 return h.call(this.scope || this, e, this.menu);
35187 up : function(e, m){
35188 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35189 m.tryActivate(m.items.length-1, -1);
35193 down : function(e, m){
35194 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35195 m.tryActivate(0, 1);
35199 right : function(e, m){
35201 m.activeItem.expandMenu(true);
35205 left : function(e, m){
35207 if(m.parentMenu && m.parentMenu.activeItem){
35208 m.parentMenu.activeItem.activate();
35212 enter : function(e, m){
35214 e.stopPropagation();
35215 m.activeItem.onClick(e);
35216 m.fireEvent("click", this, m.activeItem);
35222 * Ext JS Library 1.1.1
35223 * Copyright(c) 2006-2007, Ext JS, LLC.
35225 * Originally Released Under LGPL - original licence link has changed is not relivant.
35228 * <script type="text/javascript">
35232 * @class Roo.menu.MenuMgr
35233 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35236 Roo.menu.MenuMgr = function(){
35237 var menus, active, groups = {}, attached = false, lastShow = new Date();
35239 // private - called when first menu is created
35242 active = new Roo.util.MixedCollection();
35243 Roo.get(document).addKeyListener(27, function(){
35244 if(active.length > 0){
35251 function hideAll(){
35252 if(active && active.length > 0){
35253 var c = active.clone();
35254 c.each(function(m){
35261 function onHide(m){
35263 if(active.length < 1){
35264 Roo.get(document).un("mousedown", onMouseDown);
35270 function onShow(m){
35271 var last = active.last();
35272 lastShow = new Date();
35275 Roo.get(document).on("mousedown", onMouseDown);
35279 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35280 m.parentMenu.activeChild = m;
35281 }else if(last && last.isVisible()){
35282 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35287 function onBeforeHide(m){
35289 m.activeChild.hide();
35291 if(m.autoHideTimer){
35292 clearTimeout(m.autoHideTimer);
35293 delete m.autoHideTimer;
35298 function onBeforeShow(m){
35299 var pm = m.parentMenu;
35300 if(!pm && !m.allowOtherMenus){
35302 }else if(pm && pm.activeChild && active != m){
35303 pm.activeChild.hide();
35308 function onMouseDown(e){
35309 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35315 function onBeforeCheck(mi, state){
35317 var g = groups[mi.group];
35318 for(var i = 0, l = g.length; i < l; i++){
35320 g[i].setChecked(false);
35329 * Hides all menus that are currently visible
35331 hideAll : function(){
35336 register : function(menu){
35340 menus[menu.id] = menu;
35341 menu.on("beforehide", onBeforeHide);
35342 menu.on("hide", onHide);
35343 menu.on("beforeshow", onBeforeShow);
35344 menu.on("show", onShow);
35345 var g = menu.group;
35346 if(g && menu.events["checkchange"]){
35350 groups[g].push(menu);
35351 menu.on("checkchange", onCheck);
35356 * Returns a {@link Roo.menu.Menu} object
35357 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35358 * be used to generate and return a new Menu instance.
35360 get : function(menu){
35361 if(typeof menu == "string"){ // menu id
35362 return menus[menu];
35363 }else if(menu.events){ // menu instance
35365 }else if(typeof menu.length == 'number'){ // array of menu items?
35366 return new Roo.menu.Menu({items:menu});
35367 }else{ // otherwise, must be a config
35368 return new Roo.menu.Menu(menu);
35373 unregister : function(menu){
35374 delete menus[menu.id];
35375 menu.un("beforehide", onBeforeHide);
35376 menu.un("hide", onHide);
35377 menu.un("beforeshow", onBeforeShow);
35378 menu.un("show", onShow);
35379 var g = menu.group;
35380 if(g && menu.events["checkchange"]){
35381 groups[g].remove(menu);
35382 menu.un("checkchange", onCheck);
35387 registerCheckable : function(menuItem){
35388 var g = menuItem.group;
35393 groups[g].push(menuItem);
35394 menuItem.on("beforecheckchange", onBeforeCheck);
35399 unregisterCheckable : function(menuItem){
35400 var g = menuItem.group;
35402 groups[g].remove(menuItem);
35403 menuItem.un("beforecheckchange", onBeforeCheck);
35409 * Ext JS Library 1.1.1
35410 * Copyright(c) 2006-2007, Ext JS, LLC.
35412 * Originally Released Under LGPL - original licence link has changed is not relivant.
35415 * <script type="text/javascript">
35420 * @class Roo.menu.BaseItem
35421 * @extends Roo.Component
35422 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35423 * management and base configuration options shared by all menu components.
35425 * Creates a new BaseItem
35426 * @param {Object} config Configuration options
35428 Roo.menu.BaseItem = function(config){
35429 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35434 * Fires when this item is clicked
35435 * @param {Roo.menu.BaseItem} this
35436 * @param {Roo.EventObject} e
35441 * Fires when this item is activated
35442 * @param {Roo.menu.BaseItem} this
35446 * @event deactivate
35447 * Fires when this item is deactivated
35448 * @param {Roo.menu.BaseItem} this
35454 this.on("click", this.handler, this.scope, true);
35458 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35460 * @cfg {Function} handler
35461 * A function that will handle the click event of this menu item (defaults to undefined)
35464 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35466 canActivate : false,
35468 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35470 activeClass : "x-menu-item-active",
35472 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35474 hideOnClick : true,
35476 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35481 ctype: "Roo.menu.BaseItem",
35484 actionMode : "container",
35487 render : function(container, parentMenu){
35488 this.parentMenu = parentMenu;
35489 Roo.menu.BaseItem.superclass.render.call(this, container);
35490 this.container.menuItemId = this.id;
35494 onRender : function(container, position){
35495 this.el = Roo.get(this.el);
35496 container.dom.appendChild(this.el.dom);
35500 onClick : function(e){
35501 if(!this.disabled && this.fireEvent("click", this, e) !== false
35502 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35503 this.handleClick(e);
35510 activate : function(){
35514 var li = this.container;
35515 li.addClass(this.activeClass);
35516 this.region = li.getRegion().adjust(2, 2, -2, -2);
35517 this.fireEvent("activate", this);
35522 deactivate : function(){
35523 this.container.removeClass(this.activeClass);
35524 this.fireEvent("deactivate", this);
35528 shouldDeactivate : function(e){
35529 return !this.region || !this.region.contains(e.getPoint());
35533 handleClick : function(e){
35534 if(this.hideOnClick){
35535 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35540 expandMenu : function(autoActivate){
35545 hideMenu : function(){
35550 * Ext JS Library 1.1.1
35551 * Copyright(c) 2006-2007, Ext JS, LLC.
35553 * Originally Released Under LGPL - original licence link has changed is not relivant.
35556 * <script type="text/javascript">
35560 * @class Roo.menu.Adapter
35561 * @extends Roo.menu.BaseItem
35562 * 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.
35563 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35565 * Creates a new Adapter
35566 * @param {Object} config Configuration options
35568 Roo.menu.Adapter = function(component, config){
35569 Roo.menu.Adapter.superclass.constructor.call(this, config);
35570 this.component = component;
35572 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35574 canActivate : true,
35577 onRender : function(container, position){
35578 this.component.render(container);
35579 this.el = this.component.getEl();
35583 activate : function(){
35587 this.component.focus();
35588 this.fireEvent("activate", this);
35593 deactivate : function(){
35594 this.fireEvent("deactivate", this);
35598 disable : function(){
35599 this.component.disable();
35600 Roo.menu.Adapter.superclass.disable.call(this);
35604 enable : function(){
35605 this.component.enable();
35606 Roo.menu.Adapter.superclass.enable.call(this);
35610 * Ext JS Library 1.1.1
35611 * Copyright(c) 2006-2007, Ext JS, LLC.
35613 * Originally Released Under LGPL - original licence link has changed is not relivant.
35616 * <script type="text/javascript">
35620 * @class Roo.menu.TextItem
35621 * @extends Roo.menu.BaseItem
35622 * Adds a static text string to a menu, usually used as either a heading or group separator.
35623 * Note: old style constructor with text is still supported.
35626 * Creates a new TextItem
35627 * @param {Object} cfg Configuration
35629 Roo.menu.TextItem = function(cfg){
35630 if (typeof(cfg) == 'string') {
35633 Roo.apply(this,cfg);
35636 Roo.menu.TextItem.superclass.constructor.call(this);
35639 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35641 * @cfg {Boolean} text Text to show on item.
35646 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35648 hideOnClick : false,
35650 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35652 itemCls : "x-menu-text",
35655 onRender : function(){
35656 var s = document.createElement("span");
35657 s.className = this.itemCls;
35658 s.innerHTML = this.text;
35660 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35664 * Ext JS Library 1.1.1
35665 * Copyright(c) 2006-2007, Ext JS, LLC.
35667 * Originally Released Under LGPL - original licence link has changed is not relivant.
35670 * <script type="text/javascript">
35674 * @class Roo.menu.Separator
35675 * @extends Roo.menu.BaseItem
35676 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35677 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35679 * @param {Object} config Configuration options
35681 Roo.menu.Separator = function(config){
35682 Roo.menu.Separator.superclass.constructor.call(this, config);
35685 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35687 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35689 itemCls : "x-menu-sep",
35691 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35693 hideOnClick : false,
35696 onRender : function(li){
35697 var s = document.createElement("span");
35698 s.className = this.itemCls;
35699 s.innerHTML = " ";
35701 li.addClass("x-menu-sep-li");
35702 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35706 * Ext JS Library 1.1.1
35707 * Copyright(c) 2006-2007, Ext JS, LLC.
35709 * Originally Released Under LGPL - original licence link has changed is not relivant.
35712 * <script type="text/javascript">
35715 * @class Roo.menu.Item
35716 * @extends Roo.menu.BaseItem
35717 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35718 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35719 * activation and click handling.
35721 * Creates a new Item
35722 * @param {Object} config Configuration options
35724 Roo.menu.Item = function(config){
35725 Roo.menu.Item.superclass.constructor.call(this, config);
35727 this.menu = Roo.menu.MenuMgr.get(this.menu);
35730 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35733 * @cfg {String} text
35734 * The text to show on the menu item.
35738 * @cfg {String} HTML to render in menu
35739 * The text to show on the menu item (HTML version).
35743 * @cfg {String} icon
35744 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35748 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35750 itemCls : "x-menu-item",
35752 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35754 canActivate : true,
35756 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35759 // doc'd in BaseItem
35763 ctype: "Roo.menu.Item",
35766 onRender : function(container, position){
35767 var el = document.createElement("a");
35768 el.hideFocus = true;
35769 el.unselectable = "on";
35770 el.href = this.href || "#";
35771 if(this.hrefTarget){
35772 el.target = this.hrefTarget;
35774 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35776 var html = this.html.length ? this.html : String.format('{0}',this.text);
35778 el.innerHTML = String.format(
35779 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35780 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35782 Roo.menu.Item.superclass.onRender.call(this, container, position);
35786 * Sets the text to display in this menu item
35787 * @param {String} text The text to display
35788 * @param {Boolean} isHTML true to indicate text is pure html.
35790 setText : function(text, isHTML){
35798 var html = this.html.length ? this.html : String.format('{0}',this.text);
35800 this.el.update(String.format(
35801 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35802 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35803 this.parentMenu.autoWidth();
35808 handleClick : function(e){
35809 if(!this.href){ // if no link defined, stop the event automatically
35812 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35816 activate : function(autoExpand){
35817 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35827 shouldDeactivate : function(e){
35828 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35829 if(this.menu && this.menu.isVisible()){
35830 return !this.menu.getEl().getRegion().contains(e.getPoint());
35838 deactivate : function(){
35839 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35844 expandMenu : function(autoActivate){
35845 if(!this.disabled && this.menu){
35846 clearTimeout(this.hideTimer);
35847 delete this.hideTimer;
35848 if(!this.menu.isVisible() && !this.showTimer){
35849 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35850 }else if (this.menu.isVisible() && autoActivate){
35851 this.menu.tryActivate(0, 1);
35857 deferExpand : function(autoActivate){
35858 delete this.showTimer;
35859 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35861 this.menu.tryActivate(0, 1);
35866 hideMenu : function(){
35867 clearTimeout(this.showTimer);
35868 delete this.showTimer;
35869 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35870 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35875 deferHide : function(){
35876 delete this.hideTimer;
35881 * Ext JS Library 1.1.1
35882 * Copyright(c) 2006-2007, Ext JS, LLC.
35884 * Originally Released Under LGPL - original licence link has changed is not relivant.
35887 * <script type="text/javascript">
35891 * @class Roo.menu.CheckItem
35892 * @extends Roo.menu.Item
35893 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35895 * Creates a new CheckItem
35896 * @param {Object} config Configuration options
35898 Roo.menu.CheckItem = function(config){
35899 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35902 * @event beforecheckchange
35903 * Fires before the checked value is set, providing an opportunity to cancel if needed
35904 * @param {Roo.menu.CheckItem} this
35905 * @param {Boolean} checked The new checked value that will be set
35907 "beforecheckchange" : true,
35909 * @event checkchange
35910 * Fires after the checked value has been set
35911 * @param {Roo.menu.CheckItem} this
35912 * @param {Boolean} checked The checked value that was set
35914 "checkchange" : true
35916 if(this.checkHandler){
35917 this.on('checkchange', this.checkHandler, this.scope);
35920 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35922 * @cfg {String} group
35923 * All check items with the same group name will automatically be grouped into a single-select
35924 * radio button group (defaults to '')
35927 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35929 itemCls : "x-menu-item x-menu-check-item",
35931 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35933 groupClass : "x-menu-group-item",
35936 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35937 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35938 * initialized with checked = true will be rendered as checked.
35943 ctype: "Roo.menu.CheckItem",
35946 onRender : function(c){
35947 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35949 this.el.addClass(this.groupClass);
35951 Roo.menu.MenuMgr.registerCheckable(this);
35953 this.checked = false;
35954 this.setChecked(true, true);
35959 destroy : function(){
35961 Roo.menu.MenuMgr.unregisterCheckable(this);
35963 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35967 * Set the checked state of this item
35968 * @param {Boolean} checked The new checked value
35969 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35971 setChecked : function(state, suppressEvent){
35972 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35973 if(this.container){
35974 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35976 this.checked = state;
35977 if(suppressEvent !== true){
35978 this.fireEvent("checkchange", this, state);
35984 handleClick : function(e){
35985 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35986 this.setChecked(!this.checked);
35988 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35992 * Ext JS Library 1.1.1
35993 * Copyright(c) 2006-2007, Ext JS, LLC.
35995 * Originally Released Under LGPL - original licence link has changed is not relivant.
35998 * <script type="text/javascript">
36002 * @class Roo.menu.DateItem
36003 * @extends Roo.menu.Adapter
36004 * A menu item that wraps the {@link Roo.DatPicker} component.
36006 * Creates a new DateItem
36007 * @param {Object} config Configuration options
36009 Roo.menu.DateItem = function(config){
36010 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36011 /** The Roo.DatePicker object @type Roo.DatePicker */
36012 this.picker = this.component;
36013 this.addEvents({select: true});
36015 this.picker.on("render", function(picker){
36016 picker.getEl().swallowEvent("click");
36017 picker.container.addClass("x-menu-date-item");
36020 this.picker.on("select", this.onSelect, this);
36023 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36025 onSelect : function(picker, date){
36026 this.fireEvent("select", this, date, picker);
36027 Roo.menu.DateItem.superclass.handleClick.call(this);
36031 * Ext JS Library 1.1.1
36032 * Copyright(c) 2006-2007, Ext JS, LLC.
36034 * Originally Released Under LGPL - original licence link has changed is not relivant.
36037 * <script type="text/javascript">
36041 * @class Roo.menu.ColorItem
36042 * @extends Roo.menu.Adapter
36043 * A menu item that wraps the {@link Roo.ColorPalette} component.
36045 * Creates a new ColorItem
36046 * @param {Object} config Configuration options
36048 Roo.menu.ColorItem = function(config){
36049 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36050 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36051 this.palette = this.component;
36052 this.relayEvents(this.palette, ["select"]);
36053 if(this.selectHandler){
36054 this.on('select', this.selectHandler, this.scope);
36057 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36059 * Ext JS Library 1.1.1
36060 * Copyright(c) 2006-2007, Ext JS, LLC.
36062 * Originally Released Under LGPL - original licence link has changed is not relivant.
36065 * <script type="text/javascript">
36070 * @class Roo.menu.DateMenu
36071 * @extends Roo.menu.Menu
36072 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36074 * Creates a new DateMenu
36075 * @param {Object} config Configuration options
36077 Roo.menu.DateMenu = function(config){
36078 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36080 var di = new Roo.menu.DateItem(config);
36083 * The {@link Roo.DatePicker} instance for this DateMenu
36086 this.picker = di.picker;
36089 * @param {DatePicker} picker
36090 * @param {Date} date
36092 this.relayEvents(di, ["select"]);
36093 this.on('beforeshow', function(){
36095 this.picker.hideMonthPicker(false);
36099 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36103 * Ext JS Library 1.1.1
36104 * Copyright(c) 2006-2007, Ext JS, LLC.
36106 * Originally Released Under LGPL - original licence link has changed is not relivant.
36109 * <script type="text/javascript">
36114 * @class Roo.menu.ColorMenu
36115 * @extends Roo.menu.Menu
36116 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36118 * Creates a new ColorMenu
36119 * @param {Object} config Configuration options
36121 Roo.menu.ColorMenu = function(config){
36122 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36124 var ci = new Roo.menu.ColorItem(config);
36127 * The {@link Roo.ColorPalette} instance for this ColorMenu
36128 * @type ColorPalette
36130 this.palette = ci.palette;
36133 * @param {ColorPalette} palette
36134 * @param {String} color
36136 this.relayEvents(ci, ["select"]);
36138 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36140 * Ext JS Library 1.1.1
36141 * Copyright(c) 2006-2007, Ext JS, LLC.
36143 * Originally Released Under LGPL - original licence link has changed is not relivant.
36146 * <script type="text/javascript">
36150 * @class Roo.form.Field
36151 * @extends Roo.BoxComponent
36152 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36154 * Creates a new Field
36155 * @param {Object} config Configuration options
36157 Roo.form.Field = function(config){
36158 Roo.form.Field.superclass.constructor.call(this, config);
36161 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36163 * @cfg {String} fieldLabel Label to use when rendering a form.
36166 * @cfg {String} qtip Mouse over tip
36170 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36172 invalidClass : "x-form-invalid",
36174 * @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")
36176 invalidText : "The value in this field is invalid",
36178 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36180 focusClass : "x-form-focus",
36182 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36183 automatic validation (defaults to "keyup").
36185 validationEvent : "keyup",
36187 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36189 validateOnBlur : true,
36191 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36193 validationDelay : 250,
36195 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36196 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36198 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36200 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36202 fieldClass : "x-form-field",
36204 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36207 ----------- ----------------------------------------------------------------------
36208 qtip Display a quick tip when the user hovers over the field
36209 title Display a default browser title attribute popup
36210 under Add a block div beneath the field containing the error text
36211 side Add an error icon to the right of the field with a popup on hover
36212 [element id] Add the error text directly to the innerHTML of the specified element
36215 msgTarget : 'qtip',
36217 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36222 * @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.
36227 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36232 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36234 inputType : undefined,
36237 * @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).
36239 tabIndex : undefined,
36242 isFormField : true,
36247 * @property {Roo.Element} fieldEl
36248 * Element Containing the rendered Field (with label etc.)
36251 * @cfg {Mixed} value A value to initialize this field with.
36256 * @cfg {String} name The field's HTML name attribute.
36259 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36263 initComponent : function(){
36264 Roo.form.Field.superclass.initComponent.call(this);
36268 * Fires when this field receives input focus.
36269 * @param {Roo.form.Field} this
36274 * Fires when this field loses input focus.
36275 * @param {Roo.form.Field} this
36279 * @event specialkey
36280 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36281 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36282 * @param {Roo.form.Field} this
36283 * @param {Roo.EventObject} e The event object
36288 * Fires just before the field blurs if the field value has changed.
36289 * @param {Roo.form.Field} this
36290 * @param {Mixed} newValue The new value
36291 * @param {Mixed} oldValue The original value
36296 * Fires after the field has been marked as invalid.
36297 * @param {Roo.form.Field} this
36298 * @param {String} msg The validation message
36303 * Fires after the field has been validated with no errors.
36304 * @param {Roo.form.Field} this
36309 * Fires after the key up
36310 * @param {Roo.form.Field} this
36311 * @param {Roo.EventObject} e The event Object
36318 * Returns the name attribute of the field if available
36319 * @return {String} name The field name
36321 getName: function(){
36322 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36326 onRender : function(ct, position){
36327 Roo.form.Field.superclass.onRender.call(this, ct, position);
36329 var cfg = this.getAutoCreate();
36331 cfg.name = this.name || this.id;
36333 if(this.inputType){
36334 cfg.type = this.inputType;
36336 this.el = ct.createChild(cfg, position);
36338 var type = this.el.dom.type;
36340 if(type == 'password'){
36343 this.el.addClass('x-form-'+type);
36346 this.el.dom.readOnly = true;
36348 if(this.tabIndex !== undefined){
36349 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36352 this.el.addClass([this.fieldClass, this.cls]);
36357 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36358 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36359 * @return {Roo.form.Field} this
36361 applyTo : function(target){
36362 this.allowDomMove = false;
36363 this.el = Roo.get(target);
36364 this.render(this.el.dom.parentNode);
36369 initValue : function(){
36370 if(this.value !== undefined){
36371 this.setValue(this.value);
36372 }else if(this.el.dom.value.length > 0){
36373 this.setValue(this.el.dom.value);
36378 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36380 isDirty : function() {
36381 if(this.disabled) {
36384 return String(this.getValue()) !== String(this.originalValue);
36388 afterRender : function(){
36389 Roo.form.Field.superclass.afterRender.call(this);
36394 fireKey : function(e){
36395 //Roo.log('field ' + e.getKey());
36396 if(e.isNavKeyPress()){
36397 this.fireEvent("specialkey", this, e);
36402 * Resets the current field value to the originally loaded value and clears any validation messages
36404 reset : function(){
36405 this.setValue(this.originalValue);
36406 this.clearInvalid();
36410 initEvents : function(){
36411 // safari killled keypress - so keydown is now used..
36412 this.el.on("keydown" , this.fireKey, this);
36413 this.el.on("focus", this.onFocus, this);
36414 this.el.on("blur", this.onBlur, this);
36415 this.el.relayEvent('keyup', this);
36417 // reference to original value for reset
36418 this.originalValue = this.getValue();
36422 onFocus : function(){
36423 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36424 this.el.addClass(this.focusClass);
36426 if(!this.hasFocus){
36427 this.hasFocus = true;
36428 this.startValue = this.getValue();
36429 this.fireEvent("focus", this);
36433 beforeBlur : Roo.emptyFn,
36436 onBlur : function(){
36438 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36439 this.el.removeClass(this.focusClass);
36441 this.hasFocus = false;
36442 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36445 var v = this.getValue();
36446 if(String(v) !== String(this.startValue)){
36447 this.fireEvent('change', this, v, this.startValue);
36449 this.fireEvent("blur", this);
36453 * Returns whether or not the field value is currently valid
36454 * @param {Boolean} preventMark True to disable marking the field invalid
36455 * @return {Boolean} True if the value is valid, else false
36457 isValid : function(preventMark){
36461 var restore = this.preventMark;
36462 this.preventMark = preventMark === true;
36463 var v = this.validateValue(this.processValue(this.getRawValue()));
36464 this.preventMark = restore;
36469 * Validates the field value
36470 * @return {Boolean} True if the value is valid, else false
36472 validate : function(){
36473 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36474 this.clearInvalid();
36480 processValue : function(value){
36485 // Subclasses should provide the validation implementation by overriding this
36486 validateValue : function(value){
36491 * Mark this field as invalid
36492 * @param {String} msg The validation message
36494 markInvalid : function(msg){
36495 if(!this.rendered || this.preventMark){ // not rendered
36498 this.el.addClass(this.invalidClass);
36499 msg = msg || this.invalidText;
36500 switch(this.msgTarget){
36502 this.el.dom.qtip = msg;
36503 this.el.dom.qclass = 'x-form-invalid-tip';
36504 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36505 Roo.QuickTips.enable();
36509 this.el.dom.title = msg;
36513 var elp = this.el.findParent('.x-form-element', 5, true);
36514 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36515 this.errorEl.setWidth(elp.getWidth(true)-20);
36517 this.errorEl.update(msg);
36518 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36521 if(!this.errorIcon){
36522 var elp = this.el.findParent('.x-form-element', 5, true);
36523 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36525 this.alignErrorIcon();
36526 this.errorIcon.dom.qtip = msg;
36527 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36528 this.errorIcon.show();
36529 this.on('resize', this.alignErrorIcon, this);
36532 var t = Roo.getDom(this.msgTarget);
36534 t.style.display = this.msgDisplay;
36537 this.fireEvent('invalid', this, msg);
36541 alignErrorIcon : function(){
36542 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36546 * Clear any invalid styles/messages for this field
36548 clearInvalid : function(){
36549 if(!this.rendered || this.preventMark){ // not rendered
36552 this.el.removeClass(this.invalidClass);
36553 switch(this.msgTarget){
36555 this.el.dom.qtip = '';
36558 this.el.dom.title = '';
36562 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36566 if(this.errorIcon){
36567 this.errorIcon.dom.qtip = '';
36568 this.errorIcon.hide();
36569 this.un('resize', this.alignErrorIcon, this);
36573 var t = Roo.getDom(this.msgTarget);
36575 t.style.display = 'none';
36578 this.fireEvent('valid', this);
36582 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36583 * @return {Mixed} value The field value
36585 getRawValue : function(){
36586 var v = this.el.getValue();
36587 if(v === this.emptyText){
36594 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36595 * @return {Mixed} value The field value
36597 getValue : function(){
36598 var v = this.el.getValue();
36599 if(v === this.emptyText || v === undefined){
36606 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36607 * @param {Mixed} value The value to set
36609 setRawValue : function(v){
36610 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36614 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36615 * @param {Mixed} value The value to set
36617 setValue : function(v){
36620 this.el.dom.value = (v === null || v === undefined ? '' : v);
36625 adjustSize : function(w, h){
36626 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36627 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36631 adjustWidth : function(tag, w){
36632 tag = tag.toLowerCase();
36633 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36634 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36635 if(tag == 'input'){
36638 if(tag = 'textarea'){
36641 }else if(Roo.isOpera){
36642 if(tag == 'input'){
36645 if(tag = 'textarea'){
36655 // anything other than normal should be considered experimental
36656 Roo.form.Field.msgFx = {
36658 show: function(msgEl, f){
36659 msgEl.setDisplayed('block');
36662 hide : function(msgEl, f){
36663 msgEl.setDisplayed(false).update('');
36668 show: function(msgEl, f){
36669 msgEl.slideIn('t', {stopFx:true});
36672 hide : function(msgEl, f){
36673 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36678 show: function(msgEl, f){
36679 msgEl.fixDisplay();
36680 msgEl.alignTo(f.el, 'tl-tr');
36681 msgEl.slideIn('l', {stopFx:true});
36684 hide : function(msgEl, f){
36685 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36690 * Ext JS Library 1.1.1
36691 * Copyright(c) 2006-2007, Ext JS, LLC.
36693 * Originally Released Under LGPL - original licence link has changed is not relivant.
36696 * <script type="text/javascript">
36701 * @class Roo.form.TextField
36702 * @extends Roo.form.Field
36703 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36704 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36706 * Creates a new TextField
36707 * @param {Object} config Configuration options
36709 Roo.form.TextField = function(config){
36710 Roo.form.TextField.superclass.constructor.call(this, config);
36714 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36715 * according to the default logic, but this event provides a hook for the developer to apply additional
36716 * logic at runtime to resize the field if needed.
36717 * @param {Roo.form.Field} this This text field
36718 * @param {Number} width The new field width
36724 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36726 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36730 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36734 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36738 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36742 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36746 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36748 disableKeyFilter : false,
36750 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36754 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36758 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36760 maxLength : Number.MAX_VALUE,
36762 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36764 minLengthText : "The minimum length for this field is {0}",
36766 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36768 maxLengthText : "The maximum length for this field is {0}",
36770 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36772 selectOnFocus : false,
36774 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36776 blankText : "This field is required",
36778 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36779 * If available, this function will be called only after the basic validators all return true, and will be passed the
36780 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36784 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36785 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36786 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36790 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36794 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36798 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36799 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36801 emptyClass : 'x-form-empty-field',
36804 initEvents : function(){
36805 Roo.form.TextField.superclass.initEvents.call(this);
36806 if(this.validationEvent == 'keyup'){
36807 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36808 this.el.on('keyup', this.filterValidation, this);
36810 else if(this.validationEvent !== false){
36811 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36813 if(this.selectOnFocus || this.emptyText){
36814 this.on("focus", this.preFocus, this);
36815 if(this.emptyText){
36816 this.on('blur', this.postBlur, this);
36817 this.applyEmptyText();
36820 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36821 this.el.on("keypress", this.filterKeys, this);
36824 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36825 this.el.on("click", this.autoSize, this);
36829 processValue : function(value){
36830 if(this.stripCharsRe){
36831 var newValue = value.replace(this.stripCharsRe, '');
36832 if(newValue !== value){
36833 this.setRawValue(newValue);
36840 filterValidation : function(e){
36841 if(!e.isNavKeyPress()){
36842 this.validationTask.delay(this.validationDelay);
36847 onKeyUp : function(e){
36848 if(!e.isNavKeyPress()){
36854 * Resets the current field value to the originally-loaded value and clears any validation messages.
36855 * Also adds emptyText and emptyClass if the original value was blank.
36857 reset : function(){
36858 Roo.form.TextField.superclass.reset.call(this);
36859 this.applyEmptyText();
36862 applyEmptyText : function(){
36863 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36864 this.setRawValue(this.emptyText);
36865 this.el.addClass(this.emptyClass);
36870 preFocus : function(){
36871 if(this.emptyText){
36872 if(this.el.dom.value == this.emptyText){
36873 this.setRawValue('');
36875 this.el.removeClass(this.emptyClass);
36877 if(this.selectOnFocus){
36878 this.el.dom.select();
36883 postBlur : function(){
36884 this.applyEmptyText();
36888 filterKeys : function(e){
36889 var k = e.getKey();
36890 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36893 var c = e.getCharCode(), cc = String.fromCharCode(c);
36894 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36897 if(!this.maskRe.test(cc)){
36902 setValue : function(v){
36903 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36904 this.el.removeClass(this.emptyClass);
36906 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36907 this.applyEmptyText();
36912 * Validates a value according to the field's validation rules and marks the field as invalid
36913 * if the validation fails
36914 * @param {Mixed} value The value to validate
36915 * @return {Boolean} True if the value is valid, else false
36917 validateValue : function(value){
36918 if(value.length < 1 || value === this.emptyText){ // if it's blank
36919 if(this.allowBlank){
36920 this.clearInvalid();
36923 this.markInvalid(this.blankText);
36927 if(value.length < this.minLength){
36928 this.markInvalid(String.format(this.minLengthText, this.minLength));
36931 if(value.length > this.maxLength){
36932 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36936 var vt = Roo.form.VTypes;
36937 if(!vt[this.vtype](value, this)){
36938 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36942 if(typeof this.validator == "function"){
36943 var msg = this.validator(value);
36945 this.markInvalid(msg);
36949 if(this.regex && !this.regex.test(value)){
36950 this.markInvalid(this.regexText);
36957 * Selects text in this field
36958 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36959 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36961 selectText : function(start, end){
36962 var v = this.getRawValue();
36964 start = start === undefined ? 0 : start;
36965 end = end === undefined ? v.length : end;
36966 var d = this.el.dom;
36967 if(d.setSelectionRange){
36968 d.setSelectionRange(start, end);
36969 }else if(d.createTextRange){
36970 var range = d.createTextRange();
36971 range.moveStart("character", start);
36972 range.moveEnd("character", v.length-end);
36979 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36980 * This only takes effect if grow = true, and fires the autosize event.
36982 autoSize : function(){
36983 if(!this.grow || !this.rendered){
36987 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36990 var v = el.dom.value;
36991 var d = document.createElement('div');
36992 d.appendChild(document.createTextNode(v));
36996 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36997 this.el.setWidth(w);
36998 this.fireEvent("autosize", this, w);
37002 * Ext JS Library 1.1.1
37003 * Copyright(c) 2006-2007, Ext JS, LLC.
37005 * Originally Released Under LGPL - original licence link has changed is not relivant.
37008 * <script type="text/javascript">
37012 * @class Roo.form.Hidden
37013 * @extends Roo.form.TextField
37014 * Simple Hidden element used on forms
37016 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37019 * Creates a new Hidden form element.
37020 * @param {Object} config Configuration options
37025 // easy hidden field...
37026 Roo.form.Hidden = function(config){
37027 Roo.form.Hidden.superclass.constructor.call(this, config);
37030 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37032 inputType: 'hidden',
37035 labelSeparator: '',
37037 itemCls : 'x-form-item-display-none'
37045 * Ext JS Library 1.1.1
37046 * Copyright(c) 2006-2007, Ext JS, LLC.
37048 * Originally Released Under LGPL - original licence link has changed is not relivant.
37051 * <script type="text/javascript">
37055 * @class Roo.form.TriggerField
37056 * @extends Roo.form.TextField
37057 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37058 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37059 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37060 * for which you can provide a custom implementation. For example:
37062 var trigger = new Roo.form.TriggerField();
37063 trigger.onTriggerClick = myTriggerFn;
37064 trigger.applyTo('my-field');
37067 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37068 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37069 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37070 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37072 * Create a new TriggerField.
37073 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37074 * to the base TextField)
37076 Roo.form.TriggerField = function(config){
37077 this.mimicing = false;
37078 Roo.form.TriggerField.superclass.constructor.call(this, config);
37081 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37083 * @cfg {String} triggerClass A CSS class to apply to the trigger
37086 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37087 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37089 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37091 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37095 /** @cfg {Boolean} grow @hide */
37096 /** @cfg {Number} growMin @hide */
37097 /** @cfg {Number} growMax @hide */
37103 autoSize: Roo.emptyFn,
37107 deferHeight : true,
37110 actionMode : 'wrap',
37112 onResize : function(w, h){
37113 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37114 if(typeof w == 'number'){
37115 var x = w - this.trigger.getWidth();
37116 this.el.setWidth(this.adjustWidth('input', x));
37117 this.trigger.setStyle('left', x+'px');
37122 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37125 getResizeEl : function(){
37130 getPositionEl : function(){
37135 alignErrorIcon : function(){
37136 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37140 onRender : function(ct, position){
37141 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37142 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37143 this.trigger = this.wrap.createChild(this.triggerConfig ||
37144 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37145 if(this.hideTrigger){
37146 this.trigger.setDisplayed(false);
37148 this.initTrigger();
37150 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37155 initTrigger : function(){
37156 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37157 this.trigger.addClassOnOver('x-form-trigger-over');
37158 this.trigger.addClassOnClick('x-form-trigger-click');
37162 onDestroy : function(){
37164 this.trigger.removeAllListeners();
37165 this.trigger.remove();
37168 this.wrap.remove();
37170 Roo.form.TriggerField.superclass.onDestroy.call(this);
37174 onFocus : function(){
37175 Roo.form.TriggerField.superclass.onFocus.call(this);
37176 if(!this.mimicing){
37177 this.wrap.addClass('x-trigger-wrap-focus');
37178 this.mimicing = true;
37179 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37180 if(this.monitorTab){
37181 this.el.on("keydown", this.checkTab, this);
37187 checkTab : function(e){
37188 if(e.getKey() == e.TAB){
37189 this.triggerBlur();
37194 onBlur : function(){
37199 mimicBlur : function(e, t){
37200 if(!this.wrap.contains(t) && this.validateBlur()){
37201 this.triggerBlur();
37206 triggerBlur : function(){
37207 this.mimicing = false;
37208 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37209 if(this.monitorTab){
37210 this.el.un("keydown", this.checkTab, this);
37212 this.wrap.removeClass('x-trigger-wrap-focus');
37213 Roo.form.TriggerField.superclass.onBlur.call(this);
37217 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37218 validateBlur : function(e, t){
37223 onDisable : function(){
37224 Roo.form.TriggerField.superclass.onDisable.call(this);
37226 this.wrap.addClass('x-item-disabled');
37231 onEnable : function(){
37232 Roo.form.TriggerField.superclass.onEnable.call(this);
37234 this.wrap.removeClass('x-item-disabled');
37239 onShow : function(){
37240 var ae = this.getActionEl();
37243 ae.dom.style.display = '';
37244 ae.dom.style.visibility = 'visible';
37250 onHide : function(){
37251 var ae = this.getActionEl();
37252 ae.dom.style.display = 'none';
37256 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37257 * by an implementing function.
37259 * @param {EventObject} e
37261 onTriggerClick : Roo.emptyFn
37264 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37265 // to be extended by an implementing class. For an example of implementing this class, see the custom
37266 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37267 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37268 initComponent : function(){
37269 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37271 this.triggerConfig = {
37272 tag:'span', cls:'x-form-twin-triggers', cn:[
37273 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37274 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37278 getTrigger : function(index){
37279 return this.triggers[index];
37282 initTrigger : function(){
37283 var ts = this.trigger.select('.x-form-trigger', true);
37284 this.wrap.setStyle('overflow', 'hidden');
37285 var triggerField = this;
37286 ts.each(function(t, all, index){
37287 t.hide = function(){
37288 var w = triggerField.wrap.getWidth();
37289 this.dom.style.display = 'none';
37290 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37292 t.show = function(){
37293 var w = triggerField.wrap.getWidth();
37294 this.dom.style.display = '';
37295 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37297 var triggerIndex = 'Trigger'+(index+1);
37299 if(this['hide'+triggerIndex]){
37300 t.dom.style.display = 'none';
37302 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37303 t.addClassOnOver('x-form-trigger-over');
37304 t.addClassOnClick('x-form-trigger-click');
37306 this.triggers = ts.elements;
37309 onTrigger1Click : Roo.emptyFn,
37310 onTrigger2Click : Roo.emptyFn
37313 * Ext JS Library 1.1.1
37314 * Copyright(c) 2006-2007, Ext JS, LLC.
37316 * Originally Released Under LGPL - original licence link has changed is not relivant.
37319 * <script type="text/javascript">
37323 * @class Roo.form.TextArea
37324 * @extends Roo.form.TextField
37325 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37326 * support for auto-sizing.
37328 * Creates a new TextArea
37329 * @param {Object} config Configuration options
37331 Roo.form.TextArea = function(config){
37332 Roo.form.TextArea.superclass.constructor.call(this, config);
37333 // these are provided exchanges for backwards compat
37334 // minHeight/maxHeight were replaced by growMin/growMax to be
37335 // compatible with TextField growing config values
37336 if(this.minHeight !== undefined){
37337 this.growMin = this.minHeight;
37339 if(this.maxHeight !== undefined){
37340 this.growMax = this.maxHeight;
37344 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37346 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37350 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37354 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37355 * in the field (equivalent to setting overflow: hidden, defaults to false)
37357 preventScrollbars: false,
37359 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37360 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37364 onRender : function(ct, position){
37366 this.defaultAutoCreate = {
37368 style:"width:300px;height:60px;",
37369 autocomplete: "off"
37372 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37374 this.textSizeEl = Roo.DomHelper.append(document.body, {
37375 tag: "pre", cls: "x-form-grow-sizer"
37377 if(this.preventScrollbars){
37378 this.el.setStyle("overflow", "hidden");
37380 this.el.setHeight(this.growMin);
37384 onDestroy : function(){
37385 if(this.textSizeEl){
37386 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37388 Roo.form.TextArea.superclass.onDestroy.call(this);
37392 onKeyUp : function(e){
37393 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37399 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37400 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37402 autoSize : function(){
37403 if(!this.grow || !this.textSizeEl){
37407 var v = el.dom.value;
37408 var ts = this.textSizeEl;
37411 ts.appendChild(document.createTextNode(v));
37414 Roo.fly(ts).setWidth(this.el.getWidth());
37416 v = "  ";
37419 v = v.replace(/\n/g, '<p> </p>');
37421 v += " \n ";
37424 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37425 if(h != this.lastHeight){
37426 this.lastHeight = h;
37427 this.el.setHeight(h);
37428 this.fireEvent("autosize", this, h);
37433 * Ext JS Library 1.1.1
37434 * Copyright(c) 2006-2007, Ext JS, LLC.
37436 * Originally Released Under LGPL - original licence link has changed is not relivant.
37439 * <script type="text/javascript">
37444 * @class Roo.form.NumberField
37445 * @extends Roo.form.TextField
37446 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37448 * Creates a new NumberField
37449 * @param {Object} config Configuration options
37451 Roo.form.NumberField = function(config){
37452 Roo.form.NumberField.superclass.constructor.call(this, config);
37455 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37457 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37459 fieldClass: "x-form-field x-form-num-field",
37461 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37463 allowDecimals : true,
37465 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37467 decimalSeparator : ".",
37469 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37471 decimalPrecision : 2,
37473 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37475 allowNegative : true,
37477 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37479 minValue : Number.NEGATIVE_INFINITY,
37481 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37483 maxValue : Number.MAX_VALUE,
37485 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37487 minText : "The minimum value for this field is {0}",
37489 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37491 maxText : "The maximum value for this field is {0}",
37493 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37494 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37496 nanText : "{0} is not a valid number",
37499 initEvents : function(){
37500 Roo.form.NumberField.superclass.initEvents.call(this);
37501 var allowed = "0123456789";
37502 if(this.allowDecimals){
37503 allowed += this.decimalSeparator;
37505 if(this.allowNegative){
37508 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37509 var keyPress = function(e){
37510 var k = e.getKey();
37511 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37514 var c = e.getCharCode();
37515 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37519 this.el.on("keypress", keyPress, this);
37523 validateValue : function(value){
37524 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37527 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37530 var num = this.parseValue(value);
37532 this.markInvalid(String.format(this.nanText, value));
37535 if(num < this.minValue){
37536 this.markInvalid(String.format(this.minText, this.minValue));
37539 if(num > this.maxValue){
37540 this.markInvalid(String.format(this.maxText, this.maxValue));
37546 getValue : function(){
37547 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37551 parseValue : function(value){
37552 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37553 return isNaN(value) ? '' : value;
37557 fixPrecision : function(value){
37558 var nan = isNaN(value);
37559 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37560 return nan ? '' : value;
37562 return parseFloat(value).toFixed(this.decimalPrecision);
37565 setValue : function(v){
37566 v = this.fixPrecision(v);
37567 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37571 decimalPrecisionFcn : function(v){
37572 return Math.floor(v);
37575 beforeBlur : function(){
37576 var v = this.parseValue(this.getRawValue());
37583 * Ext JS Library 1.1.1
37584 * Copyright(c) 2006-2007, Ext JS, LLC.
37586 * Originally Released Under LGPL - original licence link has changed is not relivant.
37589 * <script type="text/javascript">
37593 * @class Roo.form.DateField
37594 * @extends Roo.form.TriggerField
37595 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37597 * Create a new DateField
37598 * @param {Object} config
37600 Roo.form.DateField = function(config){
37601 Roo.form.DateField.superclass.constructor.call(this, config);
37607 * Fires when a date is selected
37608 * @param {Roo.form.DateField} combo This combo box
37609 * @param {Date} date The date selected
37616 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37617 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37618 this.ddMatch = null;
37619 if(this.disabledDates){
37620 var dd = this.disabledDates;
37622 for(var i = 0; i < dd.length; i++){
37624 if(i != dd.length-1) re += "|";
37626 this.ddMatch = new RegExp(re + ")");
37630 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37632 * @cfg {String} format
37633 * The default date format string which can be overriden for localization support. The format must be
37634 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37638 * @cfg {String} altFormats
37639 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37640 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37642 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37644 * @cfg {Array} disabledDays
37645 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37647 disabledDays : null,
37649 * @cfg {String} disabledDaysText
37650 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37652 disabledDaysText : "Disabled",
37654 * @cfg {Array} disabledDates
37655 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37656 * expression so they are very powerful. Some examples:
37658 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37659 * <li>["03/08", "09/16"] would disable those days for every year</li>
37660 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37661 * <li>["03/../2006"] would disable every day in March 2006</li>
37662 * <li>["^03"] would disable every day in every March</li>
37664 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37665 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37667 disabledDates : null,
37669 * @cfg {String} disabledDatesText
37670 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37672 disabledDatesText : "Disabled",
37674 * @cfg {Date/String} minValue
37675 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37676 * valid format (defaults to null).
37680 * @cfg {Date/String} maxValue
37681 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37682 * valid format (defaults to null).
37686 * @cfg {String} minText
37687 * The error text to display when the date in the cell is before minValue (defaults to
37688 * 'The date in this field must be after {minValue}').
37690 minText : "The date in this field must be equal to or after {0}",
37692 * @cfg {String} maxText
37693 * The error text to display when the date in the cell is after maxValue (defaults to
37694 * 'The date in this field must be before {maxValue}').
37696 maxText : "The date in this field must be equal to or before {0}",
37698 * @cfg {String} invalidText
37699 * The error text to display when the date in the field is invalid (defaults to
37700 * '{value} is not a valid date - it must be in the format {format}').
37702 invalidText : "{0} is not a valid date - it must be in the format {1}",
37704 * @cfg {String} triggerClass
37705 * An additional CSS class used to style the trigger button. The trigger will always get the
37706 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37707 * which displays a calendar icon).
37709 triggerClass : 'x-form-date-trigger',
37713 * @cfg {Boolean} useIso
37714 * if enabled, then the date field will use a hidden field to store the
37715 * real value as iso formated date. default (false)
37719 * @cfg {String/Object} autoCreate
37720 * A DomHelper element spec, or true for a default element spec (defaults to
37721 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37724 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37727 hiddenField: false,
37729 onRender : function(ct, position)
37731 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37733 this.el.dom.removeAttribute('name');
37734 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37736 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37737 // prevent input submission
37738 this.hiddenName = this.name;
37745 validateValue : function(value)
37747 value = this.formatDate(value);
37748 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37749 Roo.log('super failed');
37752 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37755 var svalue = value;
37756 value = this.parseDate(value);
37758 Roo.log('parse date failed' + svalue);
37759 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37762 var time = value.getTime();
37763 if(this.minValue && time < this.minValue.getTime()){
37764 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37767 if(this.maxValue && time > this.maxValue.getTime()){
37768 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37771 if(this.disabledDays){
37772 var day = value.getDay();
37773 for(var i = 0; i < this.disabledDays.length; i++) {
37774 if(day === this.disabledDays[i]){
37775 this.markInvalid(this.disabledDaysText);
37780 var fvalue = this.formatDate(value);
37781 if(this.ddMatch && this.ddMatch.test(fvalue)){
37782 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37789 // Provides logic to override the default TriggerField.validateBlur which just returns true
37790 validateBlur : function(){
37791 return !this.menu || !this.menu.isVisible();
37795 * Returns the current date value of the date field.
37796 * @return {Date} The date value
37798 getValue : function(){
37800 return this.hiddenField ?
37801 this.hiddenField.value :
37802 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37806 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37807 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37808 * (the default format used is "m/d/y").
37811 //All of these calls set the same date value (May 4, 2006)
37813 //Pass a date object:
37814 var dt = new Date('5/4/06');
37815 dateField.setValue(dt);
37817 //Pass a date string (default format):
37818 dateField.setValue('5/4/06');
37820 //Pass a date string (custom format):
37821 dateField.format = 'Y-m-d';
37822 dateField.setValue('2006-5-4');
37824 * @param {String/Date} date The date or valid date string
37826 setValue : function(date){
37827 if (this.hiddenField) {
37828 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37830 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37831 // make sure the value field is always stored as a date..
37832 this.value = this.parseDate(date);
37838 parseDate : function(value){
37839 if(!value || value instanceof Date){
37842 var v = Date.parseDate(value, this.format);
37843 if (!v && this.useIso) {
37844 v = Date.parseDate(value, 'Y-m-d');
37846 if(!v && this.altFormats){
37847 if(!this.altFormatsArray){
37848 this.altFormatsArray = this.altFormats.split("|");
37850 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37851 v = Date.parseDate(value, this.altFormatsArray[i]);
37858 formatDate : function(date, fmt){
37859 return (!date || !(date instanceof Date)) ?
37860 date : date.dateFormat(fmt || this.format);
37865 select: function(m, d){
37868 this.fireEvent('select', this, d);
37870 show : function(){ // retain focus styling
37874 this.focus.defer(10, this);
37875 var ml = this.menuListeners;
37876 this.menu.un("select", ml.select, this);
37877 this.menu.un("show", ml.show, this);
37878 this.menu.un("hide", ml.hide, this);
37883 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37884 onTriggerClick : function(){
37888 if(this.menu == null){
37889 this.menu = new Roo.menu.DateMenu();
37891 Roo.apply(this.menu.picker, {
37892 showClear: this.allowBlank,
37893 minDate : this.minValue,
37894 maxDate : this.maxValue,
37895 disabledDatesRE : this.ddMatch,
37896 disabledDatesText : this.disabledDatesText,
37897 disabledDays : this.disabledDays,
37898 disabledDaysText : this.disabledDaysText,
37899 format : this.useIso ? 'Y-m-d' : this.format,
37900 minText : String.format(this.minText, this.formatDate(this.minValue)),
37901 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37903 this.menu.on(Roo.apply({}, this.menuListeners, {
37906 this.menu.picker.setValue(this.getValue() || new Date());
37907 this.menu.show(this.el, "tl-bl?");
37910 beforeBlur : function(){
37911 var v = this.parseDate(this.getRawValue());
37917 /** @cfg {Boolean} grow @hide */
37918 /** @cfg {Number} growMin @hide */
37919 /** @cfg {Number} growMax @hide */
37926 * Ext JS Library 1.1.1
37927 * Copyright(c) 2006-2007, Ext JS, LLC.
37929 * Originally Released Under LGPL - original licence link has changed is not relivant.
37932 * <script type="text/javascript">
37936 * @class Roo.form.MonthField
37937 * @extends Roo.form.TriggerField
37938 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37940 * Create a new MonthField
37941 * @param {Object} config
37943 Roo.form.MonthField = function(config){
37945 Roo.form.MonthField.superclass.constructor.call(this, config);
37951 * Fires when a date is selected
37952 * @param {Roo.form.MonthFieeld} combo This combo box
37953 * @param {Date} date The date selected
37960 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37961 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37962 this.ddMatch = null;
37963 if(this.disabledDates){
37964 var dd = this.disabledDates;
37966 for(var i = 0; i < dd.length; i++){
37968 if(i != dd.length-1) re += "|";
37970 this.ddMatch = new RegExp(re + ")");
37974 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
37976 * @cfg {String} format
37977 * The default date format string which can be overriden for localization support. The format must be
37978 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37982 * @cfg {String} altFormats
37983 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37984 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37986 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
37988 * @cfg {Array} disabledDays
37989 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37991 disabledDays : [0,1,2,3,4,5,6],
37993 * @cfg {String} disabledDaysText
37994 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37996 disabledDaysText : "Disabled",
37998 * @cfg {Array} disabledDates
37999 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38000 * expression so they are very powerful. Some examples:
38002 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38003 * <li>["03/08", "09/16"] would disable those days for every year</li>
38004 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38005 * <li>["03/../2006"] would disable every day in March 2006</li>
38006 * <li>["^03"] would disable every day in every March</li>
38008 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38009 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38011 disabledDates : null,
38013 * @cfg {String} disabledDatesText
38014 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38016 disabledDatesText : "Disabled",
38018 * @cfg {Date/String} minValue
38019 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38020 * valid format (defaults to null).
38024 * @cfg {Date/String} maxValue
38025 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38026 * valid format (defaults to null).
38030 * @cfg {String} minText
38031 * The error text to display when the date in the cell is before minValue (defaults to
38032 * 'The date in this field must be after {minValue}').
38034 minText : "The date in this field must be equal to or after {0}",
38036 * @cfg {String} maxTextf
38037 * The error text to display when the date in the cell is after maxValue (defaults to
38038 * 'The date in this field must be before {maxValue}').
38040 maxText : "The date in this field must be equal to or before {0}",
38042 * @cfg {String} invalidText
38043 * The error text to display when the date in the field is invalid (defaults to
38044 * '{value} is not a valid date - it must be in the format {format}').
38046 invalidText : "{0} is not a valid date - it must be in the format {1}",
38048 * @cfg {String} triggerClass
38049 * An additional CSS class used to style the trigger button. The trigger will always get the
38050 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38051 * which displays a calendar icon).
38053 triggerClass : 'x-form-date-trigger',
38057 * @cfg {Boolean} useIso
38058 * if enabled, then the date field will use a hidden field to store the
38059 * real value as iso formated date. default (true)
38063 * @cfg {String/Object} autoCreate
38064 * A DomHelper element spec, or true for a default element spec (defaults to
38065 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38068 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38071 hiddenField: false,
38073 hideMonthPicker : false,
38075 onRender : function(ct, position)
38077 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38079 this.el.dom.removeAttribute('name');
38080 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38082 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38083 // prevent input submission
38084 this.hiddenName = this.name;
38091 validateValue : function(value)
38093 value = this.formatDate(value);
38094 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38097 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38100 var svalue = value;
38101 value = this.parseDate(value);
38103 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38106 var time = value.getTime();
38107 if(this.minValue && time < this.minValue.getTime()){
38108 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38111 if(this.maxValue && time > this.maxValue.getTime()){
38112 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38115 /*if(this.disabledDays){
38116 var day = value.getDay();
38117 for(var i = 0; i < this.disabledDays.length; i++) {
38118 if(day === this.disabledDays[i]){
38119 this.markInvalid(this.disabledDaysText);
38125 var fvalue = this.formatDate(value);
38126 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38127 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38135 // Provides logic to override the default TriggerField.validateBlur which just returns true
38136 validateBlur : function(){
38137 return !this.menu || !this.menu.isVisible();
38141 * Returns the current date value of the date field.
38142 * @return {Date} The date value
38144 getValue : function(){
38148 return this.hiddenField ?
38149 this.hiddenField.value :
38150 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38154 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38155 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38156 * (the default format used is "m/d/y").
38159 //All of these calls set the same date value (May 4, 2006)
38161 //Pass a date object:
38162 var dt = new Date('5/4/06');
38163 monthField.setValue(dt);
38165 //Pass a date string (default format):
38166 monthField.setValue('5/4/06');
38168 //Pass a date string (custom format):
38169 monthField.format = 'Y-m-d';
38170 monthField.setValue('2006-5-4');
38172 * @param {String/Date} date The date or valid date string
38174 setValue : function(date){
38175 Roo.log('month setValue' + date);
38176 // can only be first of month..
38178 var val = this.parseDate(date);
38180 if (this.hiddenField) {
38181 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38183 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38184 this.value = this.parseDate(date);
38188 parseDate : function(value){
38189 if(!value || value instanceof Date){
38190 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38193 var v = Date.parseDate(value, this.format);
38194 if (!v && this.useIso) {
38195 v = Date.parseDate(value, 'Y-m-d');
38199 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38203 if(!v && this.altFormats){
38204 if(!this.altFormatsArray){
38205 this.altFormatsArray = this.altFormats.split("|");
38207 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38208 v = Date.parseDate(value, this.altFormatsArray[i]);
38215 formatDate : function(date, fmt){
38216 return (!date || !(date instanceof Date)) ?
38217 date : date.dateFormat(fmt || this.format);
38222 select: function(m, d){
38224 this.fireEvent('select', this, d);
38226 show : function(){ // retain focus styling
38230 this.focus.defer(10, this);
38231 var ml = this.menuListeners;
38232 this.menu.un("select", ml.select, this);
38233 this.menu.un("show", ml.show, this);
38234 this.menu.un("hide", ml.hide, this);
38238 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38239 onTriggerClick : function(){
38243 if(this.menu == null){
38244 this.menu = new Roo.menu.DateMenu();
38248 Roo.apply(this.menu.picker, {
38250 showClear: this.allowBlank,
38251 minDate : this.minValue,
38252 maxDate : this.maxValue,
38253 disabledDatesRE : this.ddMatch,
38254 disabledDatesText : this.disabledDatesText,
38256 format : this.useIso ? 'Y-m-d' : this.format,
38257 minText : String.format(this.minText, this.formatDate(this.minValue)),
38258 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38261 this.menu.on(Roo.apply({}, this.menuListeners, {
38269 // hide month picker get's called when we called by 'before hide';
38271 var ignorehide = true;
38272 p.hideMonthPicker = function(disableAnim){
38276 if(this.monthPicker){
38277 Roo.log("hideMonthPicker called");
38278 if(disableAnim === true){
38279 this.monthPicker.hide();
38281 this.monthPicker.slideOut('t', {duration:.2});
38282 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38283 p.fireEvent("select", this, this.value);
38289 Roo.log('picker set value');
38290 Roo.log(this.getValue());
38291 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38292 m.show(this.el, 'tl-bl?');
38293 ignorehide = false;
38294 // this will trigger hideMonthPicker..
38297 // hidden the day picker
38298 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38304 p.showMonthPicker.defer(100, p);
38310 beforeBlur : function(){
38311 var v = this.parseDate(this.getRawValue());
38317 /** @cfg {Boolean} grow @hide */
38318 /** @cfg {Number} growMin @hide */
38319 /** @cfg {Number} growMax @hide */
38326 * Ext JS Library 1.1.1
38327 * Copyright(c) 2006-2007, Ext JS, LLC.
38329 * Originally Released Under LGPL - original licence link has changed is not relivant.
38332 * <script type="text/javascript">
38337 * @class Roo.form.ComboBox
38338 * @extends Roo.form.TriggerField
38339 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38341 * Create a new ComboBox.
38342 * @param {Object} config Configuration options
38344 Roo.form.ComboBox = function(config){
38345 Roo.form.ComboBox.superclass.constructor.call(this, config);
38349 * Fires when the dropdown list is expanded
38350 * @param {Roo.form.ComboBox} combo This combo box
38355 * Fires when the dropdown list is collapsed
38356 * @param {Roo.form.ComboBox} combo This combo box
38360 * @event beforeselect
38361 * Fires before a list item is selected. Return false to cancel the selection.
38362 * @param {Roo.form.ComboBox} combo This combo box
38363 * @param {Roo.data.Record} record The data record returned from the underlying store
38364 * @param {Number} index The index of the selected item in the dropdown list
38366 'beforeselect' : true,
38369 * Fires when a list item is selected
38370 * @param {Roo.form.ComboBox} combo This combo box
38371 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
38372 * @param {Number} index The index of the selected item in the dropdown list
38376 * @event beforequery
38377 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
38378 * The event object passed has these properties:
38379 * @param {Roo.form.ComboBox} combo This combo box
38380 * @param {String} query The query
38381 * @param {Boolean} forceAll true to force "all" query
38382 * @param {Boolean} cancel true to cancel the query
38383 * @param {Object} e The query event object
38385 'beforequery': true,
38388 * Fires when the 'add' icon is pressed (add a listener to enable add button)
38389 * @param {Roo.form.ComboBox} combo This combo box
38394 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
38395 * @param {Roo.form.ComboBox} combo This combo box
38396 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
38402 if(this.transform){
38403 this.allowDomMove = false;
38404 var s = Roo.getDom(this.transform);
38405 if(!this.hiddenName){
38406 this.hiddenName = s.name;
38409 this.mode = 'local';
38410 var d = [], opts = s.options;
38411 for(var i = 0, len = opts.length;i < len; i++){
38413 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
38415 this.value = value;
38417 d.push([value, o.text]);
38419 this.store = new Roo.data.SimpleStore({
38421 fields: ['value', 'text'],
38424 this.valueField = 'value';
38425 this.displayField = 'text';
38427 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
38428 if(!this.lazyRender){
38429 this.target = true;
38430 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
38431 s.parentNode.removeChild(s); // remove it
38432 this.render(this.el.parentNode);
38434 s.parentNode.removeChild(s); // remove it
38439 this.store = Roo.factory(this.store, Roo.data);
38442 this.selectedIndex = -1;
38443 if(this.mode == 'local'){
38444 if(config.queryDelay === undefined){
38445 this.queryDelay = 10;
38447 if(config.minChars === undefined){
38453 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38455 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38458 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38459 * rendering into an Roo.Editor, defaults to false)
38462 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38463 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38466 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38469 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38470 * the dropdown list (defaults to undefined, with no header element)
38474 * @cfg {String/Roo.Template} tpl The template to use to render the output
38478 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38480 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38482 listWidth: undefined,
38484 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38485 * mode = 'remote' or 'text' if mode = 'local')
38487 displayField: undefined,
38489 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38490 * mode = 'remote' or 'value' if mode = 'local').
38491 * Note: use of a valueField requires the user make a selection
38492 * in order for a value to be mapped.
38494 valueField: undefined,
38498 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38499 * field's data value (defaults to the underlying DOM element's name)
38501 hiddenName: undefined,
38503 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38507 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38509 selectedClass: 'x-combo-selected',
38511 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38512 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38513 * which displays a downward arrow icon).
38515 triggerClass : 'x-form-arrow-trigger',
38517 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38521 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38522 * anchor positions (defaults to 'tl-bl')
38524 listAlign: 'tl-bl?',
38526 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38530 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38531 * query specified by the allQuery config option (defaults to 'query')
38533 triggerAction: 'query',
38535 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38536 * (defaults to 4, does not apply if editable = false)
38540 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38541 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38545 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38546 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38550 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38551 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38555 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38556 * when editable = true (defaults to false)
38558 selectOnFocus:false,
38560 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38562 queryParam: 'query',
38564 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38565 * when mode = 'remote' (defaults to 'Loading...')
38567 loadingText: 'Loading...',
38569 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38573 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38577 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38578 * traditional select (defaults to true)
38582 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38586 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38590 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38591 * listWidth has a higher value)
38595 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38596 * allow the user to set arbitrary text into the field (defaults to false)
38598 forceSelection:false,
38600 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38601 * if typeAhead = true (defaults to 250)
38603 typeAheadDelay : 250,
38605 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38606 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38608 valueNotFoundText : undefined,
38610 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38612 blockFocus : false,
38615 * @cfg {Boolean} disableClear Disable showing of clear button.
38617 disableClear : false,
38619 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38621 alwaysQuery : false,
38627 // element that contains real text value.. (when hidden is used..)
38630 onRender : function(ct, position){
38631 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38632 if(this.hiddenName){
38633 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38635 this.hiddenField.value =
38636 this.hiddenValue !== undefined ? this.hiddenValue :
38637 this.value !== undefined ? this.value : '';
38639 // prevent input submission
38640 this.el.dom.removeAttribute('name');
38645 this.el.dom.setAttribute('autocomplete', 'off');
38648 var cls = 'x-combo-list';
38650 this.list = new Roo.Layer({
38651 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38654 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38655 this.list.setWidth(lw);
38656 this.list.swallowEvent('mousewheel');
38657 this.assetHeight = 0;
38660 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38661 this.assetHeight += this.header.getHeight();
38664 this.innerList = this.list.createChild({cls:cls+'-inner'});
38665 this.innerList.on('mouseover', this.onViewOver, this);
38666 this.innerList.on('mousemove', this.onViewMove, this);
38667 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38669 if(this.allowBlank && !this.pageSize && !this.disableClear){
38670 this.footer = this.list.createChild({cls:cls+'-ft'});
38671 this.pageTb = new Roo.Toolbar(this.footer);
38675 this.footer = this.list.createChild({cls:cls+'-ft'});
38676 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38677 {pageSize: this.pageSize});
38681 if (this.pageTb && this.allowBlank && !this.disableClear) {
38683 this.pageTb.add(new Roo.Toolbar.Fill(), {
38684 cls: 'x-btn-icon x-btn-clear',
38686 handler: function()
38689 _this.clearValue();
38690 _this.onSelect(false, -1);
38695 this.assetHeight += this.footer.getHeight();
38700 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38703 this.view = new Roo.View(this.innerList, this.tpl, {
38704 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38707 this.view.on('click', this.onViewClick, this);
38709 this.store.on('beforeload', this.onBeforeLoad, this);
38710 this.store.on('load', this.onLoad, this);
38711 this.store.on('loadexception', this.onLoadException, this);
38713 if(this.resizable){
38714 this.resizer = new Roo.Resizable(this.list, {
38715 pinned:true, handles:'se'
38717 this.resizer.on('resize', function(r, w, h){
38718 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38719 this.listWidth = w;
38720 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38721 this.restrictHeight();
38723 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38725 if(!this.editable){
38726 this.editable = true;
38727 this.setEditable(false);
38731 if (typeof(this.events.add.listeners) != 'undefined') {
38733 this.addicon = this.wrap.createChild(
38734 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38736 this.addicon.on('click', function(e) {
38737 this.fireEvent('add', this);
38740 if (typeof(this.events.edit.listeners) != 'undefined') {
38742 this.editicon = this.wrap.createChild(
38743 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38744 if (this.addicon) {
38745 this.editicon.setStyle('margin-left', '40px');
38747 this.editicon.on('click', function(e) {
38749 // we fire even if inothing is selected..
38750 this.fireEvent('edit', this, this.lastData );
38760 initEvents : function(){
38761 Roo.form.ComboBox.superclass.initEvents.call(this);
38763 this.keyNav = new Roo.KeyNav(this.el, {
38764 "up" : function(e){
38765 this.inKeyMode = true;
38769 "down" : function(e){
38770 if(!this.isExpanded()){
38771 this.onTriggerClick();
38773 this.inKeyMode = true;
38778 "enter" : function(e){
38779 this.onViewClick();
38783 "esc" : function(e){
38787 "tab" : function(e){
38788 this.onViewClick(false);
38789 this.fireEvent("specialkey", this, e);
38795 doRelay : function(foo, bar, hname){
38796 if(hname == 'down' || this.scope.isExpanded()){
38797 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38804 this.queryDelay = Math.max(this.queryDelay || 10,
38805 this.mode == 'local' ? 10 : 250);
38806 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38807 if(this.typeAhead){
38808 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38810 if(this.editable !== false){
38811 this.el.on("keyup", this.onKeyUp, this);
38813 if(this.forceSelection){
38814 this.on('blur', this.doForce, this);
38818 onDestroy : function(){
38820 this.view.setStore(null);
38821 this.view.el.removeAllListeners();
38822 this.view.el.remove();
38823 this.view.purgeListeners();
38826 this.list.destroy();
38829 this.store.un('beforeload', this.onBeforeLoad, this);
38830 this.store.un('load', this.onLoad, this);
38831 this.store.un('loadexception', this.onLoadException, this);
38833 Roo.form.ComboBox.superclass.onDestroy.call(this);
38837 fireKey : function(e){
38838 if(e.isNavKeyPress() && !this.list.isVisible()){
38839 this.fireEvent("specialkey", this, e);
38844 onResize: function(w, h){
38845 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
38847 if(typeof w != 'number'){
38848 // we do not handle it!?!?
38851 var tw = this.trigger.getWidth();
38852 tw += this.addicon ? this.addicon.getWidth() : 0;
38853 tw += this.editicon ? this.editicon.getWidth() : 0;
38855 this.el.setWidth( this.adjustWidth('input', x));
38857 this.trigger.setStyle('left', x+'px');
38859 if(this.list && this.listWidth === undefined){
38860 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38861 this.list.setWidth(lw);
38862 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38870 * Allow or prevent the user from directly editing the field text. If false is passed,
38871 * the user will only be able to select from the items defined in the dropdown list. This method
38872 * is the runtime equivalent of setting the 'editable' config option at config time.
38873 * @param {Boolean} value True to allow the user to directly edit the field text
38875 setEditable : function(value){
38876 if(value == this.editable){
38879 this.editable = value;
38881 this.el.dom.setAttribute('readOnly', true);
38882 this.el.on('mousedown', this.onTriggerClick, this);
38883 this.el.addClass('x-combo-noedit');
38885 this.el.dom.setAttribute('readOnly', false);
38886 this.el.un('mousedown', this.onTriggerClick, this);
38887 this.el.removeClass('x-combo-noedit');
38892 onBeforeLoad : function(){
38893 if(!this.hasFocus){
38896 this.innerList.update(this.loadingText ?
38897 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
38898 this.restrictHeight();
38899 this.selectedIndex = -1;
38903 onLoad : function(){
38904 if(!this.hasFocus){
38907 if(this.store.getCount() > 0){
38909 this.restrictHeight();
38910 if(this.lastQuery == this.allQuery){
38912 this.el.dom.select();
38914 if(!this.selectByValue(this.value, true)){
38915 this.select(0, true);
38919 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38920 this.taTask.delay(this.typeAheadDelay);
38924 this.onEmptyResults();
38929 onLoadException : function()
38932 Roo.log(this.store.reader.jsonData);
38933 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
38934 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38940 onTypeAhead : function(){
38941 if(this.store.getCount() > 0){
38942 var r = this.store.getAt(0);
38943 var newValue = r.data[this.displayField];
38944 var len = newValue.length;
38945 var selStart = this.getRawValue().length;
38946 if(selStart != len){
38947 this.setRawValue(newValue);
38948 this.selectText(selStart, newValue.length);
38954 onSelect : function(record, index){
38955 if(this.fireEvent('beforeselect', this, record, index) !== false){
38956 this.setFromData(index > -1 ? record.data : false);
38958 this.fireEvent('select', this, record, index);
38963 * Returns the currently selected field value or empty string if no value is set.
38964 * @return {String} value The selected value
38966 getValue : function(){
38967 if(this.valueField){
38968 return typeof this.value != 'undefined' ? this.value : '';
38970 return Roo.form.ComboBox.superclass.getValue.call(this);
38975 * Clears any text/value currently set in the field
38977 clearValue : function(){
38978 if(this.hiddenField){
38979 this.hiddenField.value = '';
38982 this.setRawValue('');
38983 this.lastSelectionText = '';
38984 this.applyEmptyText();
38988 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38989 * will be displayed in the field. If the value does not match the data value of an existing item,
38990 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38991 * Otherwise the field will be blank (although the value will still be set).
38992 * @param {String} value The value to match
38994 setValue : function(v){
38996 if(this.valueField){
38997 var r = this.findRecord(this.valueField, v);
38999 text = r.data[this.displayField];
39000 }else if(this.valueNotFoundText !== undefined){
39001 text = this.valueNotFoundText;
39004 this.lastSelectionText = text;
39005 if(this.hiddenField){
39006 this.hiddenField.value = v;
39008 Roo.form.ComboBox.superclass.setValue.call(this, text);
39012 * @property {Object} the last set data for the element
39017 * Sets the value of the field based on a object which is related to the record format for the store.
39018 * @param {Object} value the value to set as. or false on reset?
39020 setFromData : function(o){
39021 var dv = ''; // display value
39022 var vv = ''; // value value..
39024 if (this.displayField) {
39025 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39027 // this is an error condition!!!
39028 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39031 if(this.valueField){
39032 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39034 if(this.hiddenField){
39035 this.hiddenField.value = vv;
39037 this.lastSelectionText = dv;
39038 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39042 // no hidden field.. - we store the value in 'value', but still display
39043 // display field!!!!
39044 this.lastSelectionText = dv;
39045 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39051 reset : function(){
39052 // overridden so that last data is reset..
39053 this.setValue(this.originalValue);
39054 this.clearInvalid();
39055 this.lastData = false;
39057 this.view.clearSelections();
39061 findRecord : function(prop, value){
39063 if(this.store.getCount() > 0){
39064 this.store.each(function(r){
39065 if(r.data[prop] == value){
39075 getName: function()
39077 // returns hidden if it's set..
39078 if (!this.rendered) {return ''};
39079 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39083 onViewMove : function(e, t){
39084 this.inKeyMode = false;
39088 onViewOver : function(e, t){
39089 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39092 var item = this.view.findItemFromChild(t);
39094 var index = this.view.indexOf(item);
39095 this.select(index, false);
39100 onViewClick : function(doFocus)
39102 var index = this.view.getSelectedIndexes()[0];
39103 var r = this.store.getAt(index);
39105 this.onSelect(r, index);
39107 if(doFocus !== false && !this.blockFocus){
39113 restrictHeight : function(){
39114 this.innerList.dom.style.height = '';
39115 var inner = this.innerList.dom;
39116 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39117 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39118 this.list.beginUpdate();
39119 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39120 this.list.alignTo(this.el, this.listAlign);
39121 this.list.endUpdate();
39125 onEmptyResults : function(){
39130 * Returns true if the dropdown list is expanded, else false.
39132 isExpanded : function(){
39133 return this.list.isVisible();
39137 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39138 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39139 * @param {String} value The data value of the item to select
39140 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39141 * selected item if it is not currently in view (defaults to true)
39142 * @return {Boolean} True if the value matched an item in the list, else false
39144 selectByValue : function(v, scrollIntoView){
39145 if(v !== undefined && v !== null){
39146 var r = this.findRecord(this.valueField || this.displayField, v);
39148 this.select(this.store.indexOf(r), scrollIntoView);
39156 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39157 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39158 * @param {Number} index The zero-based index of the list item to select
39159 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39160 * selected item if it is not currently in view (defaults to true)
39162 select : function(index, scrollIntoView){
39163 this.selectedIndex = index;
39164 this.view.select(index);
39165 if(scrollIntoView !== false){
39166 var el = this.view.getNode(index);
39168 this.innerList.scrollChildIntoView(el, false);
39174 selectNext : function(){
39175 var ct = this.store.getCount();
39177 if(this.selectedIndex == -1){
39179 }else if(this.selectedIndex < ct-1){
39180 this.select(this.selectedIndex+1);
39186 selectPrev : function(){
39187 var ct = this.store.getCount();
39189 if(this.selectedIndex == -1){
39191 }else if(this.selectedIndex != 0){
39192 this.select(this.selectedIndex-1);
39198 onKeyUp : function(e){
39199 if(this.editable !== false && !e.isSpecialKey()){
39200 this.lastKey = e.getKey();
39201 this.dqTask.delay(this.queryDelay);
39206 validateBlur : function(){
39207 return !this.list || !this.list.isVisible();
39211 initQuery : function(){
39212 this.doQuery(this.getRawValue());
39216 doForce : function(){
39217 if(this.el.dom.value.length > 0){
39218 this.el.dom.value =
39219 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39220 this.applyEmptyText();
39225 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39226 * query allowing the query action to be canceled if needed.
39227 * @param {String} query The SQL query to execute
39228 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39229 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39230 * saved in the current store (defaults to false)
39232 doQuery : function(q, forceAll){
39233 if(q === undefined || q === null){
39238 forceAll: forceAll,
39242 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39246 forceAll = qe.forceAll;
39247 if(forceAll === true || (q.length >= this.minChars)){
39248 if(this.lastQuery != q || this.alwaysQuery){
39249 this.lastQuery = q;
39250 if(this.mode == 'local'){
39251 this.selectedIndex = -1;
39253 this.store.clearFilter();
39255 this.store.filter(this.displayField, q);
39259 this.store.baseParams[this.queryParam] = q;
39261 params: this.getParams(q)
39266 this.selectedIndex = -1;
39273 getParams : function(q){
39275 //p[this.queryParam] = q;
39278 p.limit = this.pageSize;
39284 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39286 collapse : function(){
39287 if(!this.isExpanded()){
39291 Roo.get(document).un('mousedown', this.collapseIf, this);
39292 Roo.get(document).un('mousewheel', this.collapseIf, this);
39293 if (!this.editable) {
39294 Roo.get(document).un('keydown', this.listKeyPress, this);
39296 this.fireEvent('collapse', this);
39300 collapseIf : function(e){
39301 if(!e.within(this.wrap) && !e.within(this.list)){
39307 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39309 expand : function(){
39310 if(this.isExpanded() || !this.hasFocus){
39313 this.list.alignTo(this.el, this.listAlign);
39315 Roo.get(document).on('mousedown', this.collapseIf, this);
39316 Roo.get(document).on('mousewheel', this.collapseIf, this);
39317 if (!this.editable) {
39318 Roo.get(document).on('keydown', this.listKeyPress, this);
39321 this.fireEvent('expand', this);
39325 // Implements the default empty TriggerField.onTriggerClick function
39326 onTriggerClick : function(){
39330 if(this.isExpanded()){
39332 if (!this.blockFocus) {
39337 this.hasFocus = true;
39338 if(this.triggerAction == 'all') {
39339 this.doQuery(this.allQuery, true);
39341 this.doQuery(this.getRawValue());
39343 if (!this.blockFocus) {
39348 listKeyPress : function(e)
39350 //Roo.log('listkeypress');
39351 // scroll to first matching element based on key pres..
39352 if (e.isSpecialKey()) {
39355 var k = String.fromCharCode(e.getKey()).toUpperCase();
39358 var csel = this.view.getSelectedNodes();
39359 var cselitem = false;
39361 var ix = this.view.indexOf(csel[0]);
39362 cselitem = this.store.getAt(ix);
39363 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39369 this.store.each(function(v) {
39371 // start at existing selection.
39372 if (cselitem.id == v.id) {
39378 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39379 match = this.store.indexOf(v);
39384 if (match === false) {
39385 return true; // no more action?
39388 this.view.select(match);
39389 var sn = Roo.get(this.view.getSelectedNodes()[0])
39390 sn.scrollIntoView(sn.dom.parentNode, false);
39394 * @cfg {Boolean} grow
39398 * @cfg {Number} growMin
39402 * @cfg {Number} growMax
39410 * Copyright(c) 2010-2012, Roo J Solutions Limited
39417 * @class Roo.form.ComboBoxArray
39418 * @extends Roo.form.TextField
39419 * A facebook style adder... for lists of email / people / countries etc...
39420 * pick multiple items from a combo box, and shows each one.
39422 * Fred [x] Brian [x] [Pick another |v]
39425 * For this to work: it needs various extra information
39426 * - normal combo problay has
39428 * + displayField, valueField
39430 * For our purpose...
39433 * If we change from 'extends' to wrapping...
39440 * Create a new ComboBoxArray.
39441 * @param {Object} config Configuration options
39445 Roo.form.ComboBoxArray = function(config)
39448 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
39450 this.items = new Roo.util.MixedCollection(false);
39452 // construct the child combo...
39462 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39465 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39470 // behavies liek a hiddne field
39471 inputType: 'hidden',
39473 * @cfg {Number} width The width of the box that displays the selected element
39480 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39484 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39486 hiddenName : false,
39489 // private the array of items that are displayed..
39491 // private - the hidden field el.
39493 // private - the filed el..
39496 //validateValue : function() { return true; }, // all values are ok!
39497 //onAddClick: function() { },
39499 onRender : function(ct, position)
39502 // create the standard hidden element
39503 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39506 // give fake names to child combo;
39507 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39508 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39510 this.combo = Roo.factory(this.combo, Roo.form);
39511 this.combo.onRender(ct, position);
39512 this.combo.initEvents();
39514 // assigned so form know we need to do this..
39515 this.store = this.combo.store;
39516 this.valueField = this.combo.valueField;
39517 this.displayField = this.combo.displayField ;
39520 this.combo.wrap.addClass('x-cbarray-grp');
39522 var cbwrap = this.combo.wrap.createChild(
39523 {tag: 'div', cls: 'x-cbarray-cb'},
39528 this.hiddenEl = this.combo.wrap.createChild({
39529 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39531 this.el = this.combo.wrap.createChild({
39532 tag: 'input', type:'hidden' , name: this.name, value : ''
39534 // this.el.dom.removeAttribute("name");
39537 this.outerWrap = this.combo.wrap;
39538 this.wrap = cbwrap;
39540 this.outerWrap.setWidth(this.width);
39541 this.outerWrap.dom.removeChild(this.el.dom);
39543 this.wrap.dom.appendChild(this.el.dom);
39544 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39545 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39547 this.combo.trigger.setStyle('position','relative');
39548 this.combo.trigger.setStyle('left', '0px');
39549 this.combo.trigger.setStyle('top', '2px');
39551 this.combo.el.setStyle('vertical-align', 'text-bottom');
39553 //this.trigger.setStyle('vertical-align', 'top');
39555 // this should use the code from combo really... on('add' ....)
39559 this.adder = this.outerWrap.createChild(
39560 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39562 this.adder.on('click', function(e) {
39563 _t.fireEvent('adderclick', this, e);
39567 //this.adder.on('click', this.onAddClick, _t);
39570 this.combo.on('select', function(cb, rec, ix) {
39571 this.addItem(rec.data);
39574 cb.el.dom.value = '';
39575 //cb.lastData = rec.data;
39584 getName: function()
39586 // returns hidden if it's set..
39587 if (!this.rendered) {return ''};
39588 return this.hiddenName ? this.hiddenName : this.name;
39593 onResize: function(w, h){
39596 // not sure if this is needed..
39597 //this.combo.onResize(w,h);
39599 if(typeof w != 'number'){
39600 // we do not handle it!?!?
39603 var tw = this.combo.trigger.getWidth();
39604 tw += this.addicon ? this.addicon.getWidth() : 0;
39605 tw += this.editicon ? this.editicon.getWidth() : 0;
39607 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39609 this.combo.trigger.setStyle('left', '0px');
39611 if(this.list && this.listWidth === undefined){
39612 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39613 this.list.setWidth(lw);
39614 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39621 addItem: function(rec)
39623 var valueField = this.combo.valueField;
39624 var displayField = this.combo.displayField;
39625 if (this.items.indexOfKey(rec[valueField]) > -1) {
39626 //console.log("GOT " + rec.data.id);
39630 var x = new Roo.form.ComboBoxArray.Item({
39631 //id : rec[this.idField],
39633 displayField : displayField ,
39634 tipField : displayField ,
39638 this.items.add(rec[valueField],x);
39639 // add it before the element..
39640 this.updateHiddenEl();
39641 x.render(this.outerWrap, this.wrap.dom);
39642 // add the image handler..
39645 updateHiddenEl : function()
39648 if (!this.hiddenEl) {
39652 var idField = this.combo.valueField;
39654 this.items.each(function(f) {
39655 ar.push(f.data[idField]);
39658 this.hiddenEl.dom.value = ar.join(',');
39664 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39665 this.items.each(function(f) {
39668 this.el.dom.value = '';
39669 if (this.hiddenEl) {
39670 this.hiddenEl.dom.value = '';
39674 getValue: function()
39676 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39678 setValue: function(v) // not a valid action - must use addItems..
39685 if (this.store.isLocal && (typeof(v) == 'string')) {
39686 // then we can use the store to find the values..
39687 // comma seperated at present.. this needs to allow JSON based encoding..
39688 this.hiddenEl.value = v;
39690 Roo.each(v.split(','), function(k) {
39691 Roo.log("CHECK " + this.valueField + ',' + k);
39692 var li = this.store.query(this.valueField, k);
39697 add[this.valueField] = k;
39698 add[this.displayField] = li.item(0).data[this.displayField];
39704 if (typeof(v) == 'object') {
39705 // then let's assume it's an array of objects..
39706 Roo.each(v, function(l) {
39714 setFromData: function(v)
39716 // this recieves an object, if setValues is called.
39718 this.el.dom.value = v[this.displayField];
39719 this.hiddenEl.dom.value = v[this.valueField];
39720 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39723 var kv = v[this.valueField];
39724 var dv = v[this.displayField];
39725 kv = typeof(kv) != 'string' ? '' : kv;
39726 dv = typeof(dv) != 'string' ? '' : dv;
39729 var keys = kv.split(',');
39730 var display = dv.split(',');
39731 for (var i = 0 ; i < keys.length; i++) {
39734 add[this.valueField] = keys[i];
39735 add[this.displayField] = display[i];
39743 validateValue : function(value){
39744 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39753 * @class Roo.form.ComboBoxArray.Item
39754 * @extends Roo.BoxComponent
39755 * A selected item in the list
39756 * Fred [x] Brian [x] [Pick another |v]
39759 * Create a new item.
39760 * @param {Object} config Configuration options
39763 Roo.form.ComboBoxArray.Item = function(config) {
39764 config.id = Roo.id();
39765 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39768 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39771 displayField : false,
39775 defaultAutoCreate : {
39777 cls: 'x-cbarray-item',
39784 src : Roo.BLANK_IMAGE_URL ,
39792 onRender : function(ct, position)
39794 Roo.form.Field.superclass.onRender.call(this, ct, position);
39797 var cfg = this.getAutoCreate();
39798 this.el = ct.createChild(cfg, position);
39801 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39803 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39804 this.cb.renderer(this.data) :
39805 String.format('{0}',this.data[this.displayField]);
39808 this.el.child('div').dom.setAttribute('qtip',
39809 String.format('{0}',this.data[this.tipField])
39812 this.el.child('img').on('click', this.remove, this);
39816 remove : function()
39819 this.cb.items.remove(this);
39820 this.el.child('img').un('click', this.remove, this);
39822 this.cb.updateHiddenEl();
39828 * Ext JS Library 1.1.1
39829 * Copyright(c) 2006-2007, Ext JS, LLC.
39831 * Originally Released Under LGPL - original licence link has changed is not relivant.
39834 * <script type="text/javascript">
39837 * @class Roo.form.Checkbox
39838 * @extends Roo.form.Field
39839 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
39841 * Creates a new Checkbox
39842 * @param {Object} config Configuration options
39844 Roo.form.Checkbox = function(config){
39845 Roo.form.Checkbox.superclass.constructor.call(this, config);
39849 * Fires when the checkbox is checked or unchecked.
39850 * @param {Roo.form.Checkbox} this This checkbox
39851 * @param {Boolean} checked The new checked value
39857 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
39859 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
39861 focusClass : undefined,
39863 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
39865 fieldClass: "x-form-field",
39867 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
39871 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39872 * {tag: "input", type: "checkbox", autocomplete: "off"})
39874 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
39876 * @cfg {String} boxLabel The text that appears beside the checkbox
39880 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
39884 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
39886 valueOff: '0', // value when not checked..
39888 actionMode : 'viewEl',
39891 itemCls : 'x-menu-check-item x-form-item',
39892 groupClass : 'x-menu-group-item',
39893 inputType : 'hidden',
39896 inSetChecked: false, // check that we are not calling self...
39898 inputElement: false, // real input element?
39899 basedOn: false, // ????
39901 isFormField: true, // not sure where this is needed!!!!
39903 onResize : function(){
39904 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
39905 if(!this.boxLabel){
39906 this.el.alignTo(this.wrap, 'c-c');
39910 initEvents : function(){
39911 Roo.form.Checkbox.superclass.initEvents.call(this);
39912 this.el.on("click", this.onClick, this);
39913 this.el.on("change", this.onClick, this);
39917 getResizeEl : function(){
39921 getPositionEl : function(){
39926 onRender : function(ct, position){
39927 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
39929 if(this.inputValue !== undefined){
39930 this.el.dom.value = this.inputValue;
39933 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
39934 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
39935 var viewEl = this.wrap.createChild({
39936 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
39937 this.viewEl = viewEl;
39938 this.wrap.on('click', this.onClick, this);
39940 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
39941 this.el.on('propertychange', this.setFromHidden, this); //ie
39946 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
39947 // viewEl.on('click', this.onClick, this);
39949 //if(this.checked){
39950 this.setChecked(this.checked);
39952 //this.checked = this.el.dom;
39958 initValue : Roo.emptyFn,
39961 * Returns the checked state of the checkbox.
39962 * @return {Boolean} True if checked, else false
39964 getValue : function(){
39966 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
39968 return this.valueOff;
39973 onClick : function(){
39974 this.setChecked(!this.checked);
39976 //if(this.el.dom.checked != this.checked){
39977 // this.setValue(this.el.dom.checked);
39982 * Sets the checked state of the checkbox.
39983 * On is always based on a string comparison between inputValue and the param.
39984 * @param {Boolean/String} value - the value to set
39985 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
39987 setValue : function(v,suppressEvent){
39990 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
39991 //if(this.el && this.el.dom){
39992 // this.el.dom.checked = this.checked;
39993 // this.el.dom.defaultChecked = this.checked;
39995 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
39996 //this.fireEvent("check", this, this.checked);
39999 setChecked : function(state,suppressEvent)
40001 if (this.inSetChecked) {
40002 this.checked = state;
40008 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40010 this.checked = state;
40011 if(suppressEvent !== true){
40012 this.fireEvent('check', this, state);
40014 this.inSetChecked = true;
40015 this.el.dom.value = state ? this.inputValue : this.valueOff;
40016 this.inSetChecked = false;
40019 // handle setting of hidden value by some other method!!?!?
40020 setFromHidden: function()
40025 //console.log("SET FROM HIDDEN");
40026 //alert('setFrom hidden');
40027 this.setValue(this.el.dom.value);
40030 onDestroy : function()
40033 Roo.get(this.viewEl).remove();
40036 Roo.form.Checkbox.superclass.onDestroy.call(this);
40041 * Ext JS Library 1.1.1
40042 * Copyright(c) 2006-2007, Ext JS, LLC.
40044 * Originally Released Under LGPL - original licence link has changed is not relivant.
40047 * <script type="text/javascript">
40051 * @class Roo.form.Radio
40052 * @extends Roo.form.Checkbox
40053 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40054 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40056 * Creates a new Radio
40057 * @param {Object} config Configuration options
40059 Roo.form.Radio = function(){
40060 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40062 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40063 inputType: 'radio',
40066 * If this radio is part of a group, it will return the selected value
40069 getGroupValue : function(){
40070 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40072 });//<script type="text/javascript">
40075 * Ext JS Library 1.1.1
40076 * Copyright(c) 2006-2007, Ext JS, LLC.
40077 * licensing@extjs.com
40079 * http://www.extjs.com/license
40085 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40086 * - IE ? - no idea how much works there.
40094 * @class Ext.form.HtmlEditor
40095 * @extends Ext.form.Field
40096 * Provides a lightweight HTML Editor component.
40098 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40100 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40101 * supported by this editor.</b><br/><br/>
40102 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40103 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40105 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40107 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40111 * @cfg {String} createLinkText The default text for the create link prompt
40113 createLinkText : 'Please enter the URL for the link:',
40115 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40117 defaultLinkValue : 'http:/'+'/',
40120 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40125 * @cfg {Number} height (in pixels)
40129 * @cfg {Number} width (in pixels)
40134 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40137 stylesheets: false,
40142 // private properties
40143 validationEvent : false,
40145 initialized : false,
40147 sourceEditMode : false,
40148 onFocus : Roo.emptyFn,
40150 hideMode:'offsets',
40152 defaultAutoCreate : { // modified by initCompnoent..
40154 style:"width:500px;height:300px;",
40155 autocomplete: "off"
40159 initComponent : function(){
40162 * @event initialize
40163 * Fires when the editor is fully initialized (including the iframe)
40164 * @param {HtmlEditor} this
40169 * Fires when the editor is first receives the focus. Any insertion must wait
40170 * until after this event.
40171 * @param {HtmlEditor} this
40175 * @event beforesync
40176 * Fires before the textarea is updated with content from the editor iframe. Return false
40177 * to cancel the sync.
40178 * @param {HtmlEditor} this
40179 * @param {String} html
40183 * @event beforepush
40184 * Fires before the iframe editor is updated with content from the textarea. Return false
40185 * to cancel the push.
40186 * @param {HtmlEditor} this
40187 * @param {String} html
40192 * Fires when the textarea is updated with content from the editor iframe.
40193 * @param {HtmlEditor} this
40194 * @param {String} html
40199 * Fires when the iframe editor is updated with content from the textarea.
40200 * @param {HtmlEditor} this
40201 * @param {String} html
40205 * @event editmodechange
40206 * Fires when the editor switches edit modes
40207 * @param {HtmlEditor} this
40208 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40210 editmodechange: true,
40212 * @event editorevent
40213 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40214 * @param {HtmlEditor} this
40218 this.defaultAutoCreate = {
40220 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40221 autocomplete: "off"
40226 * Protected method that will not generally be called directly. It
40227 * is called when the editor creates its toolbar. Override this method if you need to
40228 * add custom toolbar buttons.
40229 * @param {HtmlEditor} editor
40231 createToolbar : function(editor){
40232 if (!editor.toolbars || !editor.toolbars.length) {
40233 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40236 for (var i =0 ; i < editor.toolbars.length;i++) {
40237 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
40238 editor.toolbars[i].init(editor);
40245 * Protected method that will not generally be called directly. It
40246 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40247 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40249 getDocMarkup : function(){
40252 if (this.stylesheets === false) {
40254 Roo.get(document.head).select('style').each(function(node) {
40255 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40258 Roo.get(document.head).select('link').each(function(node) {
40259 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40262 } else if (!this.stylesheets.length) {
40264 st = '<style type="text/css">' +
40265 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40268 Roo.each(this.stylesheets, function(s) {
40269 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40274 st += '<style type="text/css">' +
40275 'IMG { cursor: pointer } ' +
40279 return '<html><head>' + st +
40280 //<style type="text/css">' +
40281 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40283 ' </head><body class="roo-htmleditor-body"></body></html>';
40287 onRender : function(ct, position)
40290 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40291 this.el.dom.style.border = '0 none';
40292 this.el.dom.setAttribute('tabIndex', -1);
40293 this.el.addClass('x-hidden');
40294 if(Roo.isIE){ // fix IE 1px bogus margin
40295 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40297 this.wrap = this.el.wrap({
40298 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40301 if (this.resizable) {
40302 this.resizeEl = new Roo.Resizable(this.wrap, {
40306 minHeight : this.height,
40307 height: this.height,
40308 handles : this.resizable,
40311 resize : function(r, w, h) {
40312 _t.onResize(w,h); // -something
40319 this.frameId = Roo.id();
40321 this.createToolbar(this);
40325 var iframe = this.wrap.createChild({
40328 name: this.frameId,
40329 frameBorder : 'no',
40330 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
40334 // console.log(iframe);
40335 //this.wrap.dom.appendChild(iframe);
40337 this.iframe = iframe.dom;
40339 this.assignDocWin();
40341 this.doc.designMode = 'on';
40344 this.doc.write(this.getDocMarkup());
40348 var task = { // must defer to wait for browser to be ready
40350 //console.log("run task?" + this.doc.readyState);
40351 this.assignDocWin();
40352 if(this.doc.body || this.doc.readyState == 'complete'){
40354 this.doc.designMode="on";
40358 Roo.TaskMgr.stop(task);
40359 this.initEditor.defer(10, this);
40366 Roo.TaskMgr.start(task);
40369 this.setSize(this.wrap.getSize());
40371 if (this.resizeEl) {
40372 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
40373 // should trigger onReize..
40378 onResize : function(w, h)
40380 //Roo.log('resize: ' +w + ',' + h );
40381 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
40382 if(this.el && this.iframe){
40383 if(typeof w == 'number'){
40384 var aw = w - this.wrap.getFrameWidth('lr');
40385 this.el.setWidth(this.adjustWidth('textarea', aw));
40386 this.iframe.style.width = aw + 'px';
40388 if(typeof h == 'number'){
40390 for (var i =0; i < this.toolbars.length;i++) {
40391 // fixme - ask toolbars for heights?
40392 tbh += this.toolbars[i].tb.el.getHeight();
40393 if (this.toolbars[i].footer) {
40394 tbh += this.toolbars[i].footer.el.getHeight();
40401 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
40402 ah -= 5; // knock a few pixes off for look..
40403 this.el.setHeight(this.adjustWidth('textarea', ah));
40404 this.iframe.style.height = ah + 'px';
40406 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
40413 * Toggles the editor between standard and source edit mode.
40414 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
40416 toggleSourceEdit : function(sourceEditMode){
40418 this.sourceEditMode = sourceEditMode === true;
40420 if(this.sourceEditMode){
40423 this.iframe.className = 'x-hidden';
40424 this.el.removeClass('x-hidden');
40425 this.el.dom.removeAttribute('tabIndex');
40430 this.iframe.className = '';
40431 this.el.addClass('x-hidden');
40432 this.el.dom.setAttribute('tabIndex', -1);
40435 this.setSize(this.wrap.getSize());
40436 this.fireEvent('editmodechange', this, this.sourceEditMode);
40439 // private used internally
40440 createLink : function(){
40441 var url = prompt(this.createLinkText, this.defaultLinkValue);
40442 if(url && url != 'http:/'+'/'){
40443 this.relayCmd('createlink', url);
40447 // private (for BoxComponent)
40448 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40450 // private (for BoxComponent)
40451 getResizeEl : function(){
40455 // private (for BoxComponent)
40456 getPositionEl : function(){
40461 initEvents : function(){
40462 this.originalValue = this.getValue();
40466 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40469 markInvalid : Roo.emptyFn,
40471 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40474 clearInvalid : Roo.emptyFn,
40476 setValue : function(v){
40477 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40482 * Protected method that will not generally be called directly. If you need/want
40483 * custom HTML cleanup, this is the method you should override.
40484 * @param {String} html The HTML to be cleaned
40485 * return {String} The cleaned HTML
40487 cleanHtml : function(html){
40488 html = String(html);
40489 if(html.length > 5){
40490 if(Roo.isSafari){ // strip safari nonsense
40491 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40494 if(html == ' '){
40501 * Protected method that will not generally be called directly. Syncs the contents
40502 * of the editor iframe with the textarea.
40504 syncValue : function(){
40505 if(this.initialized){
40506 var bd = (this.doc.body || this.doc.documentElement);
40507 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40508 var html = bd.innerHTML;
40510 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40511 var m = bs.match(/text-align:(.*?);/i);
40513 html = '<div style="'+m[0]+'">' + html + '</div>';
40516 html = this.cleanHtml(html);
40517 // fix up the special chars..
40518 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40519 return "&#"+b.charCodeAt()+";"
40521 if(this.fireEvent('beforesync', this, html) !== false){
40522 this.el.dom.value = html;
40523 this.fireEvent('sync', this, html);
40529 * Protected method that will not generally be called directly. Pushes the value of the textarea
40530 * into the iframe editor.
40532 pushValue : function(){
40533 if(this.initialized){
40534 var v = this.el.dom.value;
40539 if(this.fireEvent('beforepush', this, v) !== false){
40540 var d = (this.doc.body || this.doc.documentElement);
40542 this.cleanUpPaste();
40543 this.el.dom.value = d.innerHTML;
40544 this.fireEvent('push', this, v);
40550 deferFocus : function(){
40551 this.focus.defer(10, this);
40555 focus : function(){
40556 if(this.win && !this.sourceEditMode){
40563 assignDocWin: function()
40565 var iframe = this.iframe;
40568 this.doc = iframe.contentWindow.document;
40569 this.win = iframe.contentWindow;
40571 if (!Roo.get(this.frameId)) {
40574 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40575 this.win = Roo.get(this.frameId).dom.contentWindow;
40580 initEditor : function(){
40581 //console.log("INIT EDITOR");
40582 this.assignDocWin();
40586 this.doc.designMode="on";
40588 this.doc.write(this.getDocMarkup());
40591 var dbody = (this.doc.body || this.doc.documentElement);
40592 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40593 // this copies styles from the containing element into thsi one..
40594 // not sure why we need all of this..
40595 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40596 ss['background-attachment'] = 'fixed'; // w3c
40597 dbody.bgProperties = 'fixed'; // ie
40598 Roo.DomHelper.applyStyles(dbody, ss);
40599 Roo.EventManager.on(this.doc, {
40600 //'mousedown': this.onEditorEvent,
40601 'mouseup': this.onEditorEvent,
40602 'dblclick': this.onEditorEvent,
40603 'click': this.onEditorEvent,
40604 'keyup': this.onEditorEvent,
40609 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40611 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40612 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40614 this.initialized = true;
40616 this.fireEvent('initialize', this);
40621 onDestroy : function(){
40627 for (var i =0; i < this.toolbars.length;i++) {
40628 // fixme - ask toolbars for heights?
40629 this.toolbars[i].onDestroy();
40632 this.wrap.dom.innerHTML = '';
40633 this.wrap.remove();
40638 onFirstFocus : function(){
40640 this.assignDocWin();
40643 this.activated = true;
40644 for (var i =0; i < this.toolbars.length;i++) {
40645 this.toolbars[i].onFirstFocus();
40648 if(Roo.isGecko){ // prevent silly gecko errors
40650 var s = this.win.getSelection();
40651 if(!s.focusNode || s.focusNode.nodeType != 3){
40652 var r = s.getRangeAt(0);
40653 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40658 this.execCmd('useCSS', true);
40659 this.execCmd('styleWithCSS', false);
40662 this.fireEvent('activate', this);
40666 adjustFont: function(btn){
40667 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40668 //if(Roo.isSafari){ // safari
40671 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40672 if(Roo.isSafari){ // safari
40673 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40674 v = (v < 10) ? 10 : v;
40675 v = (v > 48) ? 48 : v;
40676 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40681 v = Math.max(1, v+adjust);
40683 this.execCmd('FontSize', v );
40686 onEditorEvent : function(e){
40687 this.fireEvent('editorevent', this, e);
40688 // this.updateToolbar();
40689 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40692 insertTag : function(tg)
40694 // could be a bit smarter... -> wrap the current selected tRoo..
40696 this.execCmd("formatblock", tg);
40700 insertText : function(txt)
40704 range = this.createRange();
40705 range.deleteContents();
40706 //alert(Sender.getAttribute('label'));
40708 range.insertNode(this.doc.createTextNode(txt));
40712 relayBtnCmd : function(btn){
40713 this.relayCmd(btn.cmd);
40717 * Executes a Midas editor command on the editor document and performs necessary focus and
40718 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40719 * @param {String} cmd The Midas command
40720 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40722 relayCmd : function(cmd, value){
40724 this.execCmd(cmd, value);
40725 this.fireEvent('editorevent', this);
40726 //this.updateToolbar();
40731 * Executes a Midas editor command directly on the editor document.
40732 * For visual commands, you should use {@link #relayCmd} instead.
40733 * <b>This should only be called after the editor is initialized.</b>
40734 * @param {String} cmd The Midas command
40735 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40737 execCmd : function(cmd, value){
40738 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40745 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40747 * @param {String} text | dom node..
40749 insertAtCursor : function(text)
40754 if(!this.activated){
40760 var r = this.doc.selection.createRange();
40771 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40775 // from jquery ui (MIT licenced)
40777 var win = this.win;
40779 if (win.getSelection && win.getSelection().getRangeAt) {
40780 range = win.getSelection().getRangeAt(0);
40781 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
40782 range.insertNode(node);
40783 } else if (win.document.selection && win.document.selection.createRange) {
40784 // no firefox support
40785 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40786 win.document.selection.createRange().pasteHTML(txt);
40788 // no firefox support
40789 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40790 this.execCmd('InsertHTML', txt);
40799 mozKeyPress : function(e){
40801 var c = e.getCharCode(), cmd;
40804 c = String.fromCharCode(c).toLowerCase();
40818 this.cleanUpPaste.defer(100, this);
40826 e.preventDefault();
40834 fixKeys : function(){ // load time branching for fastest keydown performance
40836 return function(e){
40837 var k = e.getKey(), r;
40840 r = this.doc.selection.createRange();
40843 r.pasteHTML('    ');
40850 r = this.doc.selection.createRange();
40852 var target = r.parentElement();
40853 if(!target || target.tagName.toLowerCase() != 'li'){
40855 r.pasteHTML('<br />');
40861 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40862 this.cleanUpPaste.defer(100, this);
40868 }else if(Roo.isOpera){
40869 return function(e){
40870 var k = e.getKey();
40874 this.execCmd('InsertHTML','    ');
40877 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40878 this.cleanUpPaste.defer(100, this);
40883 }else if(Roo.isSafari){
40884 return function(e){
40885 var k = e.getKey();
40889 this.execCmd('InsertText','\t');
40893 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40894 this.cleanUpPaste.defer(100, this);
40902 getAllAncestors: function()
40904 var p = this.getSelectedNode();
40907 a.push(p); // push blank onto stack..
40908 p = this.getParentElement();
40912 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
40916 a.push(this.doc.body);
40920 lastSelNode : false,
40923 getSelection : function()
40925 this.assignDocWin();
40926 return Roo.isIE ? this.doc.selection : this.win.getSelection();
40929 getSelectedNode: function()
40931 // this may only work on Gecko!!!
40933 // should we cache this!!!!
40938 var range = this.createRange(this.getSelection()).cloneRange();
40941 var parent = range.parentElement();
40943 var testRange = range.duplicate();
40944 testRange.moveToElementText(parent);
40945 if (testRange.inRange(range)) {
40948 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
40951 parent = parent.parentElement;
40956 // is ancestor a text element.
40957 var ac = range.commonAncestorContainer;
40958 if (ac.nodeType == 3) {
40959 ac = ac.parentNode;
40962 var ar = ac.childNodes;
40965 var other_nodes = [];
40966 var has_other_nodes = false;
40967 for (var i=0;i<ar.length;i++) {
40968 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
40971 // fullly contained node.
40973 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
40978 // probably selected..
40979 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
40980 other_nodes.push(ar[i]);
40984 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
40989 has_other_nodes = true;
40991 if (!nodes.length && other_nodes.length) {
40992 nodes= other_nodes;
40994 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41000 createRange: function(sel)
41002 // this has strange effects when using with
41003 // top toolbar - not sure if it's a great idea.
41004 //this.editor.contentWindow.focus();
41005 if (typeof sel != "undefined") {
41007 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41009 return this.doc.createRange();
41012 return this.doc.createRange();
41015 getParentElement: function()
41018 this.assignDocWin();
41019 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41021 var range = this.createRange(sel);
41024 var p = range.commonAncestorContainer;
41025 while (p.nodeType == 3) { // text node
41036 * Range intersection.. the hard stuff...
41040 * [ -- selected range --- ]
41044 * if end is before start or hits it. fail.
41045 * if start is after end or hits it fail.
41047 * if either hits (but other is outside. - then it's not
41053 // @see http://www.thismuchiknow.co.uk/?p=64.
41054 rangeIntersectsNode : function(range, node)
41056 var nodeRange = node.ownerDocument.createRange();
41058 nodeRange.selectNode(node);
41060 nodeRange.selectNodeContents(node);
41063 var rangeStartRange = range.cloneRange();
41064 rangeStartRange.collapse(true);
41066 var rangeEndRange = range.cloneRange();
41067 rangeEndRange.collapse(false);
41069 var nodeStartRange = nodeRange.cloneRange();
41070 nodeStartRange.collapse(true);
41072 var nodeEndRange = nodeRange.cloneRange();
41073 nodeEndRange.collapse(false);
41075 return rangeStartRange.compareBoundaryPoints(
41076 Range.START_TO_START, nodeEndRange) == -1 &&
41077 rangeEndRange.compareBoundaryPoints(
41078 Range.START_TO_START, nodeStartRange) == 1;
41082 rangeCompareNode : function(range, node)
41084 var nodeRange = node.ownerDocument.createRange();
41086 nodeRange.selectNode(node);
41088 nodeRange.selectNodeContents(node);
41092 range.collapse(true);
41094 nodeRange.collapse(true);
41096 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41097 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41099 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41101 var nodeIsBefore = ss == 1;
41102 var nodeIsAfter = ee == -1;
41104 if (nodeIsBefore && nodeIsAfter)
41106 if (!nodeIsBefore && nodeIsAfter)
41107 return 1; //right trailed.
41109 if (nodeIsBefore && !nodeIsAfter)
41110 return 2; // left trailed.
41115 // private? - in a new class?
41116 cleanUpPaste : function()
41118 // cleans up the whole document..
41119 Roo.log('cleanuppaste');
41120 this.cleanUpChildren(this.doc.body);
41121 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41122 if (clean != this.doc.body.innerHTML) {
41123 this.doc.body.innerHTML = clean;
41128 cleanWordChars : function(input) {
41129 var he = Roo.form.HtmlEditor;
41131 var output = input;
41132 Roo.each(he.swapCodes, function(sw) {
41134 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41135 output = output.replace(swapper, sw[1]);
41141 cleanUpChildren : function (n)
41143 if (!n.childNodes.length) {
41146 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41147 this.cleanUpChild(n.childNodes[i]);
41154 cleanUpChild : function (node)
41156 //console.log(node);
41157 if (node.nodeName == "#text") {
41158 // clean up silly Windows -- stuff?
41161 if (node.nodeName == "#comment") {
41162 node.parentNode.removeChild(node);
41163 // clean up silly Windows -- stuff?
41167 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41169 node.parentNode.removeChild(node);
41174 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41176 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41177 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41179 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41180 // remove_keep_children = true;
41183 if (remove_keep_children) {
41184 this.cleanUpChildren(node);
41185 // inserts everything just before this node...
41186 while (node.childNodes.length) {
41187 var cn = node.childNodes[0];
41188 node.removeChild(cn);
41189 node.parentNode.insertBefore(cn, node);
41191 node.parentNode.removeChild(node);
41195 if (!node.attributes || !node.attributes.length) {
41196 this.cleanUpChildren(node);
41200 function cleanAttr(n,v)
41203 if (v.match(/^\./) || v.match(/^\//)) {
41206 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41209 if (v.match(/^#/)) {
41212 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
41213 node.removeAttribute(n);
41217 function cleanStyle(n,v)
41219 if (v.match(/expression/)) { //XSS?? should we even bother..
41220 node.removeAttribute(n);
41225 var parts = v.split(/;/);
41226 Roo.each(parts, function(p) {
41227 p = p.replace(/\s+/g,'');
41231 var l = p.split(':').shift().replace(/\s+/g,'');
41233 // only allow 'c whitelisted system attributes'
41234 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
41235 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
41236 node.removeAttribute(n);
41246 for (var i = node.attributes.length-1; i > -1 ; i--) {
41247 var a = node.attributes[i];
41249 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41250 node.removeAttribute(a.name);
41253 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41254 cleanAttr(a.name,a.value); // fixme..
41257 if (a.name == 'style') {
41258 cleanStyle(a.name,a.value);
41261 /// clean up MS crap..
41262 // tecnically this should be a list of valid class'es..
41265 if (a.name == 'class') {
41266 if (a.value.match(/^Mso/)) {
41267 node.className = '';
41270 if (a.value.match(/body/)) {
41271 node.className = '';
41282 this.cleanUpChildren(node);
41288 // hide stuff that is not compatible
41302 * @event specialkey
41306 * @cfg {String} fieldClass @hide
41309 * @cfg {String} focusClass @hide
41312 * @cfg {String} autoCreate @hide
41315 * @cfg {String} inputType @hide
41318 * @cfg {String} invalidClass @hide
41321 * @cfg {String} invalidText @hide
41324 * @cfg {String} msgFx @hide
41327 * @cfg {String} validateOnBlur @hide
41331 Roo.form.HtmlEditor.white = [
41332 'area', 'br', 'img', 'input', 'hr', 'wbr',
41334 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
41335 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
41336 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
41337 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
41338 'table', 'ul', 'xmp',
41340 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
41343 'dir', 'menu', 'ol', 'ul', 'dl',
41349 Roo.form.HtmlEditor.black = [
41350 // 'embed', 'object', // enable - backend responsiblity to clean thiese
41352 'base', 'basefont', 'bgsound', 'blink', 'body',
41353 'frame', 'frameset', 'head', 'html', 'ilayer',
41354 'iframe', 'layer', 'link', 'meta', 'object',
41355 'script', 'style' ,'title', 'xml' // clean later..
41357 Roo.form.HtmlEditor.clean = [
41358 'script', 'style', 'title', 'xml'
41360 Roo.form.HtmlEditor.remove = [
41365 Roo.form.HtmlEditor.ablack = [
41369 Roo.form.HtmlEditor.aclean = [
41370 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
41374 Roo.form.HtmlEditor.pwhite= [
41375 'http', 'https', 'mailto'
41378 // white listed style attributes.
41379 Roo.form.HtmlEditor.cwhite= [
41385 Roo.form.HtmlEditor.swapCodes =[
41396 // <script type="text/javascript">
41399 * Ext JS Library 1.1.1
41400 * Copyright(c) 2006-2007, Ext JS, LLC.
41406 * @class Roo.form.HtmlEditorToolbar1
41411 new Roo.form.HtmlEditor({
41414 new Roo.form.HtmlEditorToolbar1({
41415 disable : { fonts: 1 , format: 1, ..., ... , ...],
41421 * @cfg {Object} disable List of elements to disable..
41422 * @cfg {Array} btns List of additional buttons.
41426 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
41429 Roo.form.HtmlEditor.ToolbarStandard = function(config)
41432 Roo.apply(this, config);
41434 // default disabled, based on 'good practice'..
41435 this.disable = this.disable || {};
41436 Roo.applyIf(this.disable, {
41439 specialElements : true
41443 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41444 // dont call parent... till later.
41447 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41455 * @cfg {Object} disable List of toolbar elements to disable
41460 * @cfg {Array} fontFamilies An array of available font families
41478 // "á" , ?? a acute?
41483 "°" // , // degrees
41485 // "é" , // e ecute
41486 // "ú" , // u ecute?
41489 specialElements : [
41491 text: "Insert Table",
41494 ihtml : '<table><tr><td>Cell</td></tr></table>'
41498 text: "Insert Image",
41501 ihtml : '<img src="about:blank"/>'
41510 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41511 "input:submit", "input:button", "select", "textarea", "label" ],
41514 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41516 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
41519 * @cfg {String} defaultFont default font to use.
41521 defaultFont: 'tahoma',
41523 fontSelect : false,
41526 formatCombo : false,
41528 init : function(editor)
41530 this.editor = editor;
41533 var fid = editor.frameId;
41535 function btn(id, toggle, handler){
41536 var xid = fid + '-'+ id ;
41540 cls : 'x-btn-icon x-edit-'+id,
41541 enableToggle:toggle !== false,
41542 scope: editor, // was editor...
41543 handler:handler||editor.relayBtnCmd,
41544 clickEvent:'mousedown',
41545 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41552 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41554 // stop form submits
41555 tb.el.on('click', function(e){
41556 e.preventDefault(); // what does this do?
41559 if(!this.disable.font && !Roo.isSafari){
41560 /* why no safari for fonts
41561 editor.fontSelect = tb.el.createChild({
41564 cls:'x-font-select',
41565 html: editor.createFontOptions()
41567 editor.fontSelect.on('change', function(){
41568 var font = editor.fontSelect.dom.value;
41569 editor.relayCmd('fontname', font);
41570 editor.deferFocus();
41573 editor.fontSelect.dom,
41578 if(!this.disable.formats){
41579 this.formatCombo = new Roo.form.ComboBox({
41580 store: new Roo.data.SimpleStore({
41583 data : this.formats // from states.js
41586 //autoCreate : {tag: "div", size: "20"},
41587 displayField:'tag',
41591 triggerAction: 'all',
41592 emptyText:'Add tag',
41593 selectOnFocus:true,
41596 'select': function(c, r, i) {
41597 editor.insertTag(r.get('tag'));
41603 tb.addField(this.formatCombo);
41607 if(!this.disable.format){
41614 if(!this.disable.fontSize){
41619 btn('increasefontsize', false, editor.adjustFont),
41620 btn('decreasefontsize', false, editor.adjustFont)
41625 if(!this.disable.colors){
41628 id:editor.frameId +'-forecolor',
41629 cls:'x-btn-icon x-edit-forecolor',
41630 clickEvent:'mousedown',
41631 tooltip: this.buttonTips['forecolor'] || undefined,
41633 menu : new Roo.menu.ColorMenu({
41634 allowReselect: true,
41635 focus: Roo.emptyFn,
41638 selectHandler: function(cp, color){
41639 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41640 editor.deferFocus();
41643 clickEvent:'mousedown'
41646 id:editor.frameId +'backcolor',
41647 cls:'x-btn-icon x-edit-backcolor',
41648 clickEvent:'mousedown',
41649 tooltip: this.buttonTips['backcolor'] || undefined,
41651 menu : new Roo.menu.ColorMenu({
41652 focus: Roo.emptyFn,
41655 allowReselect: true,
41656 selectHandler: function(cp, color){
41658 editor.execCmd('useCSS', false);
41659 editor.execCmd('hilitecolor', color);
41660 editor.execCmd('useCSS', true);
41661 editor.deferFocus();
41663 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41664 Roo.isSafari || Roo.isIE ? '#'+color : color);
41665 editor.deferFocus();
41669 clickEvent:'mousedown'
41674 // now add all the items...
41677 if(!this.disable.alignments){
41680 btn('justifyleft'),
41681 btn('justifycenter'),
41682 btn('justifyright')
41686 //if(!Roo.isSafari){
41687 if(!this.disable.links){
41690 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41694 if(!this.disable.lists){
41697 btn('insertorderedlist'),
41698 btn('insertunorderedlist')
41701 if(!this.disable.sourceEdit){
41704 btn('sourceedit', true, function(btn){
41705 this.toggleSourceEdit(btn.pressed);
41712 // special menu.. - needs to be tidied up..
41713 if (!this.disable.special) {
41716 cls: 'x-edit-none',
41722 for (var i =0; i < this.specialChars.length; i++) {
41723 smenu.menu.items.push({
41725 html: this.specialChars[i],
41726 handler: function(a,b) {
41727 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41728 //editor.insertAtCursor(a.html);
41741 if (!this.disable.specialElements) {
41744 cls: 'x-edit-none',
41749 for (var i =0; i < this.specialElements.length; i++) {
41750 semenu.menu.items.push(
41752 handler: function(a,b) {
41753 editor.insertAtCursor(this.ihtml);
41755 }, this.specialElements[i])
41767 for(var i =0; i< this.btns.length;i++) {
41768 var b = Roo.factory(this.btns[i],Roo.form);
41769 b.cls = 'x-edit-none';
41778 // disable everything...
41780 this.tb.items.each(function(item){
41781 if(item.id != editor.frameId+ '-sourceedit'){
41785 this.rendered = true;
41787 // the all the btns;
41788 editor.on('editorevent', this.updateToolbar, this);
41789 // other toolbars need to implement this..
41790 //editor.on('editmodechange', this.updateToolbar, this);
41796 * Protected method that will not generally be called directly. It triggers
41797 * a toolbar update by reading the markup state of the current selection in the editor.
41799 updateToolbar: function(){
41801 if(!this.editor.activated){
41802 this.editor.onFirstFocus();
41806 var btns = this.tb.items.map,
41807 doc = this.editor.doc,
41808 frameId = this.editor.frameId;
41810 if(!this.disable.font && !Roo.isSafari){
41812 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
41813 if(name != this.fontSelect.dom.value){
41814 this.fontSelect.dom.value = name;
41818 if(!this.disable.format){
41819 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
41820 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
41821 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
41823 if(!this.disable.alignments){
41824 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
41825 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
41826 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
41828 if(!Roo.isSafari && !this.disable.lists){
41829 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
41830 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
41833 var ans = this.editor.getAllAncestors();
41834 if (this.formatCombo) {
41837 var store = this.formatCombo.store;
41838 this.formatCombo.setValue("");
41839 for (var i =0; i < ans.length;i++) {
41840 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
41842 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
41850 // hides menus... - so this cant be on a menu...
41851 Roo.menu.MenuMgr.hideAll();
41853 //this.editorsyncValue();
41857 createFontOptions : function(){
41858 var buf = [], fs = this.fontFamilies, ff, lc;
41859 for(var i = 0, len = fs.length; i< len; i++){
41861 lc = ff.toLowerCase();
41863 '<option value="',lc,'" style="font-family:',ff,';"',
41864 (this.defaultFont == lc ? ' selected="true">' : '>'),
41869 return buf.join('');
41872 toggleSourceEdit : function(sourceEditMode){
41873 if(sourceEditMode === undefined){
41874 sourceEditMode = !this.sourceEditMode;
41876 this.sourceEditMode = sourceEditMode === true;
41877 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
41878 // just toggle the button?
41879 if(btn.pressed !== this.editor.sourceEditMode){
41880 btn.toggle(this.editor.sourceEditMode);
41884 if(this.sourceEditMode){
41885 this.tb.items.each(function(item){
41886 if(item.cmd != 'sourceedit'){
41892 if(this.initialized){
41893 this.tb.items.each(function(item){
41899 // tell the editor that it's been pressed..
41900 this.editor.toggleSourceEdit(sourceEditMode);
41904 * Object collection of toolbar tooltips for the buttons in the editor. The key
41905 * is the command id associated with that button and the value is a valid QuickTips object.
41910 title: 'Bold (Ctrl+B)',
41911 text: 'Make the selected text bold.',
41912 cls: 'x-html-editor-tip'
41915 title: 'Italic (Ctrl+I)',
41916 text: 'Make the selected text italic.',
41917 cls: 'x-html-editor-tip'
41925 title: 'Bold (Ctrl+B)',
41926 text: 'Make the selected text bold.',
41927 cls: 'x-html-editor-tip'
41930 title: 'Italic (Ctrl+I)',
41931 text: 'Make the selected text italic.',
41932 cls: 'x-html-editor-tip'
41935 title: 'Underline (Ctrl+U)',
41936 text: 'Underline the selected text.',
41937 cls: 'x-html-editor-tip'
41939 increasefontsize : {
41940 title: 'Grow Text',
41941 text: 'Increase the font size.',
41942 cls: 'x-html-editor-tip'
41944 decreasefontsize : {
41945 title: 'Shrink Text',
41946 text: 'Decrease the font size.',
41947 cls: 'x-html-editor-tip'
41950 title: 'Text Highlight Color',
41951 text: 'Change the background color of the selected text.',
41952 cls: 'x-html-editor-tip'
41955 title: 'Font Color',
41956 text: 'Change the color of the selected text.',
41957 cls: 'x-html-editor-tip'
41960 title: 'Align Text Left',
41961 text: 'Align text to the left.',
41962 cls: 'x-html-editor-tip'
41965 title: 'Center Text',
41966 text: 'Center text in the editor.',
41967 cls: 'x-html-editor-tip'
41970 title: 'Align Text Right',
41971 text: 'Align text to the right.',
41972 cls: 'x-html-editor-tip'
41974 insertunorderedlist : {
41975 title: 'Bullet List',
41976 text: 'Start a bulleted list.',
41977 cls: 'x-html-editor-tip'
41979 insertorderedlist : {
41980 title: 'Numbered List',
41981 text: 'Start a numbered list.',
41982 cls: 'x-html-editor-tip'
41985 title: 'Hyperlink',
41986 text: 'Make the selected text a hyperlink.',
41987 cls: 'x-html-editor-tip'
41990 title: 'Source Edit',
41991 text: 'Switch to source editing mode.',
41992 cls: 'x-html-editor-tip'
41996 onDestroy : function(){
41999 this.tb.items.each(function(item){
42001 item.menu.removeAll();
42003 item.menu.el.destroy();
42011 onFirstFocus: function() {
42012 this.tb.items.each(function(item){
42021 // <script type="text/javascript">
42024 * Ext JS Library 1.1.1
42025 * Copyright(c) 2006-2007, Ext JS, LLC.
42032 * @class Roo.form.HtmlEditor.ToolbarContext
42037 new Roo.form.HtmlEditor({
42040 { xtype: 'ToolbarStandard', styles : {} }
42041 { xtype: 'ToolbarContext', disable : {} }
42047 * @config : {Object} disable List of elements to disable.. (not done yet.)
42048 * @config : {Object} styles Map of styles available.
42052 Roo.form.HtmlEditor.ToolbarContext = function(config)
42055 Roo.apply(this, config);
42056 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42057 // dont call parent... till later.
42058 this.styles = this.styles || {};
42060 Roo.form.HtmlEditor.ToolbarContext.types = {
42072 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42134 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42139 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42193 // should we really allow this??
42194 // should this just be
42209 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42217 * @cfg {Object} disable List of toolbar elements to disable
42222 * @cfg {Object} styles List of styles
42223 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42225 * These must be defined in the page, so they get rendered correctly..
42236 init : function(editor)
42238 this.editor = editor;
42241 var fid = editor.frameId;
42243 function btn(id, toggle, handler){
42244 var xid = fid + '-'+ id ;
42248 cls : 'x-btn-icon x-edit-'+id,
42249 enableToggle:toggle !== false,
42250 scope: editor, // was editor...
42251 handler:handler||editor.relayBtnCmd,
42252 clickEvent:'mousedown',
42253 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42257 // create a new element.
42258 var wdiv = editor.wrap.createChild({
42260 }, editor.wrap.dom.firstChild.nextSibling, true);
42262 // can we do this more than once??
42264 // stop form submits
42267 // disable everything...
42268 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42269 this.toolbars = {};
42271 for (var i in ty) {
42273 this.toolbars[i] = this.buildToolbar(ty[i],i);
42275 this.tb = this.toolbars.BODY;
42277 this.buildFooter();
42278 this.footer.show();
42279 editor.on('hide', function( ) { this.footer.hide() }, this);
42280 editor.on('show', function( ) { this.footer.show() }, this);
42283 this.rendered = true;
42285 // the all the btns;
42286 editor.on('editorevent', this.updateToolbar, this);
42287 // other toolbars need to implement this..
42288 //editor.on('editmodechange', this.updateToolbar, this);
42294 * Protected method that will not generally be called directly. It triggers
42295 * a toolbar update by reading the markup state of the current selection in the editor.
42297 updateToolbar: function(editor,ev,sel){
42300 // capture mouse up - this is handy for selecting images..
42301 // perhaps should go somewhere else...
42302 if(!this.editor.activated){
42303 this.editor.onFirstFocus();
42307 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42308 // selectNode - might want to handle IE?
42310 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42311 ev.target && ev.target.tagName == 'IMG') {
42312 // they have click on an image...
42313 // let's see if we can change the selection...
42316 var nodeRange = sel.ownerDocument.createRange();
42318 nodeRange.selectNode(sel);
42320 nodeRange.selectNodeContents(sel);
42322 //nodeRange.collapse(true);
42323 var s = editor.win.getSelection();
42324 s.removeAllRanges();
42325 s.addRange(nodeRange);
42329 var updateFooter = sel ? false : true;
42332 var ans = this.editor.getAllAncestors();
42335 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42338 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42339 sel = sel ? sel : this.editor.doc.body;
42340 sel = sel.tagName.length ? sel : this.editor.doc.body;
42343 // pick a menu that exists..
42344 var tn = sel.tagName.toUpperCase();
42345 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42347 tn = sel.tagName.toUpperCase();
42349 var lastSel = this.tb.selectedNode
42351 this.tb.selectedNode = sel;
42353 // if current menu does not match..
42354 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42357 ///console.log("show: " + tn);
42358 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42361 this.tb.items.first().el.innerHTML = tn + ': ';
42364 // update attributes
42365 if (this.tb.fields) {
42366 this.tb.fields.each(function(e) {
42367 e.setValue(sel.getAttribute(e.attrname));
42371 var hasStyles = false;
42372 for(var i in this.styles) {
42379 var st = this.tb.fields.item(0);
42381 st.store.removeAll();
42384 var cn = sel.className.split(/\s+/);
42387 if (this.styles['*']) {
42389 Roo.each(this.styles['*'], function(v) {
42390 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42393 if (this.styles[tn]) {
42394 Roo.each(this.styles[tn], function(v) {
42395 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42399 st.store.loadData(avs);
42403 // flag our selected Node.
42404 this.tb.selectedNode = sel;
42407 Roo.menu.MenuMgr.hideAll();
42411 if (!updateFooter) {
42412 //this.footDisp.dom.innerHTML = '';
42415 // update the footer
42419 this.footerEls = ans.reverse();
42420 Roo.each(this.footerEls, function(a,i) {
42421 if (!a) { return; }
42422 html += html.length ? ' > ' : '';
42424 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42429 var sz = this.footDisp.up('td').getSize();
42430 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42431 this.footDisp.dom.style.marginLeft = '5px';
42433 this.footDisp.dom.style.overflow = 'hidden';
42435 this.footDisp.dom.innerHTML = html;
42437 //this.editorsyncValue();
42444 onDestroy : function(){
42447 this.tb.items.each(function(item){
42449 item.menu.removeAll();
42451 item.menu.el.destroy();
42459 onFirstFocus: function() {
42460 // need to do this for all the toolbars..
42461 this.tb.items.each(function(item){
42465 buildToolbar: function(tlist, nm)
42467 var editor = this.editor;
42468 // create a new element.
42469 var wdiv = editor.wrap.createChild({
42471 }, editor.wrap.dom.firstChild.nextSibling, true);
42474 var tb = new Roo.Toolbar(wdiv);
42477 tb.add(nm+ ": ");
42480 for(var i in this.styles) {
42485 if (styles && styles.length) {
42487 // this needs a multi-select checkbox...
42488 tb.addField( new Roo.form.ComboBox({
42489 store: new Roo.data.SimpleStore({
42491 fields: ['val', 'selected'],
42494 name : '-roo-edit-className',
42495 attrname : 'className',
42496 displayField:'val',
42500 triggerAction: 'all',
42501 emptyText:'Select Style',
42502 selectOnFocus:true,
42505 'select': function(c, r, i) {
42506 // initial support only for on class per el..
42507 tb.selectedNode.className = r ? r.get('val') : '';
42508 editor.syncValue();
42517 for (var i in tlist) {
42519 var item = tlist[i];
42520 tb.add(item.title + ": ");
42526 // opts == pulldown..
42527 tb.addField( new Roo.form.ComboBox({
42528 store: new Roo.data.SimpleStore({
42533 name : '-roo-edit-' + i,
42535 displayField:'val',
42539 triggerAction: 'all',
42540 emptyText:'Select',
42541 selectOnFocus:true,
42542 width: item.width ? item.width : 130,
42544 'select': function(c, r, i) {
42545 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42554 tb.addField( new Roo.form.TextField({
42557 //allowBlank:false,
42562 tb.addField( new Roo.form.TextField({
42563 name: '-roo-edit-' + i,
42570 'change' : function(f, nv, ov) {
42571 tb.selectedNode.setAttribute(f.attrname, nv);
42580 text: 'Remove Tag',
42583 click : function ()
42586 // undo does not work.
42588 var sn = tb.selectedNode;
42590 var pn = sn.parentNode;
42592 var stn = sn.childNodes[0];
42593 var en = sn.childNodes[sn.childNodes.length - 1 ];
42594 while (sn.childNodes.length) {
42595 var node = sn.childNodes[0];
42596 sn.removeChild(node);
42598 pn.insertBefore(node, sn);
42601 pn.removeChild(sn);
42602 var range = editor.createRange();
42604 range.setStart(stn,0);
42605 range.setEnd(en,0); //????
42606 //range.selectNode(sel);
42609 var selection = editor.getSelection();
42610 selection.removeAllRanges();
42611 selection.addRange(range);
42615 //_this.updateToolbar(null, null, pn);
42616 _this.updateToolbar(null, null, null);
42617 this.footDisp.dom.innerHTML = '';
42627 tb.el.on('click', function(e){
42628 e.preventDefault(); // what does this do?
42630 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42633 // dont need to disable them... as they will get hidden
42638 buildFooter : function()
42641 var fel = this.editor.wrap.createChild();
42642 this.footer = new Roo.Toolbar(fel);
42643 // toolbar has scrolly on left / right?
42644 var footDisp= new Roo.Toolbar.Fill();
42650 handler : function() {
42651 _t.footDisp.scrollTo('left',0,true)
42655 this.footer.add( footDisp );
42660 handler : function() {
42662 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42666 var fel = Roo.get(footDisp.el);
42667 fel.addClass('x-editor-context');
42668 this.footDispWrap = fel;
42669 this.footDispWrap.overflow = 'hidden';
42671 this.footDisp = fel.createChild();
42672 this.footDispWrap.on('click', this.onContextClick, this)
42676 onContextClick : function (ev,dom)
42678 ev.preventDefault();
42679 var cn = dom.className;
42681 if (!cn.match(/x-ed-loc-/)) {
42684 var n = cn.split('-').pop();
42685 var ans = this.footerEls;
42689 var range = this.editor.createRange();
42691 range.selectNodeContents(sel);
42692 //range.selectNode(sel);
42695 var selection = this.editor.getSelection();
42696 selection.removeAllRanges();
42697 selection.addRange(range);
42701 this.updateToolbar(null, null, sel);
42718 * Ext JS Library 1.1.1
42719 * Copyright(c) 2006-2007, Ext JS, LLC.
42721 * Originally Released Under LGPL - original licence link has changed is not relivant.
42724 * <script type="text/javascript">
42728 * @class Roo.form.BasicForm
42729 * @extends Roo.util.Observable
42730 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
42732 * @param {String/HTMLElement/Roo.Element} el The form element or its id
42733 * @param {Object} config Configuration options
42735 Roo.form.BasicForm = function(el, config){
42736 this.allItems = [];
42737 this.childForms = [];
42738 Roo.apply(this, config);
42740 * The Roo.form.Field items in this form.
42741 * @type MixedCollection
42745 this.items = new Roo.util.MixedCollection(false, function(o){
42746 return o.id || (o.id = Roo.id());
42750 * @event beforeaction
42751 * Fires before any action is performed. Return false to cancel the action.
42752 * @param {Form} this
42753 * @param {Action} action The action to be performed
42755 beforeaction: true,
42757 * @event actionfailed
42758 * Fires when an action fails.
42759 * @param {Form} this
42760 * @param {Action} action The action that failed
42762 actionfailed : true,
42764 * @event actioncomplete
42765 * Fires when an action is completed.
42766 * @param {Form} this
42767 * @param {Action} action The action that completed
42769 actioncomplete : true
42774 Roo.form.BasicForm.superclass.constructor.call(this);
42777 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
42779 * @cfg {String} method
42780 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
42783 * @cfg {DataReader} reader
42784 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
42785 * This is optional as there is built-in support for processing JSON.
42788 * @cfg {DataReader} errorReader
42789 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
42790 * This is completely optional as there is built-in support for processing JSON.
42793 * @cfg {String} url
42794 * The URL to use for form actions if one isn't supplied in the action options.
42797 * @cfg {Boolean} fileUpload
42798 * Set to true if this form is a file upload.
42802 * @cfg {Object} baseParams
42803 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
42808 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
42813 activeAction : null,
42816 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
42817 * or setValues() data instead of when the form was first created.
42819 trackResetOnLoad : false,
42823 * childForms - used for multi-tab forms
42826 childForms : false,
42829 * allItems - full list of fields.
42835 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
42836 * element by passing it or its id or mask the form itself by passing in true.
42839 waitMsgTarget : false,
42842 initEl : function(el){
42843 this.el = Roo.get(el);
42844 this.id = this.el.id || Roo.id();
42845 this.el.on('submit', this.onSubmit, this);
42846 this.el.addClass('x-form');
42850 onSubmit : function(e){
42855 * Returns true if client-side validation on the form is successful.
42858 isValid : function(){
42860 this.items.each(function(f){
42869 * Returns true if any fields in this form have changed since their original load.
42872 isDirty : function(){
42874 this.items.each(function(f){
42884 * Performs a predefined action (submit or load) or custom actions you define on this form.
42885 * @param {String} actionName The name of the action type
42886 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
42887 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
42888 * accept other config options):
42890 Property Type Description
42891 ---------------- --------------- ----------------------------------------------------------------------------------
42892 url String The url for the action (defaults to the form's url)
42893 method String The form method to use (defaults to the form's method, or POST if not defined)
42894 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
42895 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
42896 validate the form on the client (defaults to false)
42898 * @return {BasicForm} this
42900 doAction : function(action, options){
42901 if(typeof action == 'string'){
42902 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
42904 if(this.fireEvent('beforeaction', this, action) !== false){
42905 this.beforeAction(action);
42906 action.run.defer(100, action);
42912 * Shortcut to do a submit action.
42913 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
42914 * @return {BasicForm} this
42916 submit : function(options){
42917 this.doAction('submit', options);
42922 * Shortcut to do a load action.
42923 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
42924 * @return {BasicForm} this
42926 load : function(options){
42927 this.doAction('load', options);
42932 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
42933 * @param {Record} record The record to edit
42934 * @return {BasicForm} this
42936 updateRecord : function(record){
42937 record.beginEdit();
42938 var fs = record.fields;
42939 fs.each(function(f){
42940 var field = this.findField(f.name);
42942 record.set(f.name, field.getValue());
42950 * Loads an Roo.data.Record into this form.
42951 * @param {Record} record The record to load
42952 * @return {BasicForm} this
42954 loadRecord : function(record){
42955 this.setValues(record.data);
42960 beforeAction : function(action){
42961 var o = action.options;
42964 if(this.waitMsgTarget === true){
42965 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
42966 }else if(this.waitMsgTarget){
42967 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
42968 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
42970 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
42976 afterAction : function(action, success){
42977 this.activeAction = null;
42978 var o = action.options;
42980 if(this.waitMsgTarget === true){
42982 }else if(this.waitMsgTarget){
42983 this.waitMsgTarget.unmask();
42985 Roo.MessageBox.updateProgress(1);
42986 Roo.MessageBox.hide();
42993 Roo.callback(o.success, o.scope, [this, action]);
42994 this.fireEvent('actioncomplete', this, action);
42998 // failure condition..
42999 // we have a scenario where updates need confirming.
43000 // eg. if a locking scenario exists..
43001 // we look for { errors : { needs_confirm : true }} in the response.
43003 (typeof(action.result) != 'undefined') &&
43004 (typeof(action.result.errors) != 'undefined') &&
43005 (typeof(action.result.errors.needs_confirm) != 'undefined')
43008 Roo.MessageBox.confirm(
43009 "Change requires confirmation",
43010 action.result.errorMsg,
43015 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43025 Roo.callback(o.failure, o.scope, [this, action]);
43026 // show an error message if no failed handler is set..
43027 if (!this.hasListener('actionfailed')) {
43028 Roo.MessageBox.alert("Error",
43029 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43030 action.result.errorMsg :
43031 "Saving Failed, please check your entries or try again"
43035 this.fireEvent('actionfailed', this, action);
43041 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43042 * @param {String} id The value to search for
43045 findField : function(id){
43046 var field = this.items.get(id);
43048 this.items.each(function(f){
43049 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43055 return field || null;
43059 * Add a secondary form to this one,
43060 * Used to provide tabbed forms. One form is primary, with hidden values
43061 * which mirror the elements from the other forms.
43063 * @param {Roo.form.Form} form to add.
43066 addForm : function(form)
43069 if (this.childForms.indexOf(form) > -1) {
43073 this.childForms.push(form);
43075 Roo.each(form.allItems, function (fe) {
43077 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43078 if (this.findField(n)) { // already added..
43081 var add = new Roo.form.Hidden({
43084 add.render(this.el);
43091 * Mark fields in this form invalid in bulk.
43092 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43093 * @return {BasicForm} this
43095 markInvalid : function(errors){
43096 if(errors instanceof Array){
43097 for(var i = 0, len = errors.length; i < len; i++){
43098 var fieldError = errors[i];
43099 var f = this.findField(fieldError.id);
43101 f.markInvalid(fieldError.msg);
43107 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43108 field.markInvalid(errors[id]);
43112 Roo.each(this.childForms || [], function (f) {
43113 f.markInvalid(errors);
43120 * Set values for fields in this form in bulk.
43121 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43122 * @return {BasicForm} this
43124 setValues : function(values){
43125 if(values instanceof Array){ // array of objects
43126 for(var i = 0, len = values.length; i < len; i++){
43128 var f = this.findField(v.id);
43130 f.setValue(v.value);
43131 if(this.trackResetOnLoad){
43132 f.originalValue = f.getValue();
43136 }else{ // object hash
43139 if(typeof values[id] != 'function' && (field = this.findField(id))){
43141 if (field.setFromData &&
43142 field.valueField &&
43143 field.displayField &&
43144 // combos' with local stores can
43145 // be queried via setValue()
43146 // to set their value..
43147 (field.store && !field.store.isLocal)
43151 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43152 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43153 field.setFromData(sd);
43156 field.setValue(values[id]);
43160 if(this.trackResetOnLoad){
43161 field.originalValue = field.getValue();
43167 Roo.each(this.childForms || [], function (f) {
43168 f.setValues(values);
43175 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43176 * they are returned as an array.
43177 * @param {Boolean} asString
43180 getValues : function(asString){
43181 if (this.childForms) {
43182 // copy values from the child forms
43183 Roo.each(this.childForms, function (f) {
43184 this.setValues(f.getValues());
43190 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43191 if(asString === true){
43194 return Roo.urlDecode(fs);
43198 * Returns the fields in this form as an object with key/value pairs.
43199 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43202 getFieldValues : function(with_hidden)
43204 if (this.childForms) {
43205 // copy values from the child forms
43206 // should this call getFieldValues - probably not as we do not currently copy
43207 // hidden fields when we generate..
43208 Roo.each(this.childForms, function (f) {
43209 this.setValues(f.getValues());
43214 this.items.each(function(f){
43215 if (!f.getName()) {
43218 var v = f.getValue();
43219 // not sure if this supported any more..
43220 if ((typeof(v) == 'object') && f.getRawValue) {
43221 v = f.getRawValue() ; // dates..
43223 // combo boxes where name != hiddenName...
43224 if (f.name != f.getName()) {
43225 ret[f.name] = f.getRawValue();
43227 ret[f.getName()] = v;
43234 * Clears all invalid messages in this form.
43235 * @return {BasicForm} this
43237 clearInvalid : function(){
43238 this.items.each(function(f){
43242 Roo.each(this.childForms || [], function (f) {
43251 * Resets this form.
43252 * @return {BasicForm} this
43254 reset : function(){
43255 this.items.each(function(f){
43259 Roo.each(this.childForms || [], function (f) {
43268 * Add Roo.form components to this form.
43269 * @param {Field} field1
43270 * @param {Field} field2 (optional)
43271 * @param {Field} etc (optional)
43272 * @return {BasicForm} this
43275 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43281 * Removes a field from the items collection (does NOT remove its markup).
43282 * @param {Field} field
43283 * @return {BasicForm} this
43285 remove : function(field){
43286 this.items.remove(field);
43291 * Looks at the fields in this form, checks them for an id attribute,
43292 * and calls applyTo on the existing dom element with that id.
43293 * @return {BasicForm} this
43295 render : function(){
43296 this.items.each(function(f){
43297 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43305 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43306 * @param {Object} values
43307 * @return {BasicForm} this
43309 applyToFields : function(o){
43310 this.items.each(function(f){
43317 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43318 * @param {Object} values
43319 * @return {BasicForm} this
43321 applyIfToFields : function(o){
43322 this.items.each(function(f){
43330 Roo.BasicForm = Roo.form.BasicForm;/*
43332 * Ext JS Library 1.1.1
43333 * Copyright(c) 2006-2007, Ext JS, LLC.
43335 * Originally Released Under LGPL - original licence link has changed is not relivant.
43338 * <script type="text/javascript">
43342 * @class Roo.form.Form
43343 * @extends Roo.form.BasicForm
43344 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43346 * @param {Object} config Configuration options
43348 Roo.form.Form = function(config){
43350 if (config.items) {
43351 xitems = config.items;
43352 delete config.items;
43356 Roo.form.Form.superclass.constructor.call(this, null, config);
43357 this.url = this.url || this.action;
43359 this.root = new Roo.form.Layout(Roo.applyIf({
43363 this.active = this.root;
43365 * Array of all the buttons that have been added to this form via {@link addButton}
43369 this.allItems = [];
43372 * @event clientvalidation
43373 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43374 * @param {Form} this
43375 * @param {Boolean} valid true if the form has passed client-side validation
43377 clientvalidation: true,
43380 * Fires when the form is rendered
43381 * @param {Roo.form.Form} form
43386 if (this.progressUrl) {
43387 // push a hidden field onto the list of fields..
43391 name : 'UPLOAD_IDENTIFIER'
43396 Roo.each(xitems, this.addxtype, this);
43402 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43404 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43407 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43410 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43412 buttonAlign:'center',
43415 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43420 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43421 * This property cascades to child containers if not set.
43426 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43427 * fires a looping event with that state. This is required to bind buttons to the valid
43428 * state using the config value formBind:true on the button.
43430 monitorValid : false,
43433 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43438 * @cfg {String} progressUrl - Url to return progress data
43441 progressUrl : false,
43444 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43445 * fields are added and the column is closed. If no fields are passed the column remains open
43446 * until end() is called.
43447 * @param {Object} config The config to pass to the column
43448 * @param {Field} field1 (optional)
43449 * @param {Field} field2 (optional)
43450 * @param {Field} etc (optional)
43451 * @return Column The column container object
43453 column : function(c){
43454 var col = new Roo.form.Column(c);
43456 if(arguments.length > 1){ // duplicate code required because of Opera
43457 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43464 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43465 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43466 * until end() is called.
43467 * @param {Object} config The config to pass to the fieldset
43468 * @param {Field} field1 (optional)
43469 * @param {Field} field2 (optional)
43470 * @param {Field} etc (optional)
43471 * @return FieldSet The fieldset container object
43473 fieldset : function(c){
43474 var fs = new Roo.form.FieldSet(c);
43476 if(arguments.length > 1){ // duplicate code required because of Opera
43477 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43484 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43485 * fields are added and the container is closed. If no fields are passed the container remains open
43486 * until end() is called.
43487 * @param {Object} config The config to pass to the Layout
43488 * @param {Field} field1 (optional)
43489 * @param {Field} field2 (optional)
43490 * @param {Field} etc (optional)
43491 * @return Layout The container object
43493 container : function(c){
43494 var l = new Roo.form.Layout(c);
43496 if(arguments.length > 1){ // duplicate code required because of Opera
43497 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43504 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43505 * @param {Object} container A Roo.form.Layout or subclass of Layout
43506 * @return {Form} this
43508 start : function(c){
43509 // cascade label info
43510 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43511 this.active.stack.push(c);
43512 c.ownerCt = this.active;
43518 * Closes the current open container
43519 * @return {Form} this
43522 if(this.active == this.root){
43525 this.active = this.active.ownerCt;
43530 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43531 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43532 * as the label of the field.
43533 * @param {Field} field1
43534 * @param {Field} field2 (optional)
43535 * @param {Field} etc. (optional)
43536 * @return {Form} this
43539 this.active.stack.push.apply(this.active.stack, arguments);
43540 this.allItems.push.apply(this.allItems,arguments);
43542 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43543 if(a[i].isFormField){
43548 Roo.form.Form.superclass.add.apply(this, r);
43558 * Find any element that has been added to a form, using it's ID or name
43559 * This can include framesets, columns etc. along with regular fields..
43560 * @param {String} id - id or name to find.
43562 * @return {Element} e - or false if nothing found.
43564 findbyId : function(id)
43570 Roo.each(this.allItems, function(f){
43571 if (f.id == id || f.name == id ){
43582 * Render this form into the passed container. This should only be called once!
43583 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43584 * @return {Form} this
43586 render : function(ct)
43592 var o = this.autoCreate || {
43594 method : this.method || 'POST',
43595 id : this.id || Roo.id()
43597 this.initEl(ct.createChild(o));
43599 this.root.render(this.el);
43603 this.items.each(function(f){
43604 f.render('x-form-el-'+f.id);
43607 if(this.buttons.length > 0){
43608 // tables are required to maintain order and for correct IE layout
43609 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43610 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43611 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43613 var tr = tb.getElementsByTagName('tr')[0];
43614 for(var i = 0, len = this.buttons.length; i < len; i++) {
43615 var b = this.buttons[i];
43616 var td = document.createElement('td');
43617 td.className = 'x-form-btn-td';
43618 b.render(tr.appendChild(td));
43621 if(this.monitorValid){ // initialize after render
43622 this.startMonitoring();
43624 this.fireEvent('rendered', this);
43629 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43630 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43631 * object or a valid Roo.DomHelper element config
43632 * @param {Function} handler The function called when the button is clicked
43633 * @param {Object} scope (optional) The scope of the handler function
43634 * @return {Roo.Button}
43636 addButton : function(config, handler, scope){
43640 minWidth: this.minButtonWidth,
43643 if(typeof config == "string"){
43646 Roo.apply(bc, config);
43648 var btn = new Roo.Button(null, bc);
43649 this.buttons.push(btn);
43654 * Adds a series of form elements (using the xtype property as the factory method.
43655 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43656 * @param {Object} config
43659 addxtype : function()
43661 var ar = Array.prototype.slice.call(arguments, 0);
43663 for(var i = 0; i < ar.length; i++) {
43665 continue; // skip -- if this happends something invalid got sent, we
43666 // should ignore it, as basically that interface element will not show up
43667 // and that should be pretty obvious!!
43670 if (Roo.form[ar[i].xtype]) {
43672 var fe = Roo.factory(ar[i], Roo.form);
43678 fe.store.form = this;
43683 this.allItems.push(fe);
43684 if (fe.items && fe.addxtype) {
43685 fe.addxtype.apply(fe, fe.items);
43695 // console.log('adding ' + ar[i].xtype);
43697 if (ar[i].xtype == 'Button') {
43698 //console.log('adding button');
43699 //console.log(ar[i]);
43700 this.addButton(ar[i]);
43701 this.allItems.push(fe);
43705 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
43706 alert('end is not supported on xtype any more, use items');
43708 // //console.log('adding end');
43716 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
43717 * option "monitorValid"
43719 startMonitoring : function(){
43722 Roo.TaskMgr.start({
43723 run : this.bindHandler,
43724 interval : this.monitorPoll || 200,
43731 * Stops monitoring of the valid state of this form
43733 stopMonitoring : function(){
43734 this.bound = false;
43738 bindHandler : function(){
43740 return false; // stops binding
43743 this.items.each(function(f){
43744 if(!f.isValid(true)){
43749 for(var i = 0, len = this.buttons.length; i < len; i++){
43750 var btn = this.buttons[i];
43751 if(btn.formBind === true && btn.disabled === valid){
43752 btn.setDisabled(!valid);
43755 this.fireEvent('clientvalidation', this, valid);
43769 Roo.Form = Roo.form.Form;
43772 * Ext JS Library 1.1.1
43773 * Copyright(c) 2006-2007, Ext JS, LLC.
43775 * Originally Released Under LGPL - original licence link has changed is not relivant.
43778 * <script type="text/javascript">
43782 * @class Roo.form.Action
43783 * Internal Class used to handle form actions
43785 * @param {Roo.form.BasicForm} el The form element or its id
43786 * @param {Object} config Configuration options
43790 // define the action interface
43791 Roo.form.Action = function(form, options){
43793 this.options = options || {};
43796 * Client Validation Failed
43799 Roo.form.Action.CLIENT_INVALID = 'client';
43801 * Server Validation Failed
43804 Roo.form.Action.SERVER_INVALID = 'server';
43806 * Connect to Server Failed
43809 Roo.form.Action.CONNECT_FAILURE = 'connect';
43811 * Reading Data from Server Failed
43814 Roo.form.Action.LOAD_FAILURE = 'load';
43816 Roo.form.Action.prototype = {
43818 failureType : undefined,
43819 response : undefined,
43820 result : undefined,
43822 // interface method
43823 run : function(options){
43827 // interface method
43828 success : function(response){
43832 // interface method
43833 handleResponse : function(response){
43837 // default connection failure
43838 failure : function(response){
43840 this.response = response;
43841 this.failureType = Roo.form.Action.CONNECT_FAILURE;
43842 this.form.afterAction(this, false);
43845 processResponse : function(response){
43846 this.response = response;
43847 if(!response.responseText){
43850 this.result = this.handleResponse(response);
43851 return this.result;
43854 // utility functions used internally
43855 getUrl : function(appendParams){
43856 var url = this.options.url || this.form.url || this.form.el.dom.action;
43858 var p = this.getParams();
43860 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
43866 getMethod : function(){
43867 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
43870 getParams : function(){
43871 var bp = this.form.baseParams;
43872 var p = this.options.params;
43874 if(typeof p == "object"){
43875 p = Roo.urlEncode(Roo.applyIf(p, bp));
43876 }else if(typeof p == 'string' && bp){
43877 p += '&' + Roo.urlEncode(bp);
43880 p = Roo.urlEncode(bp);
43885 createCallback : function(){
43887 success: this.success,
43888 failure: this.failure,
43890 timeout: (this.form.timeout*1000),
43891 upload: this.form.fileUpload ? this.success : undefined
43896 Roo.form.Action.Submit = function(form, options){
43897 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
43900 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
43903 haveProgress : false,
43904 uploadComplete : false,
43906 // uploadProgress indicator.
43907 uploadProgress : function()
43909 if (!this.form.progressUrl) {
43913 if (!this.haveProgress) {
43914 Roo.MessageBox.progress("Uploading", "Uploading");
43916 if (this.uploadComplete) {
43917 Roo.MessageBox.hide();
43921 this.haveProgress = true;
43923 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
43925 var c = new Roo.data.Connection();
43927 url : this.form.progressUrl,
43932 success : function(req){
43933 //console.log(data);
43937 rdata = Roo.decode(req.responseText)
43939 Roo.log("Invalid data from server..");
43943 if (!rdata || !rdata.success) {
43945 Roo.MessageBox.alert(Roo.encode(rdata));
43948 var data = rdata.data;
43950 if (this.uploadComplete) {
43951 Roo.MessageBox.hide();
43956 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
43957 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
43960 this.uploadProgress.defer(2000,this);
43963 failure: function(data) {
43964 Roo.log('progress url failed ');
43975 // run get Values on the form, so it syncs any secondary forms.
43976 this.form.getValues();
43978 var o = this.options;
43979 var method = this.getMethod();
43980 var isPost = method == 'POST';
43981 if(o.clientValidation === false || this.form.isValid()){
43983 if (this.form.progressUrl) {
43984 this.form.findField('UPLOAD_IDENTIFIER').setValue(
43985 (new Date() * 1) + '' + Math.random());
43990 Roo.Ajax.request(Roo.apply(this.createCallback(), {
43991 form:this.form.el.dom,
43992 url:this.getUrl(!isPost),
43994 params:isPost ? this.getParams() : null,
43995 isUpload: this.form.fileUpload
43998 this.uploadProgress();
44000 }else if (o.clientValidation !== false){ // client validation failed
44001 this.failureType = Roo.form.Action.CLIENT_INVALID;
44002 this.form.afterAction(this, false);
44006 success : function(response)
44008 this.uploadComplete= true;
44009 if (this.haveProgress) {
44010 Roo.MessageBox.hide();
44014 var result = this.processResponse(response);
44015 if(result === true || result.success){
44016 this.form.afterAction(this, true);
44020 this.form.markInvalid(result.errors);
44021 this.failureType = Roo.form.Action.SERVER_INVALID;
44023 this.form.afterAction(this, false);
44025 failure : function(response)
44027 this.uploadComplete= true;
44028 if (this.haveProgress) {
44029 Roo.MessageBox.hide();
44032 this.response = response;
44033 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44034 this.form.afterAction(this, false);
44037 handleResponse : function(response){
44038 if(this.form.errorReader){
44039 var rs = this.form.errorReader.read(response);
44042 for(var i = 0, len = rs.records.length; i < len; i++) {
44043 var r = rs.records[i];
44044 errors[i] = r.data;
44047 if(errors.length < 1){
44051 success : rs.success,
44057 ret = Roo.decode(response.responseText);
44061 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44071 Roo.form.Action.Load = function(form, options){
44072 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44073 this.reader = this.form.reader;
44076 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44081 Roo.Ajax.request(Roo.apply(
44082 this.createCallback(), {
44083 method:this.getMethod(),
44084 url:this.getUrl(false),
44085 params:this.getParams()
44089 success : function(response){
44091 var result = this.processResponse(response);
44092 if(result === true || !result.success || !result.data){
44093 this.failureType = Roo.form.Action.LOAD_FAILURE;
44094 this.form.afterAction(this, false);
44097 this.form.clearInvalid();
44098 this.form.setValues(result.data);
44099 this.form.afterAction(this, true);
44102 handleResponse : function(response){
44103 if(this.form.reader){
44104 var rs = this.form.reader.read(response);
44105 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44107 success : rs.success,
44111 return Roo.decode(response.responseText);
44115 Roo.form.Action.ACTION_TYPES = {
44116 'load' : Roo.form.Action.Load,
44117 'submit' : Roo.form.Action.Submit
44120 * Ext JS Library 1.1.1
44121 * Copyright(c) 2006-2007, Ext JS, LLC.
44123 * Originally Released Under LGPL - original licence link has changed is not relivant.
44126 * <script type="text/javascript">
44130 * @class Roo.form.Layout
44131 * @extends Roo.Component
44132 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44134 * @param {Object} config Configuration options
44136 Roo.form.Layout = function(config){
44138 if (config.items) {
44139 xitems = config.items;
44140 delete config.items;
44142 Roo.form.Layout.superclass.constructor.call(this, config);
44144 Roo.each(xitems, this.addxtype, this);
44148 Roo.extend(Roo.form.Layout, Roo.Component, {
44150 * @cfg {String/Object} autoCreate
44151 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44154 * @cfg {String/Object/Function} style
44155 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44156 * a function which returns such a specification.
44159 * @cfg {String} labelAlign
44160 * Valid values are "left," "top" and "right" (defaults to "left")
44163 * @cfg {Number} labelWidth
44164 * Fixed width in pixels of all field labels (defaults to undefined)
44167 * @cfg {Boolean} clear
44168 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44172 * @cfg {String} labelSeparator
44173 * The separator to use after field labels (defaults to ':')
44175 labelSeparator : ':',
44177 * @cfg {Boolean} hideLabels
44178 * True to suppress the display of field labels in this layout (defaults to false)
44180 hideLabels : false,
44183 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44188 onRender : function(ct, position){
44189 if(this.el){ // from markup
44190 this.el = Roo.get(this.el);
44191 }else { // generate
44192 var cfg = this.getAutoCreate();
44193 this.el = ct.createChild(cfg, position);
44196 this.el.applyStyles(this.style);
44198 if(this.labelAlign){
44199 this.el.addClass('x-form-label-'+this.labelAlign);
44201 if(this.hideLabels){
44202 this.labelStyle = "display:none";
44203 this.elementStyle = "padding-left:0;";
44205 if(typeof this.labelWidth == 'number'){
44206 this.labelStyle = "width:"+this.labelWidth+"px;";
44207 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44209 if(this.labelAlign == 'top'){
44210 this.labelStyle = "width:auto;";
44211 this.elementStyle = "padding-left:0;";
44214 var stack = this.stack;
44215 var slen = stack.length;
44217 if(!this.fieldTpl){
44218 var t = new Roo.Template(
44219 '<div class="x-form-item {5}">',
44220 '<label for="{0}" style="{2}">{1}{4}</label>',
44221 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44223 '</div><div class="x-form-clear-left"></div>'
44225 t.disableFormats = true;
44227 Roo.form.Layout.prototype.fieldTpl = t;
44229 for(var i = 0; i < slen; i++) {
44230 if(stack[i].isFormField){
44231 this.renderField(stack[i]);
44233 this.renderComponent(stack[i]);
44238 this.el.createChild({cls:'x-form-clear'});
44243 renderField : function(f){
44244 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44247 f.labelStyle||this.labelStyle||'', //2
44248 this.elementStyle||'', //3
44249 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44250 f.itemCls||this.itemCls||'' //5
44251 ], true).getPrevSibling());
44255 renderComponent : function(c){
44256 c.render(c.isLayout ? this.el : this.el.createChild());
44259 * Adds a object form elements (using the xtype property as the factory method.)
44260 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44261 * @param {Object} config
44263 addxtype : function(o)
44265 // create the lement.
44266 o.form = this.form;
44267 var fe = Roo.factory(o, Roo.form);
44268 this.form.allItems.push(fe);
44269 this.stack.push(fe);
44271 if (fe.isFormField) {
44272 this.form.items.add(fe);
44280 * @class Roo.form.Column
44281 * @extends Roo.form.Layout
44282 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44284 * @param {Object} config Configuration options
44286 Roo.form.Column = function(config){
44287 Roo.form.Column.superclass.constructor.call(this, config);
44290 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44292 * @cfg {Number/String} width
44293 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44296 * @cfg {String/Object} autoCreate
44297 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44301 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44304 onRender : function(ct, position){
44305 Roo.form.Column.superclass.onRender.call(this, ct, position);
44307 this.el.setWidth(this.width);
44314 * @class Roo.form.Row
44315 * @extends Roo.form.Layout
44316 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44318 * @param {Object} config Configuration options
44322 Roo.form.Row = function(config){
44323 Roo.form.Row.superclass.constructor.call(this, config);
44326 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44328 * @cfg {Number/String} width
44329 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44332 * @cfg {Number/String} height
44333 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44335 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44339 onRender : function(ct, position){
44340 //console.log('row render');
44342 var t = new Roo.Template(
44343 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44344 '<label for="{0}" style="{2}">{1}{4}</label>',
44345 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44349 t.disableFormats = true;
44351 Roo.form.Layout.prototype.rowTpl = t;
44353 this.fieldTpl = this.rowTpl;
44355 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44356 var labelWidth = 100;
44358 if ((this.labelAlign != 'top')) {
44359 if (typeof this.labelWidth == 'number') {
44360 labelWidth = this.labelWidth
44362 this.padWidth = 20 + labelWidth;
44366 Roo.form.Column.superclass.onRender.call(this, ct, position);
44368 this.el.setWidth(this.width);
44371 this.el.setHeight(this.height);
44376 renderField : function(f){
44377 f.fieldEl = this.fieldTpl.append(this.el, [
44378 f.id, f.fieldLabel,
44379 f.labelStyle||this.labelStyle||'',
44380 this.elementStyle||'',
44381 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44382 f.itemCls||this.itemCls||'',
44383 f.width ? f.width + this.padWidth : 160 + this.padWidth
44390 * @class Roo.form.FieldSet
44391 * @extends Roo.form.Layout
44392 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44394 * @param {Object} config Configuration options
44396 Roo.form.FieldSet = function(config){
44397 Roo.form.FieldSet.superclass.constructor.call(this, config);
44400 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44402 * @cfg {String} legend
44403 * The text to display as the legend for the FieldSet (defaults to '')
44406 * @cfg {String/Object} autoCreate
44407 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44411 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44414 onRender : function(ct, position){
44415 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44417 this.setLegend(this.legend);
44422 setLegend : function(text){
44424 this.el.child('legend').update(text);
44429 * Ext JS Library 1.1.1
44430 * Copyright(c) 2006-2007, Ext JS, LLC.
44432 * Originally Released Under LGPL - original licence link has changed is not relivant.
44435 * <script type="text/javascript">
44438 * @class Roo.form.VTypes
44439 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44442 Roo.form.VTypes = function(){
44443 // closure these in so they are only created once.
44444 var alpha = /^[a-zA-Z_]+$/;
44445 var alphanum = /^[a-zA-Z0-9_]+$/;
44446 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44447 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44449 // All these messages and functions are configurable
44452 * The function used to validate email addresses
44453 * @param {String} value The email address
44455 'email' : function(v){
44456 return email.test(v);
44459 * The error text to display when the email validation function returns false
44462 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44464 * The keystroke filter mask to be applied on email input
44467 'emailMask' : /[a-z0-9_\.\-@]/i,
44470 * The function used to validate URLs
44471 * @param {String} value The URL
44473 'url' : function(v){
44474 return url.test(v);
44477 * The error text to display when the url validation function returns false
44480 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44483 * The function used to validate alpha values
44484 * @param {String} value The value
44486 'alpha' : function(v){
44487 return alpha.test(v);
44490 * The error text to display when the alpha validation function returns false
44493 'alphaText' : 'This field should only contain letters and _',
44495 * The keystroke filter mask to be applied on alpha input
44498 'alphaMask' : /[a-z_]/i,
44501 * The function used to validate alphanumeric values
44502 * @param {String} value The value
44504 'alphanum' : function(v){
44505 return alphanum.test(v);
44508 * The error text to display when the alphanumeric validation function returns false
44511 'alphanumText' : 'This field should only contain letters, numbers and _',
44513 * The keystroke filter mask to be applied on alphanumeric input
44516 'alphanumMask' : /[a-z0-9_]/i
44518 }();//<script type="text/javascript">
44521 * @class Roo.form.FCKeditor
44522 * @extends Roo.form.TextArea
44523 * Wrapper around the FCKEditor http://www.fckeditor.net
44525 * Creates a new FCKeditor
44526 * @param {Object} config Configuration options
44528 Roo.form.FCKeditor = function(config){
44529 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44532 * @event editorinit
44533 * Fired when the editor is initialized - you can add extra handlers here..
44534 * @param {FCKeditor} this
44535 * @param {Object} the FCK object.
44542 Roo.form.FCKeditor.editors = { };
44543 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44545 //defaultAutoCreate : {
44546 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44550 * @cfg {Object} fck options - see fck manual for details.
44555 * @cfg {Object} fck toolbar set (Basic or Default)
44557 toolbarSet : 'Basic',
44559 * @cfg {Object} fck BasePath
44561 basePath : '/fckeditor/',
44569 onRender : function(ct, position)
44572 this.defaultAutoCreate = {
44574 style:"width:300px;height:60px;",
44575 autocomplete: "off"
44578 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44581 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44582 if(this.preventScrollbars){
44583 this.el.setStyle("overflow", "hidden");
44585 this.el.setHeight(this.growMin);
44588 //console.log('onrender' + this.getId() );
44589 Roo.form.FCKeditor.editors[this.getId()] = this;
44592 this.replaceTextarea() ;
44596 getEditor : function() {
44597 return this.fckEditor;
44600 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44601 * @param {Mixed} value The value to set
44605 setValue : function(value)
44607 //console.log('setValue: ' + value);
44609 if(typeof(value) == 'undefined') { // not sure why this is happending...
44612 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44614 //if(!this.el || !this.getEditor()) {
44615 // this.value = value;
44616 //this.setValue.defer(100,this,[value]);
44620 if(!this.getEditor()) {
44624 this.getEditor().SetData(value);
44631 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44632 * @return {Mixed} value The field value
44634 getValue : function()
44637 if (this.frame && this.frame.dom.style.display == 'none') {
44638 return Roo.form.FCKeditor.superclass.getValue.call(this);
44641 if(!this.el || !this.getEditor()) {
44643 // this.getValue.defer(100,this);
44648 var value=this.getEditor().GetData();
44649 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44650 return Roo.form.FCKeditor.superclass.getValue.call(this);
44656 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44657 * @return {Mixed} value The field value
44659 getRawValue : function()
44661 if (this.frame && this.frame.dom.style.display == 'none') {
44662 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44665 if(!this.el || !this.getEditor()) {
44666 //this.getRawValue.defer(100,this);
44673 var value=this.getEditor().GetData();
44674 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44675 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44679 setSize : function(w,h) {
44683 //if (this.frame && this.frame.dom.style.display == 'none') {
44684 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44687 //if(!this.el || !this.getEditor()) {
44688 // this.setSize.defer(100,this, [w,h]);
44694 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44696 this.frame.dom.setAttribute('width', w);
44697 this.frame.dom.setAttribute('height', h);
44698 this.frame.setSize(w,h);
44702 toggleSourceEdit : function(value) {
44706 this.el.dom.style.display = value ? '' : 'none';
44707 this.frame.dom.style.display = value ? 'none' : '';
44712 focus: function(tag)
44714 if (this.frame.dom.style.display == 'none') {
44715 return Roo.form.FCKeditor.superclass.focus.call(this);
44717 if(!this.el || !this.getEditor()) {
44718 this.focus.defer(100,this, [tag]);
44725 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
44726 this.getEditor().Focus();
44728 if (!this.getEditor().Selection.GetSelection()) {
44729 this.focus.defer(100,this, [tag]);
44734 var r = this.getEditor().EditorDocument.createRange();
44735 r.setStart(tgs[0],0);
44736 r.setEnd(tgs[0],0);
44737 this.getEditor().Selection.GetSelection().removeAllRanges();
44738 this.getEditor().Selection.GetSelection().addRange(r);
44739 this.getEditor().Focus();
44746 replaceTextarea : function()
44748 if ( document.getElementById( this.getId() + '___Frame' ) )
44750 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
44752 // We must check the elements firstly using the Id and then the name.
44753 var oTextarea = document.getElementById( this.getId() );
44755 var colElementsByName = document.getElementsByName( this.getId() ) ;
44757 oTextarea.style.display = 'none' ;
44759 if ( oTextarea.tabIndex ) {
44760 this.TabIndex = oTextarea.tabIndex ;
44763 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
44764 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
44765 this.frame = Roo.get(this.getId() + '___Frame')
44768 _getConfigHtml : function()
44772 for ( var o in this.fckconfig ) {
44773 sConfig += sConfig.length > 0 ? '&' : '';
44774 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
44777 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
44781 _getIFrameHtml : function()
44783 var sFile = 'fckeditor.html' ;
44784 /* no idea what this is about..
44787 if ( (/fcksource=true/i).test( window.top.location.search ) )
44788 sFile = 'fckeditor.original.html' ;
44793 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
44794 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
44797 var html = '<iframe id="' + this.getId() +
44798 '___Frame" src="' + sLink +
44799 '" width="' + this.width +
44800 '" height="' + this.height + '"' +
44801 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
44802 ' frameborder="0" scrolling="no"></iframe>' ;
44807 _insertHtmlBefore : function( html, element )
44809 if ( element.insertAdjacentHTML ) {
44811 element.insertAdjacentHTML( 'beforeBegin', html ) ;
44813 var oRange = document.createRange() ;
44814 oRange.setStartBefore( element ) ;
44815 var oFragment = oRange.createContextualFragment( html );
44816 element.parentNode.insertBefore( oFragment, element ) ;
44829 //Roo.reg('fckeditor', Roo.form.FCKeditor);
44831 function FCKeditor_OnComplete(editorInstance){
44832 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
44833 f.fckEditor = editorInstance;
44834 //console.log("loaded");
44835 f.fireEvent('editorinit', f, editorInstance);
44855 //<script type="text/javascript">
44857 * @class Roo.form.GridField
44858 * @extends Roo.form.Field
44859 * Embed a grid (or editable grid into a form)
44862 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
44864 * xgrid.store = Roo.data.Store
44865 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
44866 * xgrid.store.reader = Roo.data.JsonReader
44870 * Creates a new GridField
44871 * @param {Object} config Configuration options
44873 Roo.form.GridField = function(config){
44874 Roo.form.GridField.superclass.constructor.call(this, config);
44878 Roo.extend(Roo.form.GridField, Roo.form.Field, {
44880 * @cfg {Number} width - used to restrict width of grid..
44884 * @cfg {Number} height - used to restrict height of grid..
44888 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
44894 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44895 * {tag: "input", type: "checkbox", autocomplete: "off"})
44897 // defaultAutoCreate : { tag: 'div' },
44898 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
44900 * @cfg {String} addTitle Text to include for adding a title.
44904 onResize : function(){
44905 Roo.form.Field.superclass.onResize.apply(this, arguments);
44908 initEvents : function(){
44909 // Roo.form.Checkbox.superclass.initEvents.call(this);
44910 // has no events...
44915 getResizeEl : function(){
44919 getPositionEl : function(){
44924 onRender : function(ct, position){
44926 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
44927 var style = this.style;
44930 Roo.form.GridField.superclass.onRender.call(this, ct, position);
44931 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
44932 this.viewEl = this.wrap.createChild({ tag: 'div' });
44934 this.viewEl.applyStyles(style);
44937 this.viewEl.setWidth(this.width);
44940 this.viewEl.setHeight(this.height);
44942 //if(this.inputValue !== undefined){
44943 //this.setValue(this.value);
44946 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
44949 this.grid.render();
44950 this.grid.getDataSource().on('remove', this.refreshValue, this);
44951 this.grid.getDataSource().on('update', this.refreshValue, this);
44952 this.grid.on('afteredit', this.refreshValue, this);
44958 * Sets the value of the item.
44959 * @param {String} either an object or a string..
44961 setValue : function(v){
44963 v = v || []; // empty set..
44964 // this does not seem smart - it really only affects memoryproxy grids..
44965 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
44966 var ds = this.grid.getDataSource();
44967 // assumes a json reader..
44969 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
44970 ds.loadData( data);
44972 // clear selection so it does not get stale.
44973 if (this.grid.sm) {
44974 this.grid.sm.clearSelections();
44977 Roo.form.GridField.superclass.setValue.call(this, v);
44978 this.refreshValue();
44979 // should load data in the grid really....
44983 refreshValue: function() {
44985 this.grid.getDataSource().each(function(r) {
44988 this.el.dom.value = Roo.encode(val);
44996 * Ext JS Library 1.1.1
44997 * Copyright(c) 2006-2007, Ext JS, LLC.
44999 * Originally Released Under LGPL - original licence link has changed is not relivant.
45002 * <script type="text/javascript">
45005 * @class Roo.form.DisplayField
45006 * @extends Roo.form.Field
45007 * A generic Field to display non-editable data.
45009 * Creates a new Display Field item.
45010 * @param {Object} config Configuration options
45012 Roo.form.DisplayField = function(config){
45013 Roo.form.DisplayField.superclass.constructor.call(this, config);
45017 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45018 inputType: 'hidden',
45024 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45026 focusClass : undefined,
45028 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45030 fieldClass: 'x-form-field',
45033 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45035 valueRenderer: undefined,
45039 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45040 * {tag: "input", type: "checkbox", autocomplete: "off"})
45043 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45045 onResize : function(){
45046 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45050 initEvents : function(){
45051 // Roo.form.Checkbox.superclass.initEvents.call(this);
45052 // has no events...
45057 getResizeEl : function(){
45061 getPositionEl : function(){
45066 onRender : function(ct, position){
45068 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45069 //if(this.inputValue !== undefined){
45070 this.wrap = this.el.wrap();
45072 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45074 if (this.bodyStyle) {
45075 this.viewEl.applyStyles(this.bodyStyle);
45077 //this.viewEl.setStyle('padding', '2px');
45079 this.setValue(this.value);
45084 initValue : Roo.emptyFn,
45089 onClick : function(){
45094 * Sets the checked state of the checkbox.
45095 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45097 setValue : function(v){
45099 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45100 // this might be called before we have a dom element..
45101 if (!this.viewEl) {
45104 this.viewEl.dom.innerHTML = html;
45105 Roo.form.DisplayField.superclass.setValue.call(this, v);
45115 * @class Roo.form.DayPicker
45116 * @extends Roo.form.Field
45117 * A Day picker show [M] [T] [W] ....
45119 * Creates a new Day Picker
45120 * @param {Object} config Configuration options
45122 Roo.form.DayPicker= function(config){
45123 Roo.form.DayPicker.superclass.constructor.call(this, config);
45127 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45129 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45131 focusClass : undefined,
45133 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45135 fieldClass: "x-form-field",
45138 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45139 * {tag: "input", type: "checkbox", autocomplete: "off"})
45141 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45144 actionMode : 'viewEl',
45148 inputType : 'hidden',
45151 inputElement: false, // real input element?
45152 basedOn: false, // ????
45154 isFormField: true, // not sure where this is needed!!!!
45156 onResize : function(){
45157 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45158 if(!this.boxLabel){
45159 this.el.alignTo(this.wrap, 'c-c');
45163 initEvents : function(){
45164 Roo.form.Checkbox.superclass.initEvents.call(this);
45165 this.el.on("click", this.onClick, this);
45166 this.el.on("change", this.onClick, this);
45170 getResizeEl : function(){
45174 getPositionEl : function(){
45180 onRender : function(ct, position){
45181 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45183 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45185 var r1 = '<table><tr>';
45186 var r2 = '<tr class="x-form-daypick-icons">';
45187 for (var i=0; i < 7; i++) {
45188 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45189 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45192 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45193 viewEl.select('img').on('click', this.onClick, this);
45194 this.viewEl = viewEl;
45197 // this will not work on Chrome!!!
45198 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45199 this.el.on('propertychange', this.setFromHidden, this); //ie
45207 initValue : Roo.emptyFn,
45210 * Returns the checked state of the checkbox.
45211 * @return {Boolean} True if checked, else false
45213 getValue : function(){
45214 return this.el.dom.value;
45219 onClick : function(e){
45220 //this.setChecked(!this.checked);
45221 Roo.get(e.target).toggleClass('x-menu-item-checked');
45222 this.refreshValue();
45223 //if(this.el.dom.checked != this.checked){
45224 // this.setValue(this.el.dom.checked);
45229 refreshValue : function()
45232 this.viewEl.select('img',true).each(function(e,i,n) {
45233 val += e.is(".x-menu-item-checked") ? String(n) : '';
45235 this.setValue(val, true);
45239 * Sets the checked state of the checkbox.
45240 * On is always based on a string comparison between inputValue and the param.
45241 * @param {Boolean/String} value - the value to set
45242 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45244 setValue : function(v,suppressEvent){
45245 if (!this.el.dom) {
45248 var old = this.el.dom.value ;
45249 this.el.dom.value = v;
45250 if (suppressEvent) {
45254 // update display..
45255 this.viewEl.select('img',true).each(function(e,i,n) {
45257 var on = e.is(".x-menu-item-checked");
45258 var newv = v.indexOf(String(n)) > -1;
45260 e.toggleClass('x-menu-item-checked');
45266 this.fireEvent('change', this, v, old);
45271 // handle setting of hidden value by some other method!!?!?
45272 setFromHidden: function()
45277 //console.log("SET FROM HIDDEN");
45278 //alert('setFrom hidden');
45279 this.setValue(this.el.dom.value);
45282 onDestroy : function()
45285 Roo.get(this.viewEl).remove();
45288 Roo.form.DayPicker.superclass.onDestroy.call(this);
45292 * RooJS Library 1.1.1
45293 * Copyright(c) 2008-2011 Alan Knowles
45300 * @class Roo.form.ComboCheck
45301 * @extends Roo.form.ComboBox
45302 * A combobox for multiple select items.
45304 * FIXME - could do with a reset button..
45307 * Create a new ComboCheck
45308 * @param {Object} config Configuration options
45310 Roo.form.ComboCheck = function(config){
45311 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45312 // should verify some data...
45314 // hiddenName = required..
45315 // displayField = required
45316 // valudField == required
45317 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45319 Roo.each(req, function(e) {
45320 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45321 throw "Roo.form.ComboCheck : missing value for: " + e;
45328 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45333 selectedClass: 'x-menu-item-checked',
45336 onRender : function(ct, position){
45342 var cls = 'x-combo-list';
45345 this.tpl = new Roo.Template({
45346 html : '<div class="'+cls+'-item x-menu-check-item">' +
45347 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45348 '<span>{' + this.displayField + '}</span>' +
45355 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45356 this.view.singleSelect = false;
45357 this.view.multiSelect = true;
45358 this.view.toggleSelect = true;
45359 this.pageTb.add(new Roo.Toolbar.Fill(), {
45362 handler: function()
45369 onViewOver : function(e, t){
45375 onViewClick : function(doFocus,index){
45379 select: function () {
45380 //Roo.log("SELECT CALLED");
45383 selectByValue : function(xv, scrollIntoView){
45384 var ar = this.getValueArray();
45387 Roo.each(ar, function(v) {
45388 if(v === undefined || v === null){
45391 var r = this.findRecord(this.valueField, v);
45393 sels.push(this.store.indexOf(r))
45397 this.view.select(sels);
45403 onSelect : function(record, index){
45404 // Roo.log("onselect Called");
45405 // this is only called by the clear button now..
45406 this.view.clearSelections();
45407 this.setValue('[]');
45408 if (this.value != this.valueBefore) {
45409 this.fireEvent('change', this, this.value, this.valueBefore);
45412 getValueArray : function()
45417 //Roo.log(this.value);
45418 if (typeof(this.value) == 'undefined') {
45421 var ar = Roo.decode(this.value);
45422 return ar instanceof Array ? ar : []; //?? valid?
45425 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45430 expand : function ()
45432 Roo.form.ComboCheck.superclass.expand.call(this);
45433 this.valueBefore = this.value;
45438 collapse : function(){
45439 Roo.form.ComboCheck.superclass.collapse.call(this);
45440 var sl = this.view.getSelectedIndexes();
45441 var st = this.store;
45445 Roo.each(sl, function(i) {
45447 nv.push(r.get(this.valueField));
45449 this.setValue(Roo.encode(nv));
45450 if (this.value != this.valueBefore) {
45452 this.fireEvent('change', this, this.value, this.valueBefore);
45457 setValue : function(v){
45461 var vals = this.getValueArray();
45463 Roo.each(vals, function(k) {
45464 var r = this.findRecord(this.valueField, k);
45466 tv.push(r.data[this.displayField]);
45467 }else if(this.valueNotFoundText !== undefined){
45468 tv.push( this.valueNotFoundText );
45473 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45474 this.hiddenField.value = v;
45478 });//<script type="text/javasscript">
45482 * @class Roo.DDView
45483 * A DnD enabled version of Roo.View.
45484 * @param {Element/String} container The Element in which to create the View.
45485 * @param {String} tpl The template string used to create the markup for each element of the View
45486 * @param {Object} config The configuration properties. These include all the config options of
45487 * {@link Roo.View} plus some specific to this class.<br>
45489 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
45490 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
45492 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
45493 .x-view-drag-insert-above {
45494 border-top:1px dotted #3366cc;
45496 .x-view-drag-insert-below {
45497 border-bottom:1px dotted #3366cc;
45503 Roo.DDView = function(container, tpl, config) {
45504 Roo.DDView.superclass.constructor.apply(this, arguments);
45505 this.getEl().setStyle("outline", "0px none");
45506 this.getEl().unselectable();
45507 if (this.dragGroup) {
45508 this.setDraggable(this.dragGroup.split(","));
45510 if (this.dropGroup) {
45511 this.setDroppable(this.dropGroup.split(","));
45513 if (this.deletable) {
45514 this.setDeletable();
45516 this.isDirtyFlag = false;
45522 Roo.extend(Roo.DDView, Roo.View, {
45523 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
45524 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
45525 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
45526 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
45530 reset: Roo.emptyFn,
45532 clearInvalid: Roo.form.Field.prototype.clearInvalid,
45534 validate: function() {
45538 destroy: function() {
45539 this.purgeListeners();
45540 this.getEl.removeAllListeners();
45541 this.getEl().remove();
45542 if (this.dragZone) {
45543 if (this.dragZone.destroy) {
45544 this.dragZone.destroy();
45547 if (this.dropZone) {
45548 if (this.dropZone.destroy) {
45549 this.dropZone.destroy();
45554 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
45555 getName: function() {
45559 /** Loads the View from a JSON string representing the Records to put into the Store. */
45560 setValue: function(v) {
45562 throw "DDView.setValue(). DDView must be constructed with a valid Store";
45565 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
45566 this.store.proxy = new Roo.data.MemoryProxy(data);
45570 /** @return {String} a parenthesised list of the ids of the Records in the View. */
45571 getValue: function() {
45573 this.store.each(function(rec) {
45574 result += rec.id + ',';
45576 return result.substr(0, result.length - 1) + ')';
45579 getIds: function() {
45580 var i = 0, result = new Array(this.store.getCount());
45581 this.store.each(function(rec) {
45582 result[i++] = rec.id;
45587 isDirty: function() {
45588 return this.isDirtyFlag;
45592 * Part of the Roo.dd.DropZone interface. If no target node is found, the
45593 * whole Element becomes the target, and this causes the drop gesture to append.
45595 getTargetFromEvent : function(e) {
45596 var target = e.getTarget();
45597 while ((target !== null) && (target.parentNode != this.el.dom)) {
45598 target = target.parentNode;
45601 target = this.el.dom.lastChild || this.el.dom;
45607 * Create the drag data which consists of an object which has the property "ddel" as
45608 * the drag proxy element.
45610 getDragData : function(e) {
45611 var target = this.findItemFromChild(e.getTarget());
45613 this.handleSelection(e);
45614 var selNodes = this.getSelectedNodes();
45617 copy: this.copy || (this.allowCopy && e.ctrlKey),
45621 var selectedIndices = this.getSelectedIndexes();
45622 for (var i = 0; i < selectedIndices.length; i++) {
45623 dragData.records.push(this.store.getAt(selectedIndices[i]));
45625 if (selNodes.length == 1) {
45626 dragData.ddel = target.cloneNode(true); // the div element
45628 var div = document.createElement('div'); // create the multi element drag "ghost"
45629 div.className = 'multi-proxy';
45630 for (var i = 0, len = selNodes.length; i < len; i++) {
45631 div.appendChild(selNodes[i].cloneNode(true));
45633 dragData.ddel = div;
45635 //console.log(dragData)
45636 //console.log(dragData.ddel.innerHTML)
45639 //console.log('nodragData')
45643 /** Specify to which ddGroup items in this DDView may be dragged. */
45644 setDraggable: function(ddGroup) {
45645 if (ddGroup instanceof Array) {
45646 Roo.each(ddGroup, this.setDraggable, this);
45649 if (this.dragZone) {
45650 this.dragZone.addToGroup(ddGroup);
45652 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
45653 containerScroll: true,
45657 // Draggability implies selection. DragZone's mousedown selects the element.
45658 if (!this.multiSelect) { this.singleSelect = true; }
45660 // Wire the DragZone's handlers up to methods in *this*
45661 this.dragZone.getDragData = this.getDragData.createDelegate(this);
45665 /** Specify from which ddGroup this DDView accepts drops. */
45666 setDroppable: function(ddGroup) {
45667 if (ddGroup instanceof Array) {
45668 Roo.each(ddGroup, this.setDroppable, this);
45671 if (this.dropZone) {
45672 this.dropZone.addToGroup(ddGroup);
45674 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
45675 containerScroll: true,
45679 // Wire the DropZone's handlers up to methods in *this*
45680 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
45681 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
45682 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
45683 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
45684 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
45688 /** Decide whether to drop above or below a View node. */
45689 getDropPoint : function(e, n, dd){
45690 if (n == this.el.dom) { return "above"; }
45691 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
45692 var c = t + (b - t) / 2;
45693 var y = Roo.lib.Event.getPageY(e);
45701 onNodeEnter : function(n, dd, e, data){
45705 onNodeOver : function(n, dd, e, data){
45706 var pt = this.getDropPoint(e, n, dd);
45707 // set the insert point style on the target node
45708 var dragElClass = this.dropNotAllowed;
45711 if (pt == "above"){
45712 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
45713 targetElClass = "x-view-drag-insert-above";
45715 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
45716 targetElClass = "x-view-drag-insert-below";
45718 if (this.lastInsertClass != targetElClass){
45719 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
45720 this.lastInsertClass = targetElClass;
45723 return dragElClass;
45726 onNodeOut : function(n, dd, e, data){
45727 this.removeDropIndicators(n);
45730 onNodeDrop : function(n, dd, e, data){
45731 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
45734 var pt = this.getDropPoint(e, n, dd);
45735 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
45736 if (pt == "below") { insertAt++; }
45737 for (var i = 0; i < data.records.length; i++) {
45738 var r = data.records[i];
45739 var dup = this.store.getById(r.id);
45740 if (dup && (dd != this.dragZone)) {
45741 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
45744 this.store.insert(insertAt++, r.copy());
45746 data.source.isDirtyFlag = true;
45748 this.store.insert(insertAt++, r);
45750 this.isDirtyFlag = true;
45753 this.dragZone.cachedTarget = null;
45757 removeDropIndicators : function(n){
45759 Roo.fly(n).removeClass([
45760 "x-view-drag-insert-above",
45761 "x-view-drag-insert-below"]);
45762 this.lastInsertClass = "_noclass";
45767 * Utility method. Add a delete option to the DDView's context menu.
45768 * @param {String} imageUrl The URL of the "delete" icon image.
45770 setDeletable: function(imageUrl) {
45771 if (!this.singleSelect && !this.multiSelect) {
45772 this.singleSelect = true;
45774 var c = this.getContextMenu();
45775 this.contextMenu.on("itemclick", function(item) {
45778 this.remove(this.getSelectedIndexes());
45782 this.contextMenu.add({
45789 /** Return the context menu for this DDView. */
45790 getContextMenu: function() {
45791 if (!this.contextMenu) {
45792 // Create the View's context menu
45793 this.contextMenu = new Roo.menu.Menu({
45794 id: this.id + "-contextmenu"
45796 this.el.on("contextmenu", this.showContextMenu, this);
45798 return this.contextMenu;
45801 disableContextMenu: function() {
45802 if (this.contextMenu) {
45803 this.el.un("contextmenu", this.showContextMenu, this);
45807 showContextMenu: function(e, item) {
45808 item = this.findItemFromChild(e.getTarget());
45811 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
45812 this.contextMenu.showAt(e.getXY());
45817 * Remove {@link Roo.data.Record}s at the specified indices.
45818 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
45820 remove: function(selectedIndices) {
45821 selectedIndices = [].concat(selectedIndices);
45822 for (var i = 0; i < selectedIndices.length; i++) {
45823 var rec = this.store.getAt(selectedIndices[i]);
45824 this.store.remove(rec);
45829 * Double click fires the event, but also, if this is draggable, and there is only one other
45830 * related DropZone, it transfers the selected node.
45832 onDblClick : function(e){
45833 var item = this.findItemFromChild(e.getTarget());
45835 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
45838 if (this.dragGroup) {
45839 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
45840 while (targets.indexOf(this.dropZone) > -1) {
45841 targets.remove(this.dropZone);
45843 if (targets.length == 1) {
45844 this.dragZone.cachedTarget = null;
45845 var el = Roo.get(targets[0].getEl());
45846 var box = el.getBox(true);
45847 targets[0].onNodeDrop(el.dom, {
45849 xy: [box.x, box.y + box.height - 1]
45850 }, null, this.getDragData(e));
45856 handleSelection: function(e) {
45857 this.dragZone.cachedTarget = null;
45858 var item = this.findItemFromChild(e.getTarget());
45860 this.clearSelections(true);
45863 if (item && (this.multiSelect || this.singleSelect)){
45864 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
45865 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
45866 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
45867 this.unselect(item);
45869 this.select(item, this.multiSelect && e.ctrlKey);
45870 this.lastSelection = item;
45875 onItemClick : function(item, index, e){
45876 if(this.fireEvent("beforeclick", this, index, item, e) === false){
45882 unselect : function(nodeInfo, suppressEvent){
45883 var node = this.getNode(nodeInfo);
45884 if(node && this.isSelected(node)){
45885 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
45886 Roo.fly(node).removeClass(this.selectedClass);
45887 this.selections.remove(node);
45888 if(!suppressEvent){
45889 this.fireEvent("selectionchange", this, this.selections);
45897 * Ext JS Library 1.1.1
45898 * Copyright(c) 2006-2007, Ext JS, LLC.
45900 * Originally Released Under LGPL - original licence link has changed is not relivant.
45903 * <script type="text/javascript">
45907 * @class Roo.LayoutManager
45908 * @extends Roo.util.Observable
45909 * Base class for layout managers.
45911 Roo.LayoutManager = function(container, config){
45912 Roo.LayoutManager.superclass.constructor.call(this);
45913 this.el = Roo.get(container);
45914 // ie scrollbar fix
45915 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
45916 document.body.scroll = "no";
45917 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
45918 this.el.position('relative');
45920 this.id = this.el.id;
45921 this.el.addClass("x-layout-container");
45922 /** false to disable window resize monitoring @type Boolean */
45923 this.monitorWindowResize = true;
45928 * Fires when a layout is performed.
45929 * @param {Roo.LayoutManager} this
45933 * @event regionresized
45934 * Fires when the user resizes a region.
45935 * @param {Roo.LayoutRegion} region The resized region
45936 * @param {Number} newSize The new size (width for east/west, height for north/south)
45938 "regionresized" : true,
45940 * @event regioncollapsed
45941 * Fires when a region is collapsed.
45942 * @param {Roo.LayoutRegion} region The collapsed region
45944 "regioncollapsed" : true,
45946 * @event regionexpanded
45947 * Fires when a region is expanded.
45948 * @param {Roo.LayoutRegion} region The expanded region
45950 "regionexpanded" : true
45952 this.updating = false;
45953 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
45956 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
45958 * Returns true if this layout is currently being updated
45959 * @return {Boolean}
45961 isUpdating : function(){
45962 return this.updating;
45966 * Suspend the LayoutManager from doing auto-layouts while
45967 * making multiple add or remove calls
45969 beginUpdate : function(){
45970 this.updating = true;
45974 * Restore auto-layouts and optionally disable the manager from performing a layout
45975 * @param {Boolean} noLayout true to disable a layout update
45977 endUpdate : function(noLayout){
45978 this.updating = false;
45984 layout: function(){
45988 onRegionResized : function(region, newSize){
45989 this.fireEvent("regionresized", region, newSize);
45993 onRegionCollapsed : function(region){
45994 this.fireEvent("regioncollapsed", region);
45997 onRegionExpanded : function(region){
45998 this.fireEvent("regionexpanded", region);
46002 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
46003 * performs box-model adjustments.
46004 * @return {Object} The size as an object {width: (the width), height: (the height)}
46006 getViewSize : function(){
46008 if(this.el.dom != document.body){
46009 size = this.el.getSize();
46011 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
46013 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
46014 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
46019 * Returns the Element this layout is bound to.
46020 * @return {Roo.Element}
46022 getEl : function(){
46027 * Returns the specified region.
46028 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
46029 * @return {Roo.LayoutRegion}
46031 getRegion : function(target){
46032 return this.regions[target.toLowerCase()];
46035 onWindowResize : function(){
46036 if(this.monitorWindowResize){
46042 * Ext JS Library 1.1.1
46043 * Copyright(c) 2006-2007, Ext JS, LLC.
46045 * Originally Released Under LGPL - original licence link has changed is not relivant.
46048 * <script type="text/javascript">
46051 * @class Roo.BorderLayout
46052 * @extends Roo.LayoutManager
46053 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
46054 * please see: <br><br>
46055 * <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>
46056 * <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>
46059 var layout = new Roo.BorderLayout(document.body, {
46093 preferredTabWidth: 150
46098 var CP = Roo.ContentPanel;
46100 layout.beginUpdate();
46101 layout.add("north", new CP("north", "North"));
46102 layout.add("south", new CP("south", {title: "South", closable: true}));
46103 layout.add("west", new CP("west", {title: "West"}));
46104 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
46105 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
46106 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
46107 layout.getRegion("center").showPanel("center1");
46108 layout.endUpdate();
46111 <b>The container the layout is rendered into can be either the body element or any other element.
46112 If it is not the body element, the container needs to either be an absolute positioned element,
46113 or you will need to add "position:relative" to the css of the container. You will also need to specify
46114 the container size if it is not the body element.</b>
46117 * Create a new BorderLayout
46118 * @param {String/HTMLElement/Element} container The container this layout is bound to
46119 * @param {Object} config Configuration options
46121 Roo.BorderLayout = function(container, config){
46122 config = config || {};
46123 Roo.BorderLayout.superclass.constructor.call(this, container, config);
46124 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
46125 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
46126 var target = this.factory.validRegions[i];
46127 if(config[target]){
46128 this.addRegion(target, config[target]);
46133 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
46135 * Creates and adds a new region if it doesn't already exist.
46136 * @param {String} target The target region key (north, south, east, west or center).
46137 * @param {Object} config The regions config object
46138 * @return {BorderLayoutRegion} The new region
46140 addRegion : function(target, config){
46141 if(!this.regions[target]){
46142 var r = this.factory.create(target, this, config);
46143 this.bindRegion(target, r);
46145 return this.regions[target];
46149 bindRegion : function(name, r){
46150 this.regions[name] = r;
46151 r.on("visibilitychange", this.layout, this);
46152 r.on("paneladded", this.layout, this);
46153 r.on("panelremoved", this.layout, this);
46154 r.on("invalidated", this.layout, this);
46155 r.on("resized", this.onRegionResized, this);
46156 r.on("collapsed", this.onRegionCollapsed, this);
46157 r.on("expanded", this.onRegionExpanded, this);
46161 * Performs a layout update.
46163 layout : function(){
46164 if(this.updating) return;
46165 var size = this.getViewSize();
46166 var w = size.width;
46167 var h = size.height;
46172 //var x = 0, y = 0;
46174 var rs = this.regions;
46175 var north = rs["north"];
46176 var south = rs["south"];
46177 var west = rs["west"];
46178 var east = rs["east"];
46179 var center = rs["center"];
46180 //if(this.hideOnLayout){ // not supported anymore
46181 //c.el.setStyle("display", "none");
46183 if(north && north.isVisible()){
46184 var b = north.getBox();
46185 var m = north.getMargins();
46186 b.width = w - (m.left+m.right);
46189 centerY = b.height + b.y + m.bottom;
46190 centerH -= centerY;
46191 north.updateBox(this.safeBox(b));
46193 if(south && south.isVisible()){
46194 var b = south.getBox();
46195 var m = south.getMargins();
46196 b.width = w - (m.left+m.right);
46198 var totalHeight = (b.height + m.top + m.bottom);
46199 b.y = h - totalHeight + m.top;
46200 centerH -= totalHeight;
46201 south.updateBox(this.safeBox(b));
46203 if(west && west.isVisible()){
46204 var b = west.getBox();
46205 var m = west.getMargins();
46206 b.height = centerH - (m.top+m.bottom);
46208 b.y = centerY + m.top;
46209 var totalWidth = (b.width + m.left + m.right);
46210 centerX += totalWidth;
46211 centerW -= totalWidth;
46212 west.updateBox(this.safeBox(b));
46214 if(east && east.isVisible()){
46215 var b = east.getBox();
46216 var m = east.getMargins();
46217 b.height = centerH - (m.top+m.bottom);
46218 var totalWidth = (b.width + m.left + m.right);
46219 b.x = w - totalWidth + m.left;
46220 b.y = centerY + m.top;
46221 centerW -= totalWidth;
46222 east.updateBox(this.safeBox(b));
46225 var m = center.getMargins();
46227 x: centerX + m.left,
46228 y: centerY + m.top,
46229 width: centerW - (m.left+m.right),
46230 height: centerH - (m.top+m.bottom)
46232 //if(this.hideOnLayout){
46233 //center.el.setStyle("display", "block");
46235 center.updateBox(this.safeBox(centerBox));
46238 this.fireEvent("layout", this);
46242 safeBox : function(box){
46243 box.width = Math.max(0, box.width);
46244 box.height = Math.max(0, box.height);
46249 * Adds a ContentPanel (or subclass) to this layout.
46250 * @param {String} target The target region key (north, south, east, west or center).
46251 * @param {Roo.ContentPanel} panel The panel to add
46252 * @return {Roo.ContentPanel} The added panel
46254 add : function(target, panel){
46256 target = target.toLowerCase();
46257 return this.regions[target].add(panel);
46261 * Remove a ContentPanel (or subclass) to this layout.
46262 * @param {String} target The target region key (north, south, east, west or center).
46263 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
46264 * @return {Roo.ContentPanel} The removed panel
46266 remove : function(target, panel){
46267 target = target.toLowerCase();
46268 return this.regions[target].remove(panel);
46272 * Searches all regions for a panel with the specified id
46273 * @param {String} panelId
46274 * @return {Roo.ContentPanel} The panel or null if it wasn't found
46276 findPanel : function(panelId){
46277 var rs = this.regions;
46278 for(var target in rs){
46279 if(typeof rs[target] != "function"){
46280 var p = rs[target].getPanel(panelId);
46290 * Searches all regions for a panel with the specified id and activates (shows) it.
46291 * @param {String/ContentPanel} panelId The panels id or the panel itself
46292 * @return {Roo.ContentPanel} The shown panel or null
46294 showPanel : function(panelId) {
46295 var rs = this.regions;
46296 for(var target in rs){
46297 var r = rs[target];
46298 if(typeof r != "function"){
46299 if(r.hasPanel(panelId)){
46300 return r.showPanel(panelId);
46308 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
46309 * @param {Roo.state.Provider} provider (optional) An alternate state provider
46311 restoreState : function(provider){
46313 provider = Roo.state.Manager;
46315 var sm = new Roo.LayoutStateManager();
46316 sm.init(this, provider);
46320 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
46321 * object should contain properties for each region to add ContentPanels to, and each property's value should be
46322 * a valid ContentPanel config object. Example:
46324 // Create the main layout
46325 var layout = new Roo.BorderLayout('main-ct', {
46336 // Create and add multiple ContentPanels at once via configs
46339 id: 'source-files',
46341 title:'Ext Source Files',
46354 * @param {Object} regions An object containing ContentPanel configs by region name
46356 batchAdd : function(regions){
46357 this.beginUpdate();
46358 for(var rname in regions){
46359 var lr = this.regions[rname];
46361 this.addTypedPanels(lr, regions[rname]);
46368 addTypedPanels : function(lr, ps){
46369 if(typeof ps == 'string'){
46370 lr.add(new Roo.ContentPanel(ps));
46372 else if(ps instanceof Array){
46373 for(var i =0, len = ps.length; i < len; i++){
46374 this.addTypedPanels(lr, ps[i]);
46377 else if(!ps.events){ // raw config?
46379 delete ps.el; // prevent conflict
46380 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
46382 else { // panel object assumed!
46387 * Adds a xtype elements to the layout.
46391 xtype : 'ContentPanel',
46398 xtype : 'NestedLayoutPanel',
46404 items : [ ... list of content panels or nested layout panels.. ]
46408 * @param {Object} cfg Xtype definition of item to add.
46410 addxtype : function(cfg)
46412 // basically accepts a pannel...
46413 // can accept a layout region..!?!?
46414 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
46416 if (!cfg.xtype.match(/Panel$/)) {
46421 if (typeof(cfg.region) == 'undefined') {
46422 Roo.log("Failed to add Panel, region was not set");
46426 var region = cfg.region;
46432 xitems = cfg.items;
46439 case 'ContentPanel': // ContentPanel (el, cfg)
46440 case 'ScrollPanel': // ContentPanel (el, cfg)
46441 if(cfg.autoCreate) {
46442 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
46444 var el = this.el.createChild();
46445 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
46448 this.add(region, ret);
46452 case 'TreePanel': // our new panel!
46453 cfg.el = this.el.createChild();
46454 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
46455 this.add(region, ret);
46458 case 'NestedLayoutPanel':
46459 // create a new Layout (which is a Border Layout...
46460 var el = this.el.createChild();
46461 var clayout = cfg.layout;
46463 clayout.items = clayout.items || [];
46464 // replace this exitems with the clayout ones..
46465 xitems = clayout.items;
46468 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
46469 cfg.background = false;
46471 var layout = new Roo.BorderLayout(el, clayout);
46473 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
46474 //console.log('adding nested layout panel ' + cfg.toSource());
46475 this.add(region, ret);
46476 nb = {}; /// find first...
46481 // needs grid and region
46483 //var el = this.getRegion(region).el.createChild();
46484 var el = this.el.createChild();
46485 // create the grid first...
46487 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
46489 if (region == 'center' && this.active ) {
46490 cfg.background = false;
46492 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
46494 this.add(region, ret);
46495 if (cfg.background) {
46496 ret.on('activate', function(gp) {
46497 if (!gp.grid.rendered) {
46510 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
46512 // GridPanel (grid, cfg)
46515 this.beginUpdate();
46519 Roo.each(xitems, function(i) {
46520 region = nb && i.region ? i.region : false;
46522 var add = ret.addxtype(i);
46525 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
46526 if (!i.background) {
46527 abn[region] = nb[region] ;
46534 // make the last non-background panel active..
46535 //if (nb) { Roo.log(abn); }
46538 for(var r in abn) {
46539 region = this.getRegion(r);
46541 // tried using nb[r], but it does not work..
46543 region.showPanel(abn[r]);
46554 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
46555 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
46556 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
46557 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
46560 var CP = Roo.ContentPanel;
46562 var layout = Roo.BorderLayout.create({
46566 panels: [new CP("north", "North")]
46575 panels: [new CP("west", {title: "West"})]
46584 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
46593 panels: [new CP("south", {title: "South", closable: true})]
46600 preferredTabWidth: 150,
46602 new CP("center1", {title: "Close Me", closable: true}),
46603 new CP("center2", {title: "Center Panel", closable: false})
46608 layout.getRegion("center").showPanel("center1");
46613 Roo.BorderLayout.create = function(config, targetEl){
46614 var layout = new Roo.BorderLayout(targetEl || document.body, config);
46615 layout.beginUpdate();
46616 var regions = Roo.BorderLayout.RegionFactory.validRegions;
46617 for(var j = 0, jlen = regions.length; j < jlen; j++){
46618 var lr = regions[j];
46619 if(layout.regions[lr] && config[lr].panels){
46620 var r = layout.regions[lr];
46621 var ps = config[lr].panels;
46622 layout.addTypedPanels(r, ps);
46625 layout.endUpdate();
46630 Roo.BorderLayout.RegionFactory = {
46632 validRegions : ["north","south","east","west","center"],
46635 create : function(target, mgr, config){
46636 target = target.toLowerCase();
46637 if(config.lightweight || config.basic){
46638 return new Roo.BasicLayoutRegion(mgr, config, target);
46642 return new Roo.NorthLayoutRegion(mgr, config);
46644 return new Roo.SouthLayoutRegion(mgr, config);
46646 return new Roo.EastLayoutRegion(mgr, config);
46648 return new Roo.WestLayoutRegion(mgr, config);
46650 return new Roo.CenterLayoutRegion(mgr, config);
46652 throw 'Layout region "'+target+'" not supported.';
46656 * Ext JS Library 1.1.1
46657 * Copyright(c) 2006-2007, Ext JS, LLC.
46659 * Originally Released Under LGPL - original licence link has changed is not relivant.
46662 * <script type="text/javascript">
46666 * @class Roo.BasicLayoutRegion
46667 * @extends Roo.util.Observable
46668 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
46669 * and does not have a titlebar, tabs or any other features. All it does is size and position
46670 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
46672 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
46674 this.position = pos;
46677 * @scope Roo.BasicLayoutRegion
46681 * @event beforeremove
46682 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
46683 * @param {Roo.LayoutRegion} this
46684 * @param {Roo.ContentPanel} panel The panel
46685 * @param {Object} e The cancel event object
46687 "beforeremove" : true,
46689 * @event invalidated
46690 * Fires when the layout for this region is changed.
46691 * @param {Roo.LayoutRegion} this
46693 "invalidated" : true,
46695 * @event visibilitychange
46696 * Fires when this region is shown or hidden
46697 * @param {Roo.LayoutRegion} this
46698 * @param {Boolean} visibility true or false
46700 "visibilitychange" : true,
46702 * @event paneladded
46703 * Fires when a panel is added.
46704 * @param {Roo.LayoutRegion} this
46705 * @param {Roo.ContentPanel} panel The panel
46707 "paneladded" : true,
46709 * @event panelremoved
46710 * Fires when a panel is removed.
46711 * @param {Roo.LayoutRegion} this
46712 * @param {Roo.ContentPanel} panel The panel
46714 "panelremoved" : true,
46717 * Fires when this region is collapsed.
46718 * @param {Roo.LayoutRegion} this
46720 "collapsed" : true,
46723 * Fires when this region is expanded.
46724 * @param {Roo.LayoutRegion} this
46729 * Fires when this region is slid into view.
46730 * @param {Roo.LayoutRegion} this
46732 "slideshow" : true,
46735 * Fires when this region slides out of view.
46736 * @param {Roo.LayoutRegion} this
46738 "slidehide" : true,
46740 * @event panelactivated
46741 * Fires when a panel is activated.
46742 * @param {Roo.LayoutRegion} this
46743 * @param {Roo.ContentPanel} panel The activated panel
46745 "panelactivated" : true,
46748 * Fires when the user resizes this region.
46749 * @param {Roo.LayoutRegion} this
46750 * @param {Number} newSize The new size (width for east/west, height for north/south)
46754 /** A collection of panels in this region. @type Roo.util.MixedCollection */
46755 this.panels = new Roo.util.MixedCollection();
46756 this.panels.getKey = this.getPanelId.createDelegate(this);
46758 this.activePanel = null;
46759 // ensure listeners are added...
46761 if (config.listeners || config.events) {
46762 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
46763 listeners : config.listeners || {},
46764 events : config.events || {}
46768 if(skipConfig !== true){
46769 this.applyConfig(config);
46773 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
46774 getPanelId : function(p){
46778 applyConfig : function(config){
46779 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
46780 this.config = config;
46785 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
46786 * the width, for horizontal (north, south) the height.
46787 * @param {Number} newSize The new width or height
46789 resizeTo : function(newSize){
46790 var el = this.el ? this.el :
46791 (this.activePanel ? this.activePanel.getEl() : null);
46793 switch(this.position){
46796 el.setWidth(newSize);
46797 this.fireEvent("resized", this, newSize);
46801 el.setHeight(newSize);
46802 this.fireEvent("resized", this, newSize);
46808 getBox : function(){
46809 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
46812 getMargins : function(){
46813 return this.margins;
46816 updateBox : function(box){
46818 var el = this.activePanel.getEl();
46819 el.dom.style.left = box.x + "px";
46820 el.dom.style.top = box.y + "px";
46821 this.activePanel.setSize(box.width, box.height);
46825 * Returns the container element for this region.
46826 * @return {Roo.Element}
46828 getEl : function(){
46829 return this.activePanel;
46833 * Returns true if this region is currently visible.
46834 * @return {Boolean}
46836 isVisible : function(){
46837 return this.activePanel ? true : false;
46840 setActivePanel : function(panel){
46841 panel = this.getPanel(panel);
46842 if(this.activePanel && this.activePanel != panel){
46843 this.activePanel.setActiveState(false);
46844 this.activePanel.getEl().setLeftTop(-10000,-10000);
46846 this.activePanel = panel;
46847 panel.setActiveState(true);
46849 panel.setSize(this.box.width, this.box.height);
46851 this.fireEvent("panelactivated", this, panel);
46852 this.fireEvent("invalidated");
46856 * Show the specified panel.
46857 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
46858 * @return {Roo.ContentPanel} The shown panel or null
46860 showPanel : function(panel){
46861 if(panel = this.getPanel(panel)){
46862 this.setActivePanel(panel);
46868 * Get the active panel for this region.
46869 * @return {Roo.ContentPanel} The active panel or null
46871 getActivePanel : function(){
46872 return this.activePanel;
46876 * Add the passed ContentPanel(s)
46877 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
46878 * @return {Roo.ContentPanel} The panel added (if only one was added)
46880 add : function(panel){
46881 if(arguments.length > 1){
46882 for(var i = 0, len = arguments.length; i < len; i++) {
46883 this.add(arguments[i]);
46887 if(this.hasPanel(panel)){
46888 this.showPanel(panel);
46891 var el = panel.getEl();
46892 if(el.dom.parentNode != this.mgr.el.dom){
46893 this.mgr.el.dom.appendChild(el.dom);
46895 if(panel.setRegion){
46896 panel.setRegion(this);
46898 this.panels.add(panel);
46899 el.setStyle("position", "absolute");
46900 if(!panel.background){
46901 this.setActivePanel(panel);
46902 if(this.config.initialSize && this.panels.getCount()==1){
46903 this.resizeTo(this.config.initialSize);
46906 this.fireEvent("paneladded", this, panel);
46911 * Returns true if the panel is in this region.
46912 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46913 * @return {Boolean}
46915 hasPanel : function(panel){
46916 if(typeof panel == "object"){ // must be panel obj
46917 panel = panel.getId();
46919 return this.getPanel(panel) ? true : false;
46923 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
46924 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46925 * @param {Boolean} preservePanel Overrides the config preservePanel option
46926 * @return {Roo.ContentPanel} The panel that was removed
46928 remove : function(panel, preservePanel){
46929 panel = this.getPanel(panel);
46934 this.fireEvent("beforeremove", this, panel, e);
46935 if(e.cancel === true){
46938 var panelId = panel.getId();
46939 this.panels.removeKey(panelId);
46944 * Returns the panel specified or null if it's not in this region.
46945 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
46946 * @return {Roo.ContentPanel}
46948 getPanel : function(id){
46949 if(typeof id == "object"){ // must be panel obj
46952 return this.panels.get(id);
46956 * Returns this regions position (north/south/east/west/center).
46959 getPosition: function(){
46960 return this.position;
46964 * Ext JS Library 1.1.1
46965 * Copyright(c) 2006-2007, Ext JS, LLC.
46967 * Originally Released Under LGPL - original licence link has changed is not relivant.
46970 * <script type="text/javascript">
46974 * @class Roo.LayoutRegion
46975 * @extends Roo.BasicLayoutRegion
46976 * This class represents a region in a layout manager.
46977 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
46978 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
46979 * @cfg {Boolean} floatable False to disable floating (defaults to true)
46980 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
46981 * @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})
46982 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
46983 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
46984 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
46985 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
46986 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
46987 * @cfg {String} title The title for the region (overrides panel titles)
46988 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
46989 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
46990 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
46991 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
46992 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
46993 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
46994 * the space available, similar to FireFox 1.5 tabs (defaults to false)
46995 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
46996 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
46997 * @cfg {Boolean} showPin True to show a pin button
46998 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
46999 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
47000 * @cfg {Boolean} disableTabTips True to disable tab tooltips
47001 * @cfg {Number} width For East/West panels
47002 * @cfg {Number} height For North/South panels
47003 * @cfg {Boolean} split To show the splitter
47004 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
47006 Roo.LayoutRegion = function(mgr, config, pos){
47007 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
47008 var dh = Roo.DomHelper;
47009 /** This region's container element
47010 * @type Roo.Element */
47011 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
47012 /** This region's title element
47013 * @type Roo.Element */
47015 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
47016 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
47017 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
47019 this.titleEl.enableDisplayMode();
47020 /** This region's title text element
47021 * @type HTMLElement */
47022 this.titleTextEl = this.titleEl.dom.firstChild;
47023 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
47024 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
47025 this.closeBtn.enableDisplayMode();
47026 this.closeBtn.on("click", this.closeClicked, this);
47027 this.closeBtn.hide();
47029 this.createBody(config);
47030 this.visible = true;
47031 this.collapsed = false;
47033 if(config.hideWhenEmpty){
47035 this.on("paneladded", this.validateVisibility, this);
47036 this.on("panelremoved", this.validateVisibility, this);
47038 this.applyConfig(config);
47041 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
47043 createBody : function(){
47044 /** This region's body element
47045 * @type Roo.Element */
47046 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
47049 applyConfig : function(c){
47050 if(c.collapsible && this.position != "center" && !this.collapsedEl){
47051 var dh = Roo.DomHelper;
47052 if(c.titlebar !== false){
47053 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
47054 this.collapseBtn.on("click", this.collapse, this);
47055 this.collapseBtn.enableDisplayMode();
47057 if(c.showPin === true || this.showPin){
47058 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
47059 this.stickBtn.enableDisplayMode();
47060 this.stickBtn.on("click", this.expand, this);
47061 this.stickBtn.hide();
47064 /** This region's collapsed element
47065 * @type Roo.Element */
47066 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
47067 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
47069 if(c.floatable !== false){
47070 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
47071 this.collapsedEl.on("click", this.collapseClick, this);
47074 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
47075 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
47076 id: "message", unselectable: "on", style:{"float":"left"}});
47077 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
47079 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
47080 this.expandBtn.on("click", this.expand, this);
47082 if(this.collapseBtn){
47083 this.collapseBtn.setVisible(c.collapsible == true);
47085 this.cmargins = c.cmargins || this.cmargins ||
47086 (this.position == "west" || this.position == "east" ?
47087 {top: 0, left: 2, right:2, bottom: 0} :
47088 {top: 2, left: 0, right:0, bottom: 2});
47089 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
47090 this.bottomTabs = c.tabPosition != "top";
47091 this.autoScroll = c.autoScroll || false;
47092 if(this.autoScroll){
47093 this.bodyEl.setStyle("overflow", "auto");
47095 this.bodyEl.setStyle("overflow", "hidden");
47097 //if(c.titlebar !== false){
47098 if((!c.titlebar && !c.title) || c.titlebar === false){
47099 this.titleEl.hide();
47101 this.titleEl.show();
47103 this.titleTextEl.innerHTML = c.title;
47107 this.duration = c.duration || .30;
47108 this.slideDuration = c.slideDuration || .45;
47111 this.collapse(true);
47118 * Returns true if this region is currently visible.
47119 * @return {Boolean}
47121 isVisible : function(){
47122 return this.visible;
47126 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
47127 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
47129 setCollapsedTitle : function(title){
47130 title = title || " ";
47131 if(this.collapsedTitleTextEl){
47132 this.collapsedTitleTextEl.innerHTML = title;
47136 getBox : function(){
47138 if(!this.collapsed){
47139 b = this.el.getBox(false, true);
47141 b = this.collapsedEl.getBox(false, true);
47146 getMargins : function(){
47147 return this.collapsed ? this.cmargins : this.margins;
47150 highlight : function(){
47151 this.el.addClass("x-layout-panel-dragover");
47154 unhighlight : function(){
47155 this.el.removeClass("x-layout-panel-dragover");
47158 updateBox : function(box){
47160 if(!this.collapsed){
47161 this.el.dom.style.left = box.x + "px";
47162 this.el.dom.style.top = box.y + "px";
47163 this.updateBody(box.width, box.height);
47165 this.collapsedEl.dom.style.left = box.x + "px";
47166 this.collapsedEl.dom.style.top = box.y + "px";
47167 this.collapsedEl.setSize(box.width, box.height);
47170 this.tabs.autoSizeTabs();
47174 updateBody : function(w, h){
47176 this.el.setWidth(w);
47177 w -= this.el.getBorderWidth("rl");
47178 if(this.config.adjustments){
47179 w += this.config.adjustments[0];
47183 this.el.setHeight(h);
47184 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
47185 h -= this.el.getBorderWidth("tb");
47186 if(this.config.adjustments){
47187 h += this.config.adjustments[1];
47189 this.bodyEl.setHeight(h);
47191 h = this.tabs.syncHeight(h);
47194 if(this.panelSize){
47195 w = w !== null ? w : this.panelSize.width;
47196 h = h !== null ? h : this.panelSize.height;
47198 if(this.activePanel){
47199 var el = this.activePanel.getEl();
47200 w = w !== null ? w : el.getWidth();
47201 h = h !== null ? h : el.getHeight();
47202 this.panelSize = {width: w, height: h};
47203 this.activePanel.setSize(w, h);
47205 if(Roo.isIE && this.tabs){
47206 this.tabs.el.repaint();
47211 * Returns the container element for this region.
47212 * @return {Roo.Element}
47214 getEl : function(){
47219 * Hides this region.
47222 if(!this.collapsed){
47223 this.el.dom.style.left = "-2000px";
47226 this.collapsedEl.dom.style.left = "-2000px";
47227 this.collapsedEl.hide();
47229 this.visible = false;
47230 this.fireEvent("visibilitychange", this, false);
47234 * Shows this region if it was previously hidden.
47237 if(!this.collapsed){
47240 this.collapsedEl.show();
47242 this.visible = true;
47243 this.fireEvent("visibilitychange", this, true);
47246 closeClicked : function(){
47247 if(this.activePanel){
47248 this.remove(this.activePanel);
47252 collapseClick : function(e){
47254 e.stopPropagation();
47257 e.stopPropagation();
47263 * Collapses this region.
47264 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
47266 collapse : function(skipAnim){
47267 if(this.collapsed) return;
47268 this.collapsed = true;
47270 this.split.el.hide();
47272 if(this.config.animate && skipAnim !== true){
47273 this.fireEvent("invalidated", this);
47274 this.animateCollapse();
47276 this.el.setLocation(-20000,-20000);
47278 this.collapsedEl.show();
47279 this.fireEvent("collapsed", this);
47280 this.fireEvent("invalidated", this);
47284 animateCollapse : function(){
47289 * Expands this region if it was previously collapsed.
47290 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
47291 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
47293 expand : function(e, skipAnim){
47294 if(e) e.stopPropagation();
47295 if(!this.collapsed || this.el.hasActiveFx()) return;
47297 this.afterSlideIn();
47300 this.collapsed = false;
47301 if(this.config.animate && skipAnim !== true){
47302 this.animateExpand();
47306 this.split.el.show();
47308 this.collapsedEl.setLocation(-2000,-2000);
47309 this.collapsedEl.hide();
47310 this.fireEvent("invalidated", this);
47311 this.fireEvent("expanded", this);
47315 animateExpand : function(){
47319 initTabs : function()
47321 this.bodyEl.setStyle("overflow", "hidden");
47322 var ts = new Roo.TabPanel(
47325 tabPosition: this.bottomTabs ? 'bottom' : 'top',
47326 disableTooltips: this.config.disableTabTips,
47327 toolbar : this.config.toolbar
47330 if(this.config.hideTabs){
47331 ts.stripWrap.setDisplayed(false);
47334 ts.resizeTabs = this.config.resizeTabs === true;
47335 ts.minTabWidth = this.config.minTabWidth || 40;
47336 ts.maxTabWidth = this.config.maxTabWidth || 250;
47337 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
47338 ts.monitorResize = false;
47339 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47340 ts.bodyEl.addClass('x-layout-tabs-body');
47341 this.panels.each(this.initPanelAsTab, this);
47344 initPanelAsTab : function(panel){
47345 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
47346 this.config.closeOnTab && panel.isClosable());
47347 if(panel.tabTip !== undefined){
47348 ti.setTooltip(panel.tabTip);
47350 ti.on("activate", function(){
47351 this.setActivePanel(panel);
47353 if(this.config.closeOnTab){
47354 ti.on("beforeclose", function(t, e){
47356 this.remove(panel);
47362 updatePanelTitle : function(panel, title){
47363 if(this.activePanel == panel){
47364 this.updateTitle(title);
47367 var ti = this.tabs.getTab(panel.getEl().id);
47369 if(panel.tabTip !== undefined){
47370 ti.setTooltip(panel.tabTip);
47375 updateTitle : function(title){
47376 if(this.titleTextEl && !this.config.title){
47377 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
47381 setActivePanel : function(panel){
47382 panel = this.getPanel(panel);
47383 if(this.activePanel && this.activePanel != panel){
47384 this.activePanel.setActiveState(false);
47386 this.activePanel = panel;
47387 panel.setActiveState(true);
47388 if(this.panelSize){
47389 panel.setSize(this.panelSize.width, this.panelSize.height);
47392 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
47394 this.updateTitle(panel.getTitle());
47396 this.fireEvent("invalidated", this);
47398 this.fireEvent("panelactivated", this, panel);
47402 * Shows the specified panel.
47403 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
47404 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
47406 showPanel : function(panel){
47407 if(panel = this.getPanel(panel)){
47409 var tab = this.tabs.getTab(panel.getEl().id);
47410 if(tab.isHidden()){
47411 this.tabs.unhideTab(tab.id);
47415 this.setActivePanel(panel);
47422 * Get the active panel for this region.
47423 * @return {Roo.ContentPanel} The active panel or null
47425 getActivePanel : function(){
47426 return this.activePanel;
47429 validateVisibility : function(){
47430 if(this.panels.getCount() < 1){
47431 this.updateTitle(" ");
47432 this.closeBtn.hide();
47435 if(!this.isVisible()){
47442 * Adds the passed ContentPanel(s) to this region.
47443 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
47444 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
47446 add : function(panel){
47447 if(arguments.length > 1){
47448 for(var i = 0, len = arguments.length; i < len; i++) {
47449 this.add(arguments[i]);
47453 if(this.hasPanel(panel)){
47454 this.showPanel(panel);
47457 panel.setRegion(this);
47458 this.panels.add(panel);
47459 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
47460 this.bodyEl.dom.appendChild(panel.getEl().dom);
47461 if(panel.background !== true){
47462 this.setActivePanel(panel);
47464 this.fireEvent("paneladded", this, panel);
47470 this.initPanelAsTab(panel);
47472 if(panel.background !== true){
47473 this.tabs.activate(panel.getEl().id);
47475 this.fireEvent("paneladded", this, panel);
47480 * Hides the tab for the specified panel.
47481 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47483 hidePanel : function(panel){
47484 if(this.tabs && (panel = this.getPanel(panel))){
47485 this.tabs.hideTab(panel.getEl().id);
47490 * Unhides the tab for a previously hidden panel.
47491 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47493 unhidePanel : function(panel){
47494 if(this.tabs && (panel = this.getPanel(panel))){
47495 this.tabs.unhideTab(panel.getEl().id);
47499 clearPanels : function(){
47500 while(this.panels.getCount() > 0){
47501 this.remove(this.panels.first());
47506 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
47507 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47508 * @param {Boolean} preservePanel Overrides the config preservePanel option
47509 * @return {Roo.ContentPanel} The panel that was removed
47511 remove : function(panel, preservePanel){
47512 panel = this.getPanel(panel);
47517 this.fireEvent("beforeremove", this, panel, e);
47518 if(e.cancel === true){
47521 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
47522 var panelId = panel.getId();
47523 this.panels.removeKey(panelId);
47525 document.body.appendChild(panel.getEl().dom);
47528 this.tabs.removeTab(panel.getEl().id);
47529 }else if (!preservePanel){
47530 this.bodyEl.dom.removeChild(panel.getEl().dom);
47532 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
47533 var p = this.panels.first();
47534 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
47535 tempEl.appendChild(p.getEl().dom);
47536 this.bodyEl.update("");
47537 this.bodyEl.dom.appendChild(p.getEl().dom);
47539 this.updateTitle(p.getTitle());
47541 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47542 this.setActivePanel(p);
47544 panel.setRegion(null);
47545 if(this.activePanel == panel){
47546 this.activePanel = null;
47548 if(this.config.autoDestroy !== false && preservePanel !== true){
47549 try{panel.destroy();}catch(e){}
47551 this.fireEvent("panelremoved", this, panel);
47556 * Returns the TabPanel component used by this region
47557 * @return {Roo.TabPanel}
47559 getTabs : function(){
47563 createTool : function(parentEl, className){
47564 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
47565 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
47566 btn.addClassOnOver("x-layout-tools-button-over");
47571 * Ext JS Library 1.1.1
47572 * Copyright(c) 2006-2007, Ext JS, LLC.
47574 * Originally Released Under LGPL - original licence link has changed is not relivant.
47577 * <script type="text/javascript">
47583 * @class Roo.SplitLayoutRegion
47584 * @extends Roo.LayoutRegion
47585 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
47587 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
47588 this.cursor = cursor;
47589 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
47592 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
47593 splitTip : "Drag to resize.",
47594 collapsibleSplitTip : "Drag to resize. Double click to hide.",
47595 useSplitTips : false,
47597 applyConfig : function(config){
47598 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
47601 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
47602 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
47603 /** The SplitBar for this region
47604 * @type Roo.SplitBar */
47605 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
47606 this.split.on("moved", this.onSplitMove, this);
47607 this.split.useShim = config.useShim === true;
47608 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
47609 if(this.useSplitTips){
47610 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
47612 if(config.collapsible){
47613 this.split.el.on("dblclick", this.collapse, this);
47616 if(typeof config.minSize != "undefined"){
47617 this.split.minSize = config.minSize;
47619 if(typeof config.maxSize != "undefined"){
47620 this.split.maxSize = config.maxSize;
47622 if(config.hideWhenEmpty || config.hidden || config.collapsed){
47623 this.hideSplitter();
47628 getHMaxSize : function(){
47629 var cmax = this.config.maxSize || 10000;
47630 var center = this.mgr.getRegion("center");
47631 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
47634 getVMaxSize : function(){
47635 var cmax = this.config.maxSize || 10000;
47636 var center = this.mgr.getRegion("center");
47637 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
47640 onSplitMove : function(split, newSize){
47641 this.fireEvent("resized", this, newSize);
47645 * Returns the {@link Roo.SplitBar} for this region.
47646 * @return {Roo.SplitBar}
47648 getSplitBar : function(){
47653 this.hideSplitter();
47654 Roo.SplitLayoutRegion.superclass.hide.call(this);
47657 hideSplitter : function(){
47659 this.split.el.setLocation(-2000,-2000);
47660 this.split.el.hide();
47666 this.split.el.show();
47668 Roo.SplitLayoutRegion.superclass.show.call(this);
47671 beforeSlide: function(){
47672 if(Roo.isGecko){// firefox overflow auto bug workaround
47673 this.bodyEl.clip();
47674 if(this.tabs) this.tabs.bodyEl.clip();
47675 if(this.activePanel){
47676 this.activePanel.getEl().clip();
47678 if(this.activePanel.beforeSlide){
47679 this.activePanel.beforeSlide();
47685 afterSlide : function(){
47686 if(Roo.isGecko){// firefox overflow auto bug workaround
47687 this.bodyEl.unclip();
47688 if(this.tabs) this.tabs.bodyEl.unclip();
47689 if(this.activePanel){
47690 this.activePanel.getEl().unclip();
47691 if(this.activePanel.afterSlide){
47692 this.activePanel.afterSlide();
47698 initAutoHide : function(){
47699 if(this.autoHide !== false){
47700 if(!this.autoHideHd){
47701 var st = new Roo.util.DelayedTask(this.slideIn, this);
47702 this.autoHideHd = {
47703 "mouseout": function(e){
47704 if(!e.within(this.el, true)){
47708 "mouseover" : function(e){
47714 this.el.on(this.autoHideHd);
47718 clearAutoHide : function(){
47719 if(this.autoHide !== false){
47720 this.el.un("mouseout", this.autoHideHd.mouseout);
47721 this.el.un("mouseover", this.autoHideHd.mouseover);
47725 clearMonitor : function(){
47726 Roo.get(document).un("click", this.slideInIf, this);
47729 // these names are backwards but not changed for compat
47730 slideOut : function(){
47731 if(this.isSlid || this.el.hasActiveFx()){
47734 this.isSlid = true;
47735 if(this.collapseBtn){
47736 this.collapseBtn.hide();
47738 this.closeBtnState = this.closeBtn.getStyle('display');
47739 this.closeBtn.hide();
47741 this.stickBtn.show();
47744 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
47745 this.beforeSlide();
47746 this.el.setStyle("z-index", 10001);
47747 this.el.slideIn(this.getSlideAnchor(), {
47748 callback: function(){
47750 this.initAutoHide();
47751 Roo.get(document).on("click", this.slideInIf, this);
47752 this.fireEvent("slideshow", this);
47759 afterSlideIn : function(){
47760 this.clearAutoHide();
47761 this.isSlid = false;
47762 this.clearMonitor();
47763 this.el.setStyle("z-index", "");
47764 if(this.collapseBtn){
47765 this.collapseBtn.show();
47767 this.closeBtn.setStyle('display', this.closeBtnState);
47769 this.stickBtn.hide();
47771 this.fireEvent("slidehide", this);
47774 slideIn : function(cb){
47775 if(!this.isSlid || this.el.hasActiveFx()){
47779 this.isSlid = false;
47780 this.beforeSlide();
47781 this.el.slideOut(this.getSlideAnchor(), {
47782 callback: function(){
47783 this.el.setLeftTop(-10000, -10000);
47785 this.afterSlideIn();
47793 slideInIf : function(e){
47794 if(!e.within(this.el)){
47799 animateCollapse : function(){
47800 this.beforeSlide();
47801 this.el.setStyle("z-index", 20000);
47802 var anchor = this.getSlideAnchor();
47803 this.el.slideOut(anchor, {
47804 callback : function(){
47805 this.el.setStyle("z-index", "");
47806 this.collapsedEl.slideIn(anchor, {duration:.3});
47808 this.el.setLocation(-10000,-10000);
47810 this.fireEvent("collapsed", this);
47817 animateExpand : function(){
47818 this.beforeSlide();
47819 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
47820 this.el.setStyle("z-index", 20000);
47821 this.collapsedEl.hide({
47824 this.el.slideIn(this.getSlideAnchor(), {
47825 callback : function(){
47826 this.el.setStyle("z-index", "");
47829 this.split.el.show();
47831 this.fireEvent("invalidated", this);
47832 this.fireEvent("expanded", this);
47860 getAnchor : function(){
47861 return this.anchors[this.position];
47864 getCollapseAnchor : function(){
47865 return this.canchors[this.position];
47868 getSlideAnchor : function(){
47869 return this.sanchors[this.position];
47872 getAlignAdj : function(){
47873 var cm = this.cmargins;
47874 switch(this.position){
47890 getExpandAdj : function(){
47891 var c = this.collapsedEl, cm = this.cmargins;
47892 switch(this.position){
47894 return [-(cm.right+c.getWidth()+cm.left), 0];
47897 return [cm.right+c.getWidth()+cm.left, 0];
47900 return [0, -(cm.top+cm.bottom+c.getHeight())];
47903 return [0, cm.top+cm.bottom+c.getHeight()];
47909 * Ext JS Library 1.1.1
47910 * Copyright(c) 2006-2007, Ext JS, LLC.
47912 * Originally Released Under LGPL - original licence link has changed is not relivant.
47915 * <script type="text/javascript">
47918 * These classes are private internal classes
47920 Roo.CenterLayoutRegion = function(mgr, config){
47921 Roo.LayoutRegion.call(this, mgr, config, "center");
47922 this.visible = true;
47923 this.minWidth = config.minWidth || 20;
47924 this.minHeight = config.minHeight || 20;
47927 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
47929 // center panel can't be hidden
47933 // center panel can't be hidden
47936 getMinWidth: function(){
47937 return this.minWidth;
47940 getMinHeight: function(){
47941 return this.minHeight;
47946 Roo.NorthLayoutRegion = function(mgr, config){
47947 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
47949 this.split.placement = Roo.SplitBar.TOP;
47950 this.split.orientation = Roo.SplitBar.VERTICAL;
47951 this.split.el.addClass("x-layout-split-v");
47953 var size = config.initialSize || config.height;
47954 if(typeof size != "undefined"){
47955 this.el.setHeight(size);
47958 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
47959 orientation: Roo.SplitBar.VERTICAL,
47960 getBox : function(){
47961 if(this.collapsed){
47962 return this.collapsedEl.getBox();
47964 var box = this.el.getBox();
47966 box.height += this.split.el.getHeight();
47971 updateBox : function(box){
47972 if(this.split && !this.collapsed){
47973 box.height -= this.split.el.getHeight();
47974 this.split.el.setLeft(box.x);
47975 this.split.el.setTop(box.y+box.height);
47976 this.split.el.setWidth(box.width);
47978 if(this.collapsed){
47979 this.updateBody(box.width, null);
47981 Roo.LayoutRegion.prototype.updateBox.call(this, box);
47985 Roo.SouthLayoutRegion = function(mgr, config){
47986 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
47988 this.split.placement = Roo.SplitBar.BOTTOM;
47989 this.split.orientation = Roo.SplitBar.VERTICAL;
47990 this.split.el.addClass("x-layout-split-v");
47992 var size = config.initialSize || config.height;
47993 if(typeof size != "undefined"){
47994 this.el.setHeight(size);
47997 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
47998 orientation: Roo.SplitBar.VERTICAL,
47999 getBox : function(){
48000 if(this.collapsed){
48001 return this.collapsedEl.getBox();
48003 var box = this.el.getBox();
48005 var sh = this.split.el.getHeight();
48012 updateBox : function(box){
48013 if(this.split && !this.collapsed){
48014 var sh = this.split.el.getHeight();
48017 this.split.el.setLeft(box.x);
48018 this.split.el.setTop(box.y-sh);
48019 this.split.el.setWidth(box.width);
48021 if(this.collapsed){
48022 this.updateBody(box.width, null);
48024 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48028 Roo.EastLayoutRegion = function(mgr, config){
48029 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
48031 this.split.placement = Roo.SplitBar.RIGHT;
48032 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48033 this.split.el.addClass("x-layout-split-h");
48035 var size = config.initialSize || config.width;
48036 if(typeof size != "undefined"){
48037 this.el.setWidth(size);
48040 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
48041 orientation: Roo.SplitBar.HORIZONTAL,
48042 getBox : function(){
48043 if(this.collapsed){
48044 return this.collapsedEl.getBox();
48046 var box = this.el.getBox();
48048 var sw = this.split.el.getWidth();
48055 updateBox : function(box){
48056 if(this.split && !this.collapsed){
48057 var sw = this.split.el.getWidth();
48059 this.split.el.setLeft(box.x);
48060 this.split.el.setTop(box.y);
48061 this.split.el.setHeight(box.height);
48064 if(this.collapsed){
48065 this.updateBody(null, box.height);
48067 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48071 Roo.WestLayoutRegion = function(mgr, config){
48072 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
48074 this.split.placement = Roo.SplitBar.LEFT;
48075 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48076 this.split.el.addClass("x-layout-split-h");
48078 var size = config.initialSize || config.width;
48079 if(typeof size != "undefined"){
48080 this.el.setWidth(size);
48083 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
48084 orientation: Roo.SplitBar.HORIZONTAL,
48085 getBox : function(){
48086 if(this.collapsed){
48087 return this.collapsedEl.getBox();
48089 var box = this.el.getBox();
48091 box.width += this.split.el.getWidth();
48096 updateBox : function(box){
48097 if(this.split && !this.collapsed){
48098 var sw = this.split.el.getWidth();
48100 this.split.el.setLeft(box.x+box.width);
48101 this.split.el.setTop(box.y);
48102 this.split.el.setHeight(box.height);
48104 if(this.collapsed){
48105 this.updateBody(null, box.height);
48107 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48112 * Ext JS Library 1.1.1
48113 * Copyright(c) 2006-2007, Ext JS, LLC.
48115 * Originally Released Under LGPL - original licence link has changed is not relivant.
48118 * <script type="text/javascript">
48123 * Private internal class for reading and applying state
48125 Roo.LayoutStateManager = function(layout){
48126 // default empty state
48135 Roo.LayoutStateManager.prototype = {
48136 init : function(layout, provider){
48137 this.provider = provider;
48138 var state = provider.get(layout.id+"-layout-state");
48140 var wasUpdating = layout.isUpdating();
48142 layout.beginUpdate();
48144 for(var key in state){
48145 if(typeof state[key] != "function"){
48146 var rstate = state[key];
48147 var r = layout.getRegion(key);
48150 r.resizeTo(rstate.size);
48152 if(rstate.collapsed == true){
48155 r.expand(null, true);
48161 layout.endUpdate();
48163 this.state = state;
48165 this.layout = layout;
48166 layout.on("regionresized", this.onRegionResized, this);
48167 layout.on("regioncollapsed", this.onRegionCollapsed, this);
48168 layout.on("regionexpanded", this.onRegionExpanded, this);
48171 storeState : function(){
48172 this.provider.set(this.layout.id+"-layout-state", this.state);
48175 onRegionResized : function(region, newSize){
48176 this.state[region.getPosition()].size = newSize;
48180 onRegionCollapsed : function(region){
48181 this.state[region.getPosition()].collapsed = true;
48185 onRegionExpanded : function(region){
48186 this.state[region.getPosition()].collapsed = false;
48191 * Ext JS Library 1.1.1
48192 * Copyright(c) 2006-2007, Ext JS, LLC.
48194 * Originally Released Under LGPL - original licence link has changed is not relivant.
48197 * <script type="text/javascript">
48200 * @class Roo.ContentPanel
48201 * @extends Roo.util.Observable
48202 * A basic ContentPanel element.
48203 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
48204 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
48205 * @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
48206 * @cfg {Boolean} closable True if the panel can be closed/removed
48207 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
48208 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
48209 * @cfg {Toolbar} toolbar A toolbar for this panel
48210 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
48211 * @cfg {String} title The title for this panel
48212 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
48213 * @cfg {String} url Calls {@link #setUrl} with this value
48214 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
48215 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
48216 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
48217 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
48220 * Create a new ContentPanel.
48221 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
48222 * @param {String/Object} config A string to set only the title or a config object
48223 * @param {String} content (optional) Set the HTML content for this panel
48224 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
48226 Roo.ContentPanel = function(el, config, content){
48230 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
48234 if (config && config.parentLayout) {
48235 el = config.parentLayout.el.createChild();
48238 if(el.autoCreate){ // xtype is available if this is called from factory
48242 this.el = Roo.get(el);
48243 if(!this.el && config && config.autoCreate){
48244 if(typeof config.autoCreate == "object"){
48245 if(!config.autoCreate.id){
48246 config.autoCreate.id = config.id||el;
48248 this.el = Roo.DomHelper.append(document.body,
48249 config.autoCreate, true);
48251 this.el = Roo.DomHelper.append(document.body,
48252 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
48255 this.closable = false;
48256 this.loaded = false;
48257 this.active = false;
48258 if(typeof config == "string"){
48259 this.title = config;
48261 Roo.apply(this, config);
48264 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
48265 this.wrapEl = this.el.wrap();
48266 this.toolbar.container = this.el.insertSibling(false, 'before');
48267 this.toolbar = new Roo.Toolbar(this.toolbar);
48270 // xtype created footer. - not sure if will work as we normally have to render first..
48271 if (this.footer && !this.footer.el && this.footer.xtype) {
48272 if (!this.wrapEl) {
48273 this.wrapEl = this.el.wrap();
48276 this.footer.container = this.wrapEl.createChild();
48278 this.footer = Roo.factory(this.footer, Roo);
48283 this.resizeEl = Roo.get(this.resizeEl, true);
48285 this.resizeEl = this.el;
48287 // handle view.xtype
48289 if (this.view && typeof(this.view.xtype) != 'undefined') {
48290 this.view.el = this.el.appendChild(document.createElement("div"));
48291 this.view = Roo.factory(this.view);
48292 this.view.render && this.view.render(false, ''); // render blank..
48300 * Fires when this panel is activated.
48301 * @param {Roo.ContentPanel} this
48305 * @event deactivate
48306 * Fires when this panel is activated.
48307 * @param {Roo.ContentPanel} this
48309 "deactivate" : true,
48313 * Fires when this panel is resized if fitToFrame is true.
48314 * @param {Roo.ContentPanel} this
48315 * @param {Number} width The width after any component adjustments
48316 * @param {Number} height The height after any component adjustments
48322 * Fires when this tab is created
48323 * @param {Roo.ContentPanel} this
48330 if(this.autoScroll){
48331 this.resizeEl.setStyle("overflow", "auto");
48333 // fix randome scrolling
48334 this.el.on('scroll', function() {
48335 Roo.log('fix random scolling');
48336 this.scrollTo('top',0);
48339 content = content || this.content;
48341 this.setContent(content);
48343 if(config && config.url){
48344 this.setUrl(this.url, this.params, this.loadOnce);
48349 Roo.ContentPanel.superclass.constructor.call(this);
48351 this.fireEvent('render', this);
48354 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
48356 setRegion : function(region){
48357 this.region = region;
48359 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
48361 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
48366 * Returns the toolbar for this Panel if one was configured.
48367 * @return {Roo.Toolbar}
48369 getToolbar : function(){
48370 return this.toolbar;
48373 setActiveState : function(active){
48374 this.active = active;
48376 this.fireEvent("deactivate", this);
48378 this.fireEvent("activate", this);
48382 * Updates this panel's element
48383 * @param {String} content The new content
48384 * @param {Boolean} loadScripts (optional) true to look for and process scripts
48386 setContent : function(content, loadScripts){
48387 this.el.update(content, loadScripts);
48390 ignoreResize : function(w, h){
48391 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
48394 this.lastSize = {width: w, height: h};
48399 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
48400 * @return {Roo.UpdateManager} The UpdateManager
48402 getUpdateManager : function(){
48403 return this.el.getUpdateManager();
48406 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
48407 * @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:
48410 url: "your-url.php",
48411 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
48412 callback: yourFunction,
48413 scope: yourObject, //(optional scope)
48416 text: "Loading...",
48421 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
48422 * 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.
48423 * @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}
48424 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
48425 * @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.
48426 * @return {Roo.ContentPanel} this
48429 var um = this.el.getUpdateManager();
48430 um.update.apply(um, arguments);
48436 * 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.
48437 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
48438 * @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)
48439 * @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)
48440 * @return {Roo.UpdateManager} The UpdateManager
48442 setUrl : function(url, params, loadOnce){
48443 if(this.refreshDelegate){
48444 this.removeListener("activate", this.refreshDelegate);
48446 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
48447 this.on("activate", this.refreshDelegate);
48448 return this.el.getUpdateManager();
48451 _handleRefresh : function(url, params, loadOnce){
48452 if(!loadOnce || !this.loaded){
48453 var updater = this.el.getUpdateManager();
48454 updater.update(url, params, this._setLoaded.createDelegate(this));
48458 _setLoaded : function(){
48459 this.loaded = true;
48463 * Returns this panel's id
48466 getId : function(){
48471 * Returns this panel's element - used by regiosn to add.
48472 * @return {Roo.Element}
48474 getEl : function(){
48475 return this.wrapEl || this.el;
48478 adjustForComponents : function(width, height)
48480 Roo.log('adjustForComponents ');
48481 if(this.resizeEl != this.el){
48482 width -= this.el.getFrameWidth('lr');
48483 height -= this.el.getFrameWidth('tb');
48486 var te = this.toolbar.getEl();
48487 height -= te.getHeight();
48488 te.setWidth(width);
48491 var te = this.footer.getEl();
48492 Roo.log("footer:" + te.getHeight());
48494 height -= te.getHeight();
48495 te.setWidth(width);
48499 if(this.adjustments){
48500 width += this.adjustments[0];
48501 height += this.adjustments[1];
48503 return {"width": width, "height": height};
48506 setSize : function(width, height){
48507 if(this.fitToFrame && !this.ignoreResize(width, height)){
48508 if(this.fitContainer && this.resizeEl != this.el){
48509 this.el.setSize(width, height);
48511 var size = this.adjustForComponents(width, height);
48512 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
48513 this.fireEvent('resize', this, size.width, size.height);
48518 * Returns this panel's title
48521 getTitle : function(){
48526 * Set this panel's title
48527 * @param {String} title
48529 setTitle : function(title){
48530 this.title = title;
48532 this.region.updatePanelTitle(this, title);
48537 * Returns true is this panel was configured to be closable
48538 * @return {Boolean}
48540 isClosable : function(){
48541 return this.closable;
48544 beforeSlide : function(){
48546 this.resizeEl.clip();
48549 afterSlide : function(){
48551 this.resizeEl.unclip();
48555 * Force a content refresh from the URL specified in the {@link #setUrl} method.
48556 * Will fail silently if the {@link #setUrl} method has not been called.
48557 * This does not activate the panel, just updates its content.
48559 refresh : function(){
48560 if(this.refreshDelegate){
48561 this.loaded = false;
48562 this.refreshDelegate();
48567 * Destroys this panel
48569 destroy : function(){
48570 this.el.removeAllListeners();
48571 var tempEl = document.createElement("span");
48572 tempEl.appendChild(this.el.dom);
48573 tempEl.innerHTML = "";
48579 * form - if the content panel contains a form - this is a reference to it.
48580 * @type {Roo.form.Form}
48584 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
48585 * This contains a reference to it.
48591 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
48601 * @param {Object} cfg Xtype definition of item to add.
48604 addxtype : function(cfg) {
48606 if (cfg.xtype.match(/^Form$/)) {
48609 //if (this.footer) {
48610 // el = this.footer.container.insertSibling(false, 'before');
48612 el = this.el.createChild();
48615 this.form = new Roo.form.Form(cfg);
48618 if ( this.form.allItems.length) this.form.render(el.dom);
48621 // should only have one of theses..
48622 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
48624 cfg.el = this.el.appendChild(document.createElement("div"));
48627 var ret = new Roo.factory(cfg);
48628 ret.render && ret.render(false, ''); // render blank..
48637 * @class Roo.GridPanel
48638 * @extends Roo.ContentPanel
48640 * Create a new GridPanel.
48641 * @param {Roo.grid.Grid} grid The grid for this panel
48642 * @param {String/Object} config A string to set only the panel's title, or a config object
48644 Roo.GridPanel = function(grid, config){
48647 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
48648 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
48650 this.wrapper.dom.appendChild(grid.getGridEl().dom);
48652 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
48655 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
48657 // xtype created footer. - not sure if will work as we normally have to render first..
48658 if (this.footer && !this.footer.el && this.footer.xtype) {
48660 this.footer.container = this.grid.getView().getFooterPanel(true);
48661 this.footer.dataSource = this.grid.dataSource;
48662 this.footer = Roo.factory(this.footer, Roo);
48666 grid.monitorWindowResize = false; // turn off autosizing
48667 grid.autoHeight = false;
48668 grid.autoWidth = false;
48670 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
48673 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
48674 getId : function(){
48675 return this.grid.id;
48679 * Returns the grid for this panel
48680 * @return {Roo.grid.Grid}
48682 getGrid : function(){
48686 setSize : function(width, height){
48687 if(!this.ignoreResize(width, height)){
48688 var grid = this.grid;
48689 var size = this.adjustForComponents(width, height);
48690 grid.getGridEl().setSize(size.width, size.height);
48695 beforeSlide : function(){
48696 this.grid.getView().scroller.clip();
48699 afterSlide : function(){
48700 this.grid.getView().scroller.unclip();
48703 destroy : function(){
48704 this.grid.destroy();
48706 Roo.GridPanel.superclass.destroy.call(this);
48712 * @class Roo.NestedLayoutPanel
48713 * @extends Roo.ContentPanel
48715 * Create a new NestedLayoutPanel.
48718 * @param {Roo.BorderLayout} layout The layout for this panel
48719 * @param {String/Object} config A string to set only the title or a config object
48721 Roo.NestedLayoutPanel = function(layout, config)
48723 // construct with only one argument..
48724 /* FIXME - implement nicer consturctors
48725 if (layout.layout) {
48727 layout = config.layout;
48728 delete config.layout;
48730 if (layout.xtype && !layout.getEl) {
48731 // then layout needs constructing..
48732 layout = Roo.factory(layout, Roo);
48737 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
48739 layout.monitorWindowResize = false; // turn off autosizing
48740 this.layout = layout;
48741 this.layout.getEl().addClass("x-layout-nested-layout");
48748 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
48750 setSize : function(width, height){
48751 if(!this.ignoreResize(width, height)){
48752 var size = this.adjustForComponents(width, height);
48753 var el = this.layout.getEl();
48754 el.setSize(size.width, size.height);
48755 var touch = el.dom.offsetWidth;
48756 this.layout.layout();
48757 // ie requires a double layout on the first pass
48758 if(Roo.isIE && !this.initialized){
48759 this.initialized = true;
48760 this.layout.layout();
48765 // activate all subpanels if not currently active..
48767 setActiveState : function(active){
48768 this.active = active;
48770 this.fireEvent("deactivate", this);
48774 this.fireEvent("activate", this);
48775 // not sure if this should happen before or after..
48776 if (!this.layout) {
48777 return; // should not happen..
48780 for (var r in this.layout.regions) {
48781 reg = this.layout.getRegion(r);
48782 if (reg.getActivePanel()) {
48783 //reg.showPanel(reg.getActivePanel()); // force it to activate..
48784 reg.setActivePanel(reg.getActivePanel());
48787 if (!reg.panels.length) {
48790 reg.showPanel(reg.getPanel(0));
48799 * Returns the nested BorderLayout for this panel
48800 * @return {Roo.BorderLayout}
48802 getLayout : function(){
48803 return this.layout;
48807 * Adds a xtype elements to the layout of the nested panel
48811 xtype : 'ContentPanel',
48818 xtype : 'NestedLayoutPanel',
48824 items : [ ... list of content panels or nested layout panels.. ]
48828 * @param {Object} cfg Xtype definition of item to add.
48830 addxtype : function(cfg) {
48831 return this.layout.addxtype(cfg);
48836 Roo.ScrollPanel = function(el, config, content){
48837 config = config || {};
48838 config.fitToFrame = true;
48839 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
48841 this.el.dom.style.overflow = "hidden";
48842 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
48843 this.el.removeClass("x-layout-inactive-content");
48844 this.el.on("mousewheel", this.onWheel, this);
48846 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
48847 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
48848 up.unselectable(); down.unselectable();
48849 up.on("click", this.scrollUp, this);
48850 down.on("click", this.scrollDown, this);
48851 up.addClassOnOver("x-scroller-btn-over");
48852 down.addClassOnOver("x-scroller-btn-over");
48853 up.addClassOnClick("x-scroller-btn-click");
48854 down.addClassOnClick("x-scroller-btn-click");
48855 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
48857 this.resizeEl = this.el;
48858 this.el = wrap; this.up = up; this.down = down;
48861 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
48863 wheelIncrement : 5,
48864 scrollUp : function(){
48865 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
48868 scrollDown : function(){
48869 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
48872 afterScroll : function(){
48873 var el = this.resizeEl;
48874 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
48875 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
48876 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
48879 setSize : function(){
48880 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
48881 this.afterScroll();
48884 onWheel : function(e){
48885 var d = e.getWheelDelta();
48886 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
48887 this.afterScroll();
48891 setContent : function(content, loadScripts){
48892 this.resizeEl.update(content, loadScripts);
48906 * @class Roo.TreePanel
48907 * @extends Roo.ContentPanel
48909 * Create a new TreePanel. - defaults to fit/scoll contents.
48910 * @param {String/Object} config A string to set only the panel's title, or a config object
48911 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
48913 Roo.TreePanel = function(config){
48914 var el = config.el;
48915 var tree = config.tree;
48916 delete config.tree;
48917 delete config.el; // hopefull!
48919 // wrapper for IE7 strict & safari scroll issue
48921 var treeEl = el.createChild();
48922 config.resizeEl = treeEl;
48926 Roo.TreePanel.superclass.constructor.call(this, el, config);
48929 this.tree = new Roo.tree.TreePanel(treeEl , tree);
48930 //console.log(tree);
48931 this.on('activate', function()
48933 if (this.tree.rendered) {
48936 //console.log('render tree');
48937 this.tree.render();
48939 // this should not be needed.. - it's actually the 'el' that resizes?
48940 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
48942 //this.on('resize', function (cp, w, h) {
48943 // this.tree.innerCt.setWidth(w);
48944 // this.tree.innerCt.setHeight(h);
48945 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
48952 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
48969 * Ext JS Library 1.1.1
48970 * Copyright(c) 2006-2007, Ext JS, LLC.
48972 * Originally Released Under LGPL - original licence link has changed is not relivant.
48975 * <script type="text/javascript">
48980 * @class Roo.ReaderLayout
48981 * @extends Roo.BorderLayout
48982 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
48983 * center region containing two nested regions (a top one for a list view and one for item preview below),
48984 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
48985 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
48986 * expedites the setup of the overall layout and regions for this common application style.
48989 var reader = new Roo.ReaderLayout();
48990 var CP = Roo.ContentPanel; // shortcut for adding
48992 reader.beginUpdate();
48993 reader.add("north", new CP("north", "North"));
48994 reader.add("west", new CP("west", {title: "West"}));
48995 reader.add("east", new CP("east", {title: "East"}));
48997 reader.regions.listView.add(new CP("listView", "List"));
48998 reader.regions.preview.add(new CP("preview", "Preview"));
48999 reader.endUpdate();
49002 * Create a new ReaderLayout
49003 * @param {Object} config Configuration options
49004 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
49005 * document.body if omitted)
49007 Roo.ReaderLayout = function(config, renderTo){
49008 var c = config || {size:{}};
49009 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
49010 north: c.north !== false ? Roo.apply({
49014 }, c.north) : false,
49015 west: c.west !== false ? Roo.apply({
49023 margins:{left:5,right:0,bottom:5,top:5},
49024 cmargins:{left:5,right:5,bottom:5,top:5}
49025 }, c.west) : false,
49026 east: c.east !== false ? Roo.apply({
49034 margins:{left:0,right:5,bottom:5,top:5},
49035 cmargins:{left:5,right:5,bottom:5,top:5}
49036 }, c.east) : false,
49037 center: Roo.apply({
49038 tabPosition: 'top',
49042 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
49046 this.el.addClass('x-reader');
49048 this.beginUpdate();
49050 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
49051 south: c.preview !== false ? Roo.apply({
49058 cmargins:{top:5,left:0, right:0, bottom:0}
49059 }, c.preview) : false,
49060 center: Roo.apply({
49066 this.add('center', new Roo.NestedLayoutPanel(inner,
49067 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
49071 this.regions.preview = inner.getRegion('south');
49072 this.regions.listView = inner.getRegion('center');
49075 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
49077 * Ext JS Library 1.1.1
49078 * Copyright(c) 2006-2007, Ext JS, LLC.
49080 * Originally Released Under LGPL - original licence link has changed is not relivant.
49083 * <script type="text/javascript">
49087 * @class Roo.grid.Grid
49088 * @extends Roo.util.Observable
49089 * This class represents the primary interface of a component based grid control.
49090 * <br><br>Usage:<pre><code>
49091 var grid = new Roo.grid.Grid("my-container-id", {
49094 selModel: mySelectionModel,
49095 autoSizeColumns: true,
49096 monitorWindowResize: false,
49097 trackMouseOver: true
49102 * <b>Common Problems:</b><br/>
49103 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
49104 * element will correct this<br/>
49105 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
49106 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
49107 * are unpredictable.<br/>
49108 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
49109 * grid to calculate dimensions/offsets.<br/>
49111 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49112 * The container MUST have some type of size defined for the grid to fill. The container will be
49113 * automatically set to position relative if it isn't already.
49114 * @param {Object} config A config object that sets properties on this grid.
49116 Roo.grid.Grid = function(container, config){
49117 // initialize the container
49118 this.container = Roo.get(container);
49119 this.container.update("");
49120 this.container.setStyle("overflow", "hidden");
49121 this.container.addClass('x-grid-container');
49123 this.id = this.container.id;
49125 Roo.apply(this, config);
49126 // check and correct shorthanded configs
49128 this.dataSource = this.ds;
49132 this.colModel = this.cm;
49136 this.selModel = this.sm;
49140 if (this.selModel) {
49141 this.selModel = Roo.factory(this.selModel, Roo.grid);
49142 this.sm = this.selModel;
49143 this.sm.xmodule = this.xmodule || false;
49145 if (typeof(this.colModel.config) == 'undefined') {
49146 this.colModel = new Roo.grid.ColumnModel(this.colModel);
49147 this.cm = this.colModel;
49148 this.cm.xmodule = this.xmodule || false;
49150 if (this.dataSource) {
49151 this.dataSource= Roo.factory(this.dataSource, Roo.data);
49152 this.ds = this.dataSource;
49153 this.ds.xmodule = this.xmodule || false;
49160 this.container.setWidth(this.width);
49164 this.container.setHeight(this.height);
49171 * The raw click event for the entire grid.
49172 * @param {Roo.EventObject} e
49177 * The raw dblclick event for the entire grid.
49178 * @param {Roo.EventObject} e
49182 * @event contextmenu
49183 * The raw contextmenu event for the entire grid.
49184 * @param {Roo.EventObject} e
49186 "contextmenu" : true,
49189 * The raw mousedown event for the entire grid.
49190 * @param {Roo.EventObject} e
49192 "mousedown" : true,
49195 * The raw mouseup event for the entire grid.
49196 * @param {Roo.EventObject} e
49201 * The raw mouseover event for the entire grid.
49202 * @param {Roo.EventObject} e
49204 "mouseover" : true,
49207 * The raw mouseout event for the entire grid.
49208 * @param {Roo.EventObject} e
49213 * The raw keypress event for the entire grid.
49214 * @param {Roo.EventObject} e
49219 * The raw keydown event for the entire grid.
49220 * @param {Roo.EventObject} e
49228 * Fires when a cell is clicked
49229 * @param {Grid} this
49230 * @param {Number} rowIndex
49231 * @param {Number} columnIndex
49232 * @param {Roo.EventObject} e
49234 "cellclick" : true,
49236 * @event celldblclick
49237 * Fires when a cell is double clicked
49238 * @param {Grid} this
49239 * @param {Number} rowIndex
49240 * @param {Number} columnIndex
49241 * @param {Roo.EventObject} e
49243 "celldblclick" : true,
49246 * Fires when a row is clicked
49247 * @param {Grid} this
49248 * @param {Number} rowIndex
49249 * @param {Roo.EventObject} e
49253 * @event rowdblclick
49254 * Fires when a row is double clicked
49255 * @param {Grid} this
49256 * @param {Number} rowIndex
49257 * @param {Roo.EventObject} e
49259 "rowdblclick" : true,
49261 * @event headerclick
49262 * Fires when a header is clicked
49263 * @param {Grid} this
49264 * @param {Number} columnIndex
49265 * @param {Roo.EventObject} e
49267 "headerclick" : true,
49269 * @event headerdblclick
49270 * Fires when a header cell is double clicked
49271 * @param {Grid} this
49272 * @param {Number} columnIndex
49273 * @param {Roo.EventObject} e
49275 "headerdblclick" : true,
49277 * @event rowcontextmenu
49278 * Fires when a row is right clicked
49279 * @param {Grid} this
49280 * @param {Number} rowIndex
49281 * @param {Roo.EventObject} e
49283 "rowcontextmenu" : true,
49285 * @event cellcontextmenu
49286 * Fires when a cell is right clicked
49287 * @param {Grid} this
49288 * @param {Number} rowIndex
49289 * @param {Number} cellIndex
49290 * @param {Roo.EventObject} e
49292 "cellcontextmenu" : true,
49294 * @event headercontextmenu
49295 * Fires when a header is right clicked
49296 * @param {Grid} this
49297 * @param {Number} columnIndex
49298 * @param {Roo.EventObject} e
49300 "headercontextmenu" : true,
49302 * @event bodyscroll
49303 * Fires when the body element is scrolled
49304 * @param {Number} scrollLeft
49305 * @param {Number} scrollTop
49307 "bodyscroll" : true,
49309 * @event columnresize
49310 * Fires when the user resizes a column
49311 * @param {Number} columnIndex
49312 * @param {Number} newSize
49314 "columnresize" : true,
49316 * @event columnmove
49317 * Fires when the user moves a column
49318 * @param {Number} oldIndex
49319 * @param {Number} newIndex
49321 "columnmove" : true,
49324 * Fires when row(s) start being dragged
49325 * @param {Grid} this
49326 * @param {Roo.GridDD} dd The drag drop object
49327 * @param {event} e The raw browser event
49329 "startdrag" : true,
49332 * Fires when a drag operation is complete
49333 * @param {Grid} this
49334 * @param {Roo.GridDD} dd The drag drop object
49335 * @param {event} e The raw browser event
49340 * Fires when dragged row(s) are dropped on a valid DD target
49341 * @param {Grid} this
49342 * @param {Roo.GridDD} dd The drag drop object
49343 * @param {String} targetId The target drag drop object
49344 * @param {event} e The raw browser event
49349 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
49350 * @param {Grid} this
49351 * @param {Roo.GridDD} dd The drag drop object
49352 * @param {String} targetId The target drag drop object
49353 * @param {event} e The raw browser event
49358 * Fires when the dragged row(s) first cross another DD target while being dragged
49359 * @param {Grid} this
49360 * @param {Roo.GridDD} dd The drag drop object
49361 * @param {String} targetId The target drag drop object
49362 * @param {event} e The raw browser event
49364 "dragenter" : true,
49367 * Fires when the dragged row(s) leave another DD target while being dragged
49368 * @param {Grid} this
49369 * @param {Roo.GridDD} dd The drag drop object
49370 * @param {String} targetId The target drag drop object
49371 * @param {event} e The raw browser event
49376 * Fires when a row is rendered, so you can change add a style to it.
49377 * @param {GridView} gridview The grid view
49378 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
49384 * Fires when the grid is rendered
49385 * @param {Grid} grid
49390 Roo.grid.Grid.superclass.constructor.call(this);
49392 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
49395 * @cfg {String} ddGroup - drag drop group.
49399 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
49401 minColumnWidth : 25,
49404 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
49405 * <b>on initial render.</b> It is more efficient to explicitly size the columns
49406 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
49408 autoSizeColumns : false,
49411 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
49413 autoSizeHeaders : true,
49416 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
49418 monitorWindowResize : true,
49421 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
49422 * rows measured to get a columns size. Default is 0 (all rows).
49424 maxRowsToMeasure : 0,
49427 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
49429 trackMouseOver : true,
49432 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
49436 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
49438 enableDragDrop : false,
49441 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
49443 enableColumnMove : true,
49446 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
49448 enableColumnHide : true,
49451 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
49453 enableRowHeightSync : false,
49456 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
49461 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
49463 autoHeight : false,
49466 * @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.
49468 autoExpandColumn : false,
49471 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
49474 autoExpandMin : 50,
49477 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
49479 autoExpandMax : 1000,
49482 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
49487 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
49491 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
49501 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
49502 * of a fixed width. Default is false.
49505 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
49508 * Called once after all setup has been completed and the grid is ready to be rendered.
49509 * @return {Roo.grid.Grid} this
49511 render : function()
49513 var c = this.container;
49514 // try to detect autoHeight/width mode
49515 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
49516 this.autoHeight = true;
49518 var view = this.getView();
49521 c.on("click", this.onClick, this);
49522 c.on("dblclick", this.onDblClick, this);
49523 c.on("contextmenu", this.onContextMenu, this);
49524 c.on("keydown", this.onKeyDown, this);
49526 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
49528 this.getSelectionModel().init(this);
49533 this.loadMask = new Roo.LoadMask(this.container,
49534 Roo.apply({store:this.dataSource}, this.loadMask));
49538 if (this.toolbar && this.toolbar.xtype) {
49539 this.toolbar.container = this.getView().getHeaderPanel(true);
49540 this.toolbar = new Roo.Toolbar(this.toolbar);
49542 if (this.footer && this.footer.xtype) {
49543 this.footer.dataSource = this.getDataSource();
49544 this.footer.container = this.getView().getFooterPanel(true);
49545 this.footer = Roo.factory(this.footer, Roo);
49547 if (this.dropTarget && this.dropTarget.xtype) {
49548 delete this.dropTarget.xtype;
49549 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
49553 this.rendered = true;
49554 this.fireEvent('render', this);
49559 * Reconfigures the grid to use a different Store and Column Model.
49560 * The View will be bound to the new objects and refreshed.
49561 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
49562 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
49564 reconfigure : function(dataSource, colModel){
49566 this.loadMask.destroy();
49567 this.loadMask = new Roo.LoadMask(this.container,
49568 Roo.apply({store:dataSource}, this.loadMask));
49570 this.view.bind(dataSource, colModel);
49571 this.dataSource = dataSource;
49572 this.colModel = colModel;
49573 this.view.refresh(true);
49577 onKeyDown : function(e){
49578 this.fireEvent("keydown", e);
49582 * Destroy this grid.
49583 * @param {Boolean} removeEl True to remove the element
49585 destroy : function(removeEl, keepListeners){
49587 this.loadMask.destroy();
49589 var c = this.container;
49590 c.removeAllListeners();
49591 this.view.destroy();
49592 this.colModel.purgeListeners();
49593 if(!keepListeners){
49594 this.purgeListeners();
49597 if(removeEl === true){
49603 processEvent : function(name, e){
49604 this.fireEvent(name, e);
49605 var t = e.getTarget();
49607 var header = v.findHeaderIndex(t);
49608 if(header !== false){
49609 this.fireEvent("header" + name, this, header, e);
49611 var row = v.findRowIndex(t);
49612 var cell = v.findCellIndex(t);
49614 this.fireEvent("row" + name, this, row, e);
49615 if(cell !== false){
49616 this.fireEvent("cell" + name, this, row, cell, e);
49623 onClick : function(e){
49624 this.processEvent("click", e);
49628 onContextMenu : function(e, t){
49629 this.processEvent("contextmenu", e);
49633 onDblClick : function(e){
49634 this.processEvent("dblclick", e);
49638 walkCells : function(row, col, step, fn, scope){
49639 var cm = this.colModel, clen = cm.getColumnCount();
49640 var ds = this.dataSource, rlen = ds.getCount(), first = true;
49652 if(fn.call(scope || this, row, col, cm) === true){
49670 if(fn.call(scope || this, row, col, cm) === true){
49682 getSelections : function(){
49683 return this.selModel.getSelections();
49687 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
49688 * but if manual update is required this method will initiate it.
49690 autoSize : function(){
49692 this.view.layout();
49693 if(this.view.adjustForScroll){
49694 this.view.adjustForScroll();
49700 * Returns the grid's underlying element.
49701 * @return {Element} The element
49703 getGridEl : function(){
49704 return this.container;
49707 // private for compatibility, overridden by editor grid
49708 stopEditing : function(){},
49711 * Returns the grid's SelectionModel.
49712 * @return {SelectionModel}
49714 getSelectionModel : function(){
49715 if(!this.selModel){
49716 this.selModel = new Roo.grid.RowSelectionModel();
49718 return this.selModel;
49722 * Returns the grid's DataSource.
49723 * @return {DataSource}
49725 getDataSource : function(){
49726 return this.dataSource;
49730 * Returns the grid's ColumnModel.
49731 * @return {ColumnModel}
49733 getColumnModel : function(){
49734 return this.colModel;
49738 * Returns the grid's GridView object.
49739 * @return {GridView}
49741 getView : function(){
49743 this.view = new Roo.grid.GridView(this.viewConfig);
49748 * Called to get grid's drag proxy text, by default returns this.ddText.
49751 getDragDropText : function(){
49752 var count = this.selModel.getCount();
49753 return String.format(this.ddText, count, count == 1 ? '' : 's');
49757 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
49758 * %0 is replaced with the number of selected rows.
49761 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
49763 * Ext JS Library 1.1.1
49764 * Copyright(c) 2006-2007, Ext JS, LLC.
49766 * Originally Released Under LGPL - original licence link has changed is not relivant.
49769 * <script type="text/javascript">
49772 Roo.grid.AbstractGridView = function(){
49776 "beforerowremoved" : true,
49777 "beforerowsinserted" : true,
49778 "beforerefresh" : true,
49779 "rowremoved" : true,
49780 "rowsinserted" : true,
49781 "rowupdated" : true,
49784 Roo.grid.AbstractGridView.superclass.constructor.call(this);
49787 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
49788 rowClass : "x-grid-row",
49789 cellClass : "x-grid-cell",
49790 tdClass : "x-grid-td",
49791 hdClass : "x-grid-hd",
49792 splitClass : "x-grid-hd-split",
49794 init: function(grid){
49796 var cid = this.grid.getGridEl().id;
49797 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
49798 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
49799 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
49800 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
49803 getColumnRenderers : function(){
49804 var renderers = [];
49805 var cm = this.grid.colModel;
49806 var colCount = cm.getColumnCount();
49807 for(var i = 0; i < colCount; i++){
49808 renderers[i] = cm.getRenderer(i);
49813 getColumnIds : function(){
49815 var cm = this.grid.colModel;
49816 var colCount = cm.getColumnCount();
49817 for(var i = 0; i < colCount; i++){
49818 ids[i] = cm.getColumnId(i);
49823 getDataIndexes : function(){
49824 if(!this.indexMap){
49825 this.indexMap = this.buildIndexMap();
49827 return this.indexMap.colToData;
49830 getColumnIndexByDataIndex : function(dataIndex){
49831 if(!this.indexMap){
49832 this.indexMap = this.buildIndexMap();
49834 return this.indexMap.dataToCol[dataIndex];
49838 * Set a css style for a column dynamically.
49839 * @param {Number} colIndex The index of the column
49840 * @param {String} name The css property name
49841 * @param {String} value The css value
49843 setCSSStyle : function(colIndex, name, value){
49844 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
49845 Roo.util.CSS.updateRule(selector, name, value);
49848 generateRules : function(cm){
49849 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
49850 Roo.util.CSS.removeStyleSheet(rulesId);
49851 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49852 var cid = cm.getColumnId(i);
49853 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
49854 this.tdSelector, cid, " {\n}\n",
49855 this.hdSelector, cid, " {\n}\n",
49856 this.splitSelector, cid, " {\n}\n");
49858 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49862 * Ext JS Library 1.1.1
49863 * Copyright(c) 2006-2007, Ext JS, LLC.
49865 * Originally Released Under LGPL - original licence link has changed is not relivant.
49868 * <script type="text/javascript">
49872 // This is a support class used internally by the Grid components
49873 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
49875 this.view = grid.getView();
49876 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
49877 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
49879 this.setHandleElId(Roo.id(hd));
49880 this.setOuterHandleElId(Roo.id(hd2));
49882 this.scroll = false;
49884 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
49886 getDragData : function(e){
49887 var t = Roo.lib.Event.getTarget(e);
49888 var h = this.view.findHeaderCell(t);
49890 return {ddel: h.firstChild, header:h};
49895 onInitDrag : function(e){
49896 this.view.headersDisabled = true;
49897 var clone = this.dragData.ddel.cloneNode(true);
49898 clone.id = Roo.id();
49899 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
49900 this.proxy.update(clone);
49904 afterValidDrop : function(){
49906 setTimeout(function(){
49907 v.headersDisabled = false;
49911 afterInvalidDrop : function(){
49913 setTimeout(function(){
49914 v.headersDisabled = false;
49920 * Ext JS Library 1.1.1
49921 * Copyright(c) 2006-2007, Ext JS, LLC.
49923 * Originally Released Under LGPL - original licence link has changed is not relivant.
49926 * <script type="text/javascript">
49929 // This is a support class used internally by the Grid components
49930 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
49932 this.view = grid.getView();
49933 // split the proxies so they don't interfere with mouse events
49934 this.proxyTop = Roo.DomHelper.append(document.body, {
49935 cls:"col-move-top", html:" "
49937 this.proxyBottom = Roo.DomHelper.append(document.body, {
49938 cls:"col-move-bottom", html:" "
49940 this.proxyTop.hide = this.proxyBottom.hide = function(){
49941 this.setLeftTop(-100,-100);
49942 this.setStyle("visibility", "hidden");
49944 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
49945 // temporarily disabled
49946 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
49947 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
49949 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
49950 proxyOffsets : [-4, -9],
49951 fly: Roo.Element.fly,
49953 getTargetFromEvent : function(e){
49954 var t = Roo.lib.Event.getTarget(e);
49955 var cindex = this.view.findCellIndex(t);
49956 if(cindex !== false){
49957 return this.view.getHeaderCell(cindex);
49962 nextVisible : function(h){
49963 var v = this.view, cm = this.grid.colModel;
49966 if(!cm.isHidden(v.getCellIndex(h))){
49974 prevVisible : function(h){
49975 var v = this.view, cm = this.grid.colModel;
49978 if(!cm.isHidden(v.getCellIndex(h))){
49986 positionIndicator : function(h, n, e){
49987 var x = Roo.lib.Event.getPageX(e);
49988 var r = Roo.lib.Dom.getRegion(n.firstChild);
49989 var px, pt, py = r.top + this.proxyOffsets[1];
49990 if((r.right - x) <= (r.right-r.left)/2){
49991 px = r.right+this.view.borderWidth;
49997 var oldIndex = this.view.getCellIndex(h);
49998 var newIndex = this.view.getCellIndex(n);
50000 if(this.grid.colModel.isFixed(newIndex)){
50004 var locked = this.grid.colModel.isLocked(newIndex);
50009 if(oldIndex < newIndex){
50012 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
50015 px += this.proxyOffsets[0];
50016 this.proxyTop.setLeftTop(px, py);
50017 this.proxyTop.show();
50018 if(!this.bottomOffset){
50019 this.bottomOffset = this.view.mainHd.getHeight();
50021 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
50022 this.proxyBottom.show();
50026 onNodeEnter : function(n, dd, e, data){
50027 if(data.header != n){
50028 this.positionIndicator(data.header, n, e);
50032 onNodeOver : function(n, dd, e, data){
50033 var result = false;
50034 if(data.header != n){
50035 result = this.positionIndicator(data.header, n, e);
50038 this.proxyTop.hide();
50039 this.proxyBottom.hide();
50041 return result ? this.dropAllowed : this.dropNotAllowed;
50044 onNodeOut : function(n, dd, e, data){
50045 this.proxyTop.hide();
50046 this.proxyBottom.hide();
50049 onNodeDrop : function(n, dd, e, data){
50050 var h = data.header;
50052 var cm = this.grid.colModel;
50053 var x = Roo.lib.Event.getPageX(e);
50054 var r = Roo.lib.Dom.getRegion(n.firstChild);
50055 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
50056 var oldIndex = this.view.getCellIndex(h);
50057 var newIndex = this.view.getCellIndex(n);
50058 var locked = cm.isLocked(newIndex);
50062 if(oldIndex < newIndex){
50065 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
50068 cm.setLocked(oldIndex, locked, true);
50069 cm.moveColumn(oldIndex, newIndex);
50070 this.grid.fireEvent("columnmove", oldIndex, newIndex);
50078 * Ext JS Library 1.1.1
50079 * Copyright(c) 2006-2007, Ext JS, LLC.
50081 * Originally Released Under LGPL - original licence link has changed is not relivant.
50084 * <script type="text/javascript">
50088 * @class Roo.grid.GridView
50089 * @extends Roo.util.Observable
50092 * @param {Object} config
50094 Roo.grid.GridView = function(config){
50095 Roo.grid.GridView.superclass.constructor.call(this);
50098 Roo.apply(this, config);
50101 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
50103 unselectable : 'unselectable="on"',
50104 unselectableCls : 'x-unselectable',
50107 rowClass : "x-grid-row",
50109 cellClass : "x-grid-col",
50111 tdClass : "x-grid-td",
50113 hdClass : "x-grid-hd",
50115 splitClass : "x-grid-split",
50117 sortClasses : ["sort-asc", "sort-desc"],
50119 enableMoveAnim : false,
50123 dh : Roo.DomHelper,
50125 fly : Roo.Element.fly,
50127 css : Roo.util.CSS,
50133 scrollIncrement : 22,
50135 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
50137 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
50139 bind : function(ds, cm){
50141 this.ds.un("load", this.onLoad, this);
50142 this.ds.un("datachanged", this.onDataChange, this);
50143 this.ds.un("add", this.onAdd, this);
50144 this.ds.un("remove", this.onRemove, this);
50145 this.ds.un("update", this.onUpdate, this);
50146 this.ds.un("clear", this.onClear, this);
50149 ds.on("load", this.onLoad, this);
50150 ds.on("datachanged", this.onDataChange, this);
50151 ds.on("add", this.onAdd, this);
50152 ds.on("remove", this.onRemove, this);
50153 ds.on("update", this.onUpdate, this);
50154 ds.on("clear", this.onClear, this);
50159 this.cm.un("widthchange", this.onColWidthChange, this);
50160 this.cm.un("headerchange", this.onHeaderChange, this);
50161 this.cm.un("hiddenchange", this.onHiddenChange, this);
50162 this.cm.un("columnmoved", this.onColumnMove, this);
50163 this.cm.un("columnlockchange", this.onColumnLock, this);
50166 this.generateRules(cm);
50167 cm.on("widthchange", this.onColWidthChange, this);
50168 cm.on("headerchange", this.onHeaderChange, this);
50169 cm.on("hiddenchange", this.onHiddenChange, this);
50170 cm.on("columnmoved", this.onColumnMove, this);
50171 cm.on("columnlockchange", this.onColumnLock, this);
50176 init: function(grid){
50177 Roo.grid.GridView.superclass.init.call(this, grid);
50179 this.bind(grid.dataSource, grid.colModel);
50181 grid.on("headerclick", this.handleHeaderClick, this);
50183 if(grid.trackMouseOver){
50184 grid.on("mouseover", this.onRowOver, this);
50185 grid.on("mouseout", this.onRowOut, this);
50187 grid.cancelTextSelection = function(){};
50188 this.gridId = grid.id;
50190 var tpls = this.templates || {};
50193 tpls.master = new Roo.Template(
50194 '<div class="x-grid" hidefocus="true">',
50195 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
50196 '<div class="x-grid-topbar"></div>',
50197 '<div class="x-grid-scroller"><div></div></div>',
50198 '<div class="x-grid-locked">',
50199 '<div class="x-grid-header">{lockedHeader}</div>',
50200 '<div class="x-grid-body">{lockedBody}</div>',
50202 '<div class="x-grid-viewport">',
50203 '<div class="x-grid-header">{header}</div>',
50204 '<div class="x-grid-body">{body}</div>',
50206 '<div class="x-grid-bottombar"></div>',
50208 '<div class="x-grid-resize-proxy"> </div>',
50211 tpls.master.disableformats = true;
50215 tpls.header = new Roo.Template(
50216 '<table border="0" cellspacing="0" cellpadding="0">',
50217 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
50220 tpls.header.disableformats = true;
50222 tpls.header.compile();
50225 tpls.hcell = new Roo.Template(
50226 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
50227 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
50230 tpls.hcell.disableFormats = true;
50232 tpls.hcell.compile();
50235 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
50236 this.unselectableCls + '" ' + this.unselectable +'> </div>');
50237 tpls.hsplit.disableFormats = true;
50239 tpls.hsplit.compile();
50242 tpls.body = new Roo.Template(
50243 '<table border="0" cellspacing="0" cellpadding="0">',
50244 "<tbody>{rows}</tbody>",
50247 tpls.body.disableFormats = true;
50249 tpls.body.compile();
50252 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
50253 tpls.row.disableFormats = true;
50255 tpls.row.compile();
50258 tpls.cell = new Roo.Template(
50259 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
50260 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
50261 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
50264 tpls.cell.disableFormats = true;
50266 tpls.cell.compile();
50268 this.templates = tpls;
50271 // remap these for backwards compat
50272 onColWidthChange : function(){
50273 this.updateColumns.apply(this, arguments);
50275 onHeaderChange : function(){
50276 this.updateHeaders.apply(this, arguments);
50278 onHiddenChange : function(){
50279 this.handleHiddenChange.apply(this, arguments);
50281 onColumnMove : function(){
50282 this.handleColumnMove.apply(this, arguments);
50284 onColumnLock : function(){
50285 this.handleLockChange.apply(this, arguments);
50288 onDataChange : function(){
50290 this.updateHeaderSortState();
50293 onClear : function(){
50297 onUpdate : function(ds, record){
50298 this.refreshRow(record);
50301 refreshRow : function(record){
50302 var ds = this.ds, index;
50303 if(typeof record == 'number'){
50305 record = ds.getAt(index);
50307 index = ds.indexOf(record);
50309 this.insertRows(ds, index, index, true);
50310 this.onRemove(ds, record, index+1, true);
50311 this.syncRowHeights(index, index);
50313 this.fireEvent("rowupdated", this, index, record);
50316 onAdd : function(ds, records, index){
50317 this.insertRows(ds, index, index + (records.length-1));
50320 onRemove : function(ds, record, index, isUpdate){
50321 if(isUpdate !== true){
50322 this.fireEvent("beforerowremoved", this, index, record);
50324 var bt = this.getBodyTable(), lt = this.getLockedTable();
50325 if(bt.rows[index]){
50326 bt.firstChild.removeChild(bt.rows[index]);
50328 if(lt.rows[index]){
50329 lt.firstChild.removeChild(lt.rows[index]);
50331 if(isUpdate !== true){
50332 this.stripeRows(index);
50333 this.syncRowHeights(index, index);
50335 this.fireEvent("rowremoved", this, index, record);
50339 onLoad : function(){
50340 this.scrollToTop();
50344 * Scrolls the grid to the top
50346 scrollToTop : function(){
50348 this.scroller.dom.scrollTop = 0;
50354 * Gets a panel in the header of the grid that can be used for toolbars etc.
50355 * After modifying the contents of this panel a call to grid.autoSize() may be
50356 * required to register any changes in size.
50357 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
50358 * @return Roo.Element
50360 getHeaderPanel : function(doShow){
50362 this.headerPanel.show();
50364 return this.headerPanel;
50368 * Gets a panel in the footer of the grid that can be used for toolbars etc.
50369 * After modifying the contents of this panel a call to grid.autoSize() may be
50370 * required to register any changes in size.
50371 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
50372 * @return Roo.Element
50374 getFooterPanel : function(doShow){
50376 this.footerPanel.show();
50378 return this.footerPanel;
50381 initElements : function(){
50382 var E = Roo.Element;
50383 var el = this.grid.getGridEl().dom.firstChild;
50384 var cs = el.childNodes;
50386 this.el = new E(el);
50388 this.focusEl = new E(el.firstChild);
50389 this.focusEl.swallowEvent("click", true);
50391 this.headerPanel = new E(cs[1]);
50392 this.headerPanel.enableDisplayMode("block");
50394 this.scroller = new E(cs[2]);
50395 this.scrollSizer = new E(this.scroller.dom.firstChild);
50397 this.lockedWrap = new E(cs[3]);
50398 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
50399 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
50401 this.mainWrap = new E(cs[4]);
50402 this.mainHd = new E(this.mainWrap.dom.firstChild);
50403 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
50405 this.footerPanel = new E(cs[5]);
50406 this.footerPanel.enableDisplayMode("block");
50408 this.resizeProxy = new E(cs[6]);
50410 this.headerSelector = String.format(
50411 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
50412 this.lockedHd.id, this.mainHd.id
50415 this.splitterSelector = String.format(
50416 '#{0} div.x-grid-split, #{1} div.x-grid-split',
50417 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
50420 idToCssName : function(s)
50422 return s.replace(/[^a-z0-9]+/ig, '-');
50425 getHeaderCell : function(index){
50426 return Roo.DomQuery.select(this.headerSelector)[index];
50429 getHeaderCellMeasure : function(index){
50430 return this.getHeaderCell(index).firstChild;
50433 getHeaderCellText : function(index){
50434 return this.getHeaderCell(index).firstChild.firstChild;
50437 getLockedTable : function(){
50438 return this.lockedBody.dom.firstChild;
50441 getBodyTable : function(){
50442 return this.mainBody.dom.firstChild;
50445 getLockedRow : function(index){
50446 return this.getLockedTable().rows[index];
50449 getRow : function(index){
50450 return this.getBodyTable().rows[index];
50453 getRowComposite : function(index){
50455 this.rowEl = new Roo.CompositeElementLite();
50457 var els = [], lrow, mrow;
50458 if(lrow = this.getLockedRow(index)){
50461 if(mrow = this.getRow(index)){
50464 this.rowEl.elements = els;
50468 * Gets the 'td' of the cell
50470 * @param {Integer} rowIndex row to select
50471 * @param {Integer} colIndex column to select
50475 getCell : function(rowIndex, colIndex){
50476 var locked = this.cm.getLockedCount();
50478 if(colIndex < locked){
50479 source = this.lockedBody.dom.firstChild;
50481 source = this.mainBody.dom.firstChild;
50482 colIndex -= locked;
50484 return source.rows[rowIndex].childNodes[colIndex];
50487 getCellText : function(rowIndex, colIndex){
50488 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
50491 getCellBox : function(cell){
50492 var b = this.fly(cell).getBox();
50493 if(Roo.isOpera){ // opera fails to report the Y
50494 b.y = cell.offsetTop + this.mainBody.getY();
50499 getCellIndex : function(cell){
50500 var id = String(cell.className).match(this.cellRE);
50502 return parseInt(id[1], 10);
50507 findHeaderIndex : function(n){
50508 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
50509 return r ? this.getCellIndex(r) : false;
50512 findHeaderCell : function(n){
50513 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
50514 return r ? r : false;
50517 findRowIndex : function(n){
50521 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
50522 return r ? r.rowIndex : false;
50525 findCellIndex : function(node){
50526 var stop = this.el.dom;
50527 while(node && node != stop){
50528 if(this.findRE.test(node.className)){
50529 return this.getCellIndex(node);
50531 node = node.parentNode;
50536 getColumnId : function(index){
50537 return this.cm.getColumnId(index);
50540 getSplitters : function()
50542 if(this.splitterSelector){
50543 return Roo.DomQuery.select(this.splitterSelector);
50549 getSplitter : function(index){
50550 return this.getSplitters()[index];
50553 onRowOver : function(e, t){
50555 if((row = this.findRowIndex(t)) !== false){
50556 this.getRowComposite(row).addClass("x-grid-row-over");
50560 onRowOut : function(e, t){
50562 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
50563 this.getRowComposite(row).removeClass("x-grid-row-over");
50567 renderHeaders : function(){
50569 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
50570 var cb = [], lb = [], sb = [], lsb = [], p = {};
50571 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50572 p.cellId = "x-grid-hd-0-" + i;
50573 p.splitId = "x-grid-csplit-0-" + i;
50574 p.id = cm.getColumnId(i);
50575 p.title = cm.getColumnTooltip(i) || "";
50576 p.value = cm.getColumnHeader(i) || "";
50577 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
50578 if(!cm.isLocked(i)){
50579 cb[cb.length] = ct.apply(p);
50580 sb[sb.length] = st.apply(p);
50582 lb[lb.length] = ct.apply(p);
50583 lsb[lsb.length] = st.apply(p);
50586 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
50587 ht.apply({cells: cb.join(""), splits:sb.join("")})];
50590 updateHeaders : function(){
50591 var html = this.renderHeaders();
50592 this.lockedHd.update(html[0]);
50593 this.mainHd.update(html[1]);
50597 * Focuses the specified row.
50598 * @param {Number} row The row index
50600 focusRow : function(row)
50602 //Roo.log('GridView.focusRow');
50603 var x = this.scroller.dom.scrollLeft;
50604 this.focusCell(row, 0, false);
50605 this.scroller.dom.scrollLeft = x;
50609 * Focuses the specified cell.
50610 * @param {Number} row The row index
50611 * @param {Number} col The column index
50612 * @param {Boolean} hscroll false to disable horizontal scrolling
50614 focusCell : function(row, col, hscroll)
50616 //Roo.log('GridView.focusCell');
50617 var el = this.ensureVisible(row, col, hscroll);
50618 this.focusEl.alignTo(el, "tl-tl");
50620 this.focusEl.focus();
50622 this.focusEl.focus.defer(1, this.focusEl);
50627 * Scrolls the specified cell into view
50628 * @param {Number} row The row index
50629 * @param {Number} col The column index
50630 * @param {Boolean} hscroll false to disable horizontal scrolling
50632 ensureVisible : function(row, col, hscroll)
50634 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
50635 //return null; //disable for testing.
50636 if(typeof row != "number"){
50637 row = row.rowIndex;
50639 if(row < 0 && row >= this.ds.getCount()){
50642 col = (col !== undefined ? col : 0);
50643 var cm = this.grid.colModel;
50644 while(cm.isHidden(col)){
50648 var el = this.getCell(row, col);
50652 var c = this.scroller.dom;
50654 var ctop = parseInt(el.offsetTop, 10);
50655 var cleft = parseInt(el.offsetLeft, 10);
50656 var cbot = ctop + el.offsetHeight;
50657 var cright = cleft + el.offsetWidth;
50659 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
50660 var stop = parseInt(c.scrollTop, 10);
50661 var sleft = parseInt(c.scrollLeft, 10);
50662 var sbot = stop + ch;
50663 var sright = sleft + c.clientWidth;
50665 Roo.log('GridView.ensureVisible:' +
50667 ' c.clientHeight:' + c.clientHeight +
50668 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
50676 c.scrollTop = ctop;
50677 //Roo.log("set scrolltop to ctop DISABLE?");
50678 }else if(cbot > sbot){
50679 //Roo.log("set scrolltop to cbot-ch");
50680 c.scrollTop = cbot-ch;
50683 if(hscroll !== false){
50685 c.scrollLeft = cleft;
50686 }else if(cright > sright){
50687 c.scrollLeft = cright-c.clientWidth;
50694 updateColumns : function(){
50695 this.grid.stopEditing();
50696 var cm = this.grid.colModel, colIds = this.getColumnIds();
50697 //var totalWidth = cm.getTotalWidth();
50699 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50700 //if(cm.isHidden(i)) continue;
50701 var w = cm.getColumnWidth(i);
50702 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50703 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50705 this.updateSplitters();
50708 generateRules : function(cm){
50709 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
50710 Roo.util.CSS.removeStyleSheet(rulesId);
50711 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50712 var cid = cm.getColumnId(i);
50714 if(cm.config[i].align){
50715 align = 'text-align:'+cm.config[i].align+';';
50718 if(cm.isHidden(i)){
50719 hidden = 'display:none;';
50721 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
50723 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
50724 this.hdSelector, cid, " {\n", align, width, "}\n",
50725 this.tdSelector, cid, " {\n",hidden,"\n}\n",
50726 this.splitSelector, cid, " {\n", hidden , "\n}\n");
50728 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
50731 updateSplitters : function(){
50732 var cm = this.cm, s = this.getSplitters();
50733 if(s){ // splitters not created yet
50734 var pos = 0, locked = true;
50735 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50736 if(cm.isHidden(i)) continue;
50737 var w = cm.getColumnWidth(i); // make sure it's a number
50738 if(!cm.isLocked(i) && locked){
50743 s[i].style.left = (pos-this.splitOffset) + "px";
50748 handleHiddenChange : function(colModel, colIndex, hidden){
50750 this.hideColumn(colIndex);
50752 this.unhideColumn(colIndex);
50756 hideColumn : function(colIndex){
50757 var cid = this.getColumnId(colIndex);
50758 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
50759 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
50761 this.updateHeaders();
50763 this.updateSplitters();
50767 unhideColumn : function(colIndex){
50768 var cid = this.getColumnId(colIndex);
50769 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
50770 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
50773 this.updateHeaders();
50775 this.updateSplitters();
50779 insertRows : function(dm, firstRow, lastRow, isUpdate){
50780 if(firstRow == 0 && lastRow == dm.getCount()-1){
50784 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
50786 var s = this.getScrollState();
50787 var markup = this.renderRows(firstRow, lastRow);
50788 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
50789 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
50790 this.restoreScroll(s);
50792 this.fireEvent("rowsinserted", this, firstRow, lastRow);
50793 this.syncRowHeights(firstRow, lastRow);
50794 this.stripeRows(firstRow);
50800 bufferRows : function(markup, target, index){
50801 var before = null, trows = target.rows, tbody = target.tBodies[0];
50802 if(index < trows.length){
50803 before = trows[index];
50805 var b = document.createElement("div");
50806 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
50807 var rows = b.firstChild.rows;
50808 for(var i = 0, len = rows.length; i < len; i++){
50810 tbody.insertBefore(rows[0], before);
50812 tbody.appendChild(rows[0]);
50819 deleteRows : function(dm, firstRow, lastRow){
50820 if(dm.getRowCount()<1){
50821 this.fireEvent("beforerefresh", this);
50822 this.mainBody.update("");
50823 this.lockedBody.update("");
50824 this.fireEvent("refresh", this);
50826 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
50827 var bt = this.getBodyTable();
50828 var tbody = bt.firstChild;
50829 var rows = bt.rows;
50830 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
50831 tbody.removeChild(rows[firstRow]);
50833 this.stripeRows(firstRow);
50834 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
50838 updateRows : function(dataSource, firstRow, lastRow){
50839 var s = this.getScrollState();
50841 this.restoreScroll(s);
50844 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
50848 this.updateHeaderSortState();
50851 getScrollState : function(){
50853 var sb = this.scroller.dom;
50854 return {left: sb.scrollLeft, top: sb.scrollTop};
50857 stripeRows : function(startRow){
50858 if(!this.grid.stripeRows || this.ds.getCount() < 1){
50861 startRow = startRow || 0;
50862 var rows = this.getBodyTable().rows;
50863 var lrows = this.getLockedTable().rows;
50864 var cls = ' x-grid-row-alt ';
50865 for(var i = startRow, len = rows.length; i < len; i++){
50866 var row = rows[i], lrow = lrows[i];
50867 var isAlt = ((i+1) % 2 == 0);
50868 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
50869 if(isAlt == hasAlt){
50873 row.className += " x-grid-row-alt";
50875 row.className = row.className.replace("x-grid-row-alt", "");
50878 lrow.className = row.className;
50883 restoreScroll : function(state){
50884 //Roo.log('GridView.restoreScroll');
50885 var sb = this.scroller.dom;
50886 sb.scrollLeft = state.left;
50887 sb.scrollTop = state.top;
50891 syncScroll : function(){
50892 //Roo.log('GridView.syncScroll');
50893 var sb = this.scroller.dom;
50894 var sh = this.mainHd.dom;
50895 var bs = this.mainBody.dom;
50896 var lv = this.lockedBody.dom;
50897 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
50898 lv.scrollTop = bs.scrollTop = sb.scrollTop;
50901 handleScroll : function(e){
50903 var sb = this.scroller.dom;
50904 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
50908 handleWheel : function(e){
50909 var d = e.getWheelDelta();
50910 this.scroller.dom.scrollTop -= d*22;
50911 // set this here to prevent jumpy scrolling on large tables
50912 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
50916 renderRows : function(startRow, endRow){
50917 // pull in all the crap needed to render rows
50918 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
50919 var colCount = cm.getColumnCount();
50921 if(ds.getCount() < 1){
50925 // build a map for all the columns
50927 for(var i = 0; i < colCount; i++){
50928 var name = cm.getDataIndex(i);
50930 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
50931 renderer : cm.getRenderer(i),
50932 id : cm.getColumnId(i),
50933 locked : cm.isLocked(i)
50937 startRow = startRow || 0;
50938 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
50940 // records to render
50941 var rs = ds.getRange(startRow, endRow);
50943 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
50946 // As much as I hate to duplicate code, this was branched because FireFox really hates
50947 // [].join("") on strings. The performance difference was substantial enough to
50948 // branch this function
50949 doRender : Roo.isGecko ?
50950 function(cs, rs, ds, startRow, colCount, stripe){
50951 var ts = this.templates, ct = ts.cell, rt = ts.row;
50953 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
50955 var hasListener = this.grid.hasListener('rowclass');
50957 for(var j = 0, len = rs.length; j < len; j++){
50958 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
50959 for(var i = 0; i < colCount; i++){
50961 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
50963 p.css = p.attr = "";
50964 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
50965 if(p.value == undefined || p.value === "") p.value = " ";
50966 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
50967 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
50969 var markup = ct.apply(p);
50977 if(stripe && ((rowIndex+1) % 2 == 0)){
50978 alt.push("x-grid-row-alt")
50981 alt.push( " x-grid-dirty-row");
50984 if(this.getRowClass){
50985 alt.push(this.getRowClass(r, rowIndex));
50991 rowIndex : rowIndex,
50994 this.grid.fireEvent('rowclass', this, rowcfg);
50995 alt.push(rowcfg.rowClass);
50997 rp.alt = alt.join(" ");
50998 lbuf+= rt.apply(rp);
51000 buf+= rt.apply(rp);
51002 return [lbuf, buf];
51004 function(cs, rs, ds, startRow, colCount, stripe){
51005 var ts = this.templates, ct = ts.cell, rt = ts.row;
51007 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
51008 var hasListener = this.grid.hasListener('rowclass');
51011 for(var j = 0, len = rs.length; j < len; j++){
51012 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
51013 for(var i = 0; i < colCount; i++){
51015 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
51017 p.css = p.attr = "";
51018 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
51019 if(p.value == undefined || p.value === "") p.value = " ";
51020 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
51021 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
51024 var markup = ct.apply(p);
51026 cb[cb.length] = markup;
51028 lcb[lcb.length] = markup;
51032 if(stripe && ((rowIndex+1) % 2 == 0)){
51033 alt.push( "x-grid-row-alt");
51036 alt.push(" x-grid-dirty-row");
51039 if(this.getRowClass){
51040 alt.push( this.getRowClass(r, rowIndex));
51046 rowIndex : rowIndex,
51049 this.grid.fireEvent('rowclass', this, rowcfg);
51050 alt.push(rowcfg.rowClass);
51052 rp.alt = alt.join(" ");
51053 rp.cells = lcb.join("");
51054 lbuf[lbuf.length] = rt.apply(rp);
51055 rp.cells = cb.join("");
51056 buf[buf.length] = rt.apply(rp);
51058 return [lbuf.join(""), buf.join("")];
51061 renderBody : function(){
51062 var markup = this.renderRows();
51063 var bt = this.templates.body;
51064 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
51068 * Refreshes the grid
51069 * @param {Boolean} headersToo
51071 refresh : function(headersToo){
51072 this.fireEvent("beforerefresh", this);
51073 this.grid.stopEditing();
51074 var result = this.renderBody();
51075 this.lockedBody.update(result[0]);
51076 this.mainBody.update(result[1]);
51077 if(headersToo === true){
51078 this.updateHeaders();
51079 this.updateColumns();
51080 this.updateSplitters();
51081 this.updateHeaderSortState();
51083 this.syncRowHeights();
51085 this.fireEvent("refresh", this);
51088 handleColumnMove : function(cm, oldIndex, newIndex){
51089 this.indexMap = null;
51090 var s = this.getScrollState();
51091 this.refresh(true);
51092 this.restoreScroll(s);
51093 this.afterMove(newIndex);
51096 afterMove : function(colIndex){
51097 if(this.enableMoveAnim && Roo.enableFx){
51098 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
51100 // if multisort - fix sortOrder, and reload..
51101 if (this.grid.dataSource.multiSort) {
51102 // the we can call sort again..
51103 var dm = this.grid.dataSource;
51104 var cm = this.grid.colModel;
51106 for(var i = 0; i < cm.config.length; i++ ) {
51108 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
51109 continue; // dont' bother, it's not in sort list or being set.
51112 so.push(cm.config[i].dataIndex);
51115 dm.load(dm.lastOptions);
51122 updateCell : function(dm, rowIndex, dataIndex){
51123 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
51124 if(typeof colIndex == "undefined"){ // not present in grid
51127 var cm = this.grid.colModel;
51128 var cell = this.getCell(rowIndex, colIndex);
51129 var cellText = this.getCellText(rowIndex, colIndex);
51132 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
51133 id : cm.getColumnId(colIndex),
51134 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
51136 var renderer = cm.getRenderer(colIndex);
51137 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
51138 if(typeof val == "undefined" || val === "") val = " ";
51139 cellText.innerHTML = val;
51140 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
51141 this.syncRowHeights(rowIndex, rowIndex);
51144 calcColumnWidth : function(colIndex, maxRowsToMeasure){
51146 if(this.grid.autoSizeHeaders){
51147 var h = this.getHeaderCellMeasure(colIndex);
51148 maxWidth = Math.max(maxWidth, h.scrollWidth);
51151 if(this.cm.isLocked(colIndex)){
51152 tb = this.getLockedTable();
51155 tb = this.getBodyTable();
51156 index = colIndex - this.cm.getLockedCount();
51159 var rows = tb.rows;
51160 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
51161 for(var i = 0; i < stopIndex; i++){
51162 var cell = rows[i].childNodes[index].firstChild;
51163 maxWidth = Math.max(maxWidth, cell.scrollWidth);
51166 return maxWidth + /*margin for error in IE*/ 5;
51169 * Autofit a column to its content.
51170 * @param {Number} colIndex
51171 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
51173 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
51174 if(this.cm.isHidden(colIndex)){
51175 return; // can't calc a hidden column
51178 var cid = this.cm.getColumnId(colIndex);
51179 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
51180 if(this.grid.autoSizeHeaders){
51181 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
51184 var newWidth = this.calcColumnWidth(colIndex);
51185 this.cm.setColumnWidth(colIndex,
51186 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
51187 if(!suppressEvent){
51188 this.grid.fireEvent("columnresize", colIndex, newWidth);
51193 * Autofits all columns to their content and then expands to fit any extra space in the grid
51195 autoSizeColumns : function(){
51196 var cm = this.grid.colModel;
51197 var colCount = cm.getColumnCount();
51198 for(var i = 0; i < colCount; i++){
51199 this.autoSizeColumn(i, true, true);
51201 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
51204 this.updateColumns();
51210 * Autofits all columns to the grid's width proportionate with their current size
51211 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
51213 fitColumns : function(reserveScrollSpace){
51214 var cm = this.grid.colModel;
51215 var colCount = cm.getColumnCount();
51219 for (i = 0; i < colCount; i++){
51220 if(!cm.isHidden(i) && !cm.isFixed(i)){
51221 w = cm.getColumnWidth(i);
51227 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
51228 if(reserveScrollSpace){
51231 var frac = (avail - cm.getTotalWidth())/width;
51232 while (cols.length){
51235 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
51237 this.updateColumns();
51241 onRowSelect : function(rowIndex){
51242 var row = this.getRowComposite(rowIndex);
51243 row.addClass("x-grid-row-selected");
51246 onRowDeselect : function(rowIndex){
51247 var row = this.getRowComposite(rowIndex);
51248 row.removeClass("x-grid-row-selected");
51251 onCellSelect : function(row, col){
51252 var cell = this.getCell(row, col);
51254 Roo.fly(cell).addClass("x-grid-cell-selected");
51258 onCellDeselect : function(row, col){
51259 var cell = this.getCell(row, col);
51261 Roo.fly(cell).removeClass("x-grid-cell-selected");
51265 updateHeaderSortState : function(){
51267 // sort state can be single { field: xxx, direction : yyy}
51268 // or { xxx=>ASC , yyy : DESC ..... }
51271 if (!this.ds.multiSort) {
51272 var state = this.ds.getSortState();
51276 mstate[state.field] = state.direction;
51277 // FIXME... - this is not used here.. but might be elsewhere..
51278 this.sortState = state;
51281 mstate = this.ds.sortToggle;
51283 //remove existing sort classes..
51285 var sc = this.sortClasses;
51286 var hds = this.el.select(this.headerSelector).removeClass(sc);
51288 for(var f in mstate) {
51290 var sortColumn = this.cm.findColumnIndex(f);
51292 if(sortColumn != -1){
51293 var sortDir = mstate[f];
51294 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
51303 handleHeaderClick : function(g, index){
51304 if(this.headersDisabled){
51307 var dm = g.dataSource, cm = g.colModel;
51308 if(!cm.isSortable(index)){
51313 if (dm.multiSort) {
51314 // update the sortOrder
51316 for(var i = 0; i < cm.config.length; i++ ) {
51318 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
51319 continue; // dont' bother, it's not in sort list or being set.
51322 so.push(cm.config[i].dataIndex);
51328 dm.sort(cm.getDataIndex(index));
51332 destroy : function(){
51334 this.colMenu.removeAll();
51335 Roo.menu.MenuMgr.unregister(this.colMenu);
51336 this.colMenu.getEl().remove();
51337 delete this.colMenu;
51340 this.hmenu.removeAll();
51341 Roo.menu.MenuMgr.unregister(this.hmenu);
51342 this.hmenu.getEl().remove();
51345 if(this.grid.enableColumnMove){
51346 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51348 for(var dd in dds){
51349 if(!dds[dd].config.isTarget && dds[dd].dragElId){
51350 var elid = dds[dd].dragElId;
51352 Roo.get(elid).remove();
51353 } else if(dds[dd].config.isTarget){
51354 dds[dd].proxyTop.remove();
51355 dds[dd].proxyBottom.remove();
51358 if(Roo.dd.DDM.locationCache[dd]){
51359 delete Roo.dd.DDM.locationCache[dd];
51362 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51365 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
51366 this.bind(null, null);
51367 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
51370 handleLockChange : function(){
51371 this.refresh(true);
51374 onDenyColumnLock : function(){
51378 onDenyColumnHide : function(){
51382 handleHdMenuClick : function(item){
51383 var index = this.hdCtxIndex;
51384 var cm = this.cm, ds = this.ds;
51387 ds.sort(cm.getDataIndex(index), "ASC");
51390 ds.sort(cm.getDataIndex(index), "DESC");
51393 var lc = cm.getLockedCount();
51394 if(cm.getColumnCount(true) <= lc+1){
51395 this.onDenyColumnLock();
51399 cm.setLocked(index, true, true);
51400 cm.moveColumn(index, lc);
51401 this.grid.fireEvent("columnmove", index, lc);
51403 cm.setLocked(index, true);
51407 var lc = cm.getLockedCount();
51408 if((lc-1) != index){
51409 cm.setLocked(index, false, true);
51410 cm.moveColumn(index, lc-1);
51411 this.grid.fireEvent("columnmove", index, lc-1);
51413 cm.setLocked(index, false);
51417 index = cm.getIndexById(item.id.substr(4));
51419 if(item.checked && cm.getColumnCount(true) <= 1){
51420 this.onDenyColumnHide();
51423 cm.setHidden(index, item.checked);
51429 beforeColMenuShow : function(){
51430 var cm = this.cm, colCount = cm.getColumnCount();
51431 this.colMenu.removeAll();
51432 for(var i = 0; i < colCount; i++){
51433 this.colMenu.add(new Roo.menu.CheckItem({
51434 id: "col-"+cm.getColumnId(i),
51435 text: cm.getColumnHeader(i),
51436 checked: !cm.isHidden(i),
51442 handleHdCtx : function(g, index, e){
51444 var hd = this.getHeaderCell(index);
51445 this.hdCtxIndex = index;
51446 var ms = this.hmenu.items, cm = this.cm;
51447 ms.get("asc").setDisabled(!cm.isSortable(index));
51448 ms.get("desc").setDisabled(!cm.isSortable(index));
51449 if(this.grid.enableColLock !== false){
51450 ms.get("lock").setDisabled(cm.isLocked(index));
51451 ms.get("unlock").setDisabled(!cm.isLocked(index));
51453 this.hmenu.show(hd, "tl-bl");
51456 handleHdOver : function(e){
51457 var hd = this.findHeaderCell(e.getTarget());
51458 if(hd && !this.headersDisabled){
51459 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
51460 this.fly(hd).addClass("x-grid-hd-over");
51465 handleHdOut : function(e){
51466 var hd = this.findHeaderCell(e.getTarget());
51468 this.fly(hd).removeClass("x-grid-hd-over");
51472 handleSplitDblClick : function(e, t){
51473 var i = this.getCellIndex(t);
51474 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
51475 this.autoSizeColumn(i, true);
51480 render : function(){
51483 var colCount = cm.getColumnCount();
51485 if(this.grid.monitorWindowResize === true){
51486 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51488 var header = this.renderHeaders();
51489 var body = this.templates.body.apply({rows:""});
51490 var html = this.templates.master.apply({
51493 lockedHeader: header[0],
51497 //this.updateColumns();
51499 this.grid.getGridEl().dom.innerHTML = html;
51501 this.initElements();
51503 // a kludge to fix the random scolling effect in webkit
51504 this.el.on("scroll", function() {
51505 this.el.dom.scrollTop=0; // hopefully not recursive..
51508 this.scroller.on("scroll", this.handleScroll, this);
51509 this.lockedBody.on("mousewheel", this.handleWheel, this);
51510 this.mainBody.on("mousewheel", this.handleWheel, this);
51512 this.mainHd.on("mouseover", this.handleHdOver, this);
51513 this.mainHd.on("mouseout", this.handleHdOut, this);
51514 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
51515 {delegate: "."+this.splitClass});
51517 this.lockedHd.on("mouseover", this.handleHdOver, this);
51518 this.lockedHd.on("mouseout", this.handleHdOut, this);
51519 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
51520 {delegate: "."+this.splitClass});
51522 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
51523 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51526 this.updateSplitters();
51528 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
51529 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51530 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51533 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
51534 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
51536 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
51537 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
51539 if(this.grid.enableColLock !== false){
51540 this.hmenu.add('-',
51541 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
51542 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
51545 if(this.grid.enableColumnHide !== false){
51547 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
51548 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
51549 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
51551 this.hmenu.add('-',
51552 {id:"columns", text: this.columnsText, menu: this.colMenu}
51555 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
51557 this.grid.on("headercontextmenu", this.handleHdCtx, this);
51560 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
51561 this.dd = new Roo.grid.GridDragZone(this.grid, {
51562 ddGroup : this.grid.ddGroup || 'GridDD'
51568 for(var i = 0; i < colCount; i++){
51569 if(cm.isHidden(i)){
51570 this.hideColumn(i);
51572 if(cm.config[i].align){
51573 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
51574 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
51578 this.updateHeaderSortState();
51580 this.beforeInitialResize();
51583 // two part rendering gives faster view to the user
51584 this.renderPhase2.defer(1, this);
51587 renderPhase2 : function(){
51588 // render the rows now
51590 if(this.grid.autoSizeColumns){
51591 this.autoSizeColumns();
51595 beforeInitialResize : function(){
51599 onColumnSplitterMoved : function(i, w){
51600 this.userResized = true;
51601 var cm = this.grid.colModel;
51602 cm.setColumnWidth(i, w, true);
51603 var cid = cm.getColumnId(i);
51604 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51605 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51606 this.updateSplitters();
51608 this.grid.fireEvent("columnresize", i, w);
51611 syncRowHeights : function(startIndex, endIndex){
51612 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
51613 startIndex = startIndex || 0;
51614 var mrows = this.getBodyTable().rows;
51615 var lrows = this.getLockedTable().rows;
51616 var len = mrows.length-1;
51617 endIndex = Math.min(endIndex || len, len);
51618 for(var i = startIndex; i <= endIndex; i++){
51619 var m = mrows[i], l = lrows[i];
51620 var h = Math.max(m.offsetHeight, l.offsetHeight);
51621 m.style.height = l.style.height = h + "px";
51626 layout : function(initialRender, is2ndPass){
51628 var auto = g.autoHeight;
51629 var scrollOffset = 16;
51630 var c = g.getGridEl(), cm = this.cm,
51631 expandCol = g.autoExpandColumn,
51633 //c.beginMeasure();
51635 if(!c.dom.offsetWidth){ // display:none?
51637 this.lockedWrap.show();
51638 this.mainWrap.show();
51643 var hasLock = this.cm.isLocked(0);
51645 var tbh = this.headerPanel.getHeight();
51646 var bbh = this.footerPanel.getHeight();
51649 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
51650 var newHeight = ch + c.getBorderWidth("tb");
51652 newHeight = Math.min(g.maxHeight, newHeight);
51654 c.setHeight(newHeight);
51658 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
51661 var s = this.scroller;
51663 var csize = c.getSize(true);
51665 this.el.setSize(csize.width, csize.height);
51667 this.headerPanel.setWidth(csize.width);
51668 this.footerPanel.setWidth(csize.width);
51670 var hdHeight = this.mainHd.getHeight();
51671 var vw = csize.width;
51672 var vh = csize.height - (tbh + bbh);
51676 var bt = this.getBodyTable();
51677 var ltWidth = hasLock ?
51678 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
51680 var scrollHeight = bt.offsetHeight;
51681 var scrollWidth = ltWidth + bt.offsetWidth;
51682 var vscroll = false, hscroll = false;
51684 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
51686 var lw = this.lockedWrap, mw = this.mainWrap;
51687 var lb = this.lockedBody, mb = this.mainBody;
51689 setTimeout(function(){
51690 var t = s.dom.offsetTop;
51691 var w = s.dom.clientWidth,
51692 h = s.dom.clientHeight;
51695 lw.setSize(ltWidth, h);
51697 mw.setLeftTop(ltWidth, t);
51698 mw.setSize(w-ltWidth, h);
51700 lb.setHeight(h-hdHeight);
51701 mb.setHeight(h-hdHeight);
51703 if(is2ndPass !== true && !gv.userResized && expandCol){
51704 // high speed resize without full column calculation
51706 var ci = cm.getIndexById(expandCol);
51708 ci = cm.findColumnIndex(expandCol);
51710 ci = Math.max(0, ci); // make sure it's got at least the first col.
51711 var expandId = cm.getColumnId(ci);
51712 var tw = cm.getTotalWidth(false);
51713 var currentWidth = cm.getColumnWidth(ci);
51714 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
51715 if(currentWidth != cw){
51716 cm.setColumnWidth(ci, cw, true);
51717 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51718 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51719 gv.updateSplitters();
51720 gv.layout(false, true);
51732 onWindowResize : function(){
51733 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
51739 appendFooter : function(parentEl){
51743 sortAscText : "Sort Ascending",
51744 sortDescText : "Sort Descending",
51745 lockText : "Lock Column",
51746 unlockText : "Unlock Column",
51747 columnsText : "Columns"
51751 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
51752 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
51753 this.proxy.el.addClass('x-grid3-col-dd');
51756 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
51757 handleMouseDown : function(e){
51761 callHandleMouseDown : function(e){
51762 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
51767 * Ext JS Library 1.1.1
51768 * Copyright(c) 2006-2007, Ext JS, LLC.
51770 * Originally Released Under LGPL - original licence link has changed is not relivant.
51773 * <script type="text/javascript">
51777 // This is a support class used internally by the Grid components
51778 Roo.grid.SplitDragZone = function(grid, hd, hd2){
51780 this.view = grid.getView();
51781 this.proxy = this.view.resizeProxy;
51782 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
51783 "gridSplitters" + this.grid.getGridEl().id, {
51784 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
51786 this.setHandleElId(Roo.id(hd));
51787 this.setOuterHandleElId(Roo.id(hd2));
51788 this.scroll = false;
51790 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
51791 fly: Roo.Element.fly,
51793 b4StartDrag : function(x, y){
51794 this.view.headersDisabled = true;
51795 this.proxy.setHeight(this.view.mainWrap.getHeight());
51796 var w = this.cm.getColumnWidth(this.cellIndex);
51797 var minw = Math.max(w-this.grid.minColumnWidth, 0);
51798 this.resetConstraints();
51799 this.setXConstraint(minw, 1000);
51800 this.setYConstraint(0, 0);
51801 this.minX = x - minw;
51802 this.maxX = x + 1000;
51804 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
51808 handleMouseDown : function(e){
51809 ev = Roo.EventObject.setEvent(e);
51810 var t = this.fly(ev.getTarget());
51811 if(t.hasClass("x-grid-split")){
51812 this.cellIndex = this.view.getCellIndex(t.dom);
51813 this.split = t.dom;
51814 this.cm = this.grid.colModel;
51815 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
51816 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
51821 endDrag : function(e){
51822 this.view.headersDisabled = false;
51823 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
51824 var diff = endX - this.startPos;
51825 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
51828 autoOffset : function(){
51829 this.setDelta(0,0);
51833 * Ext JS Library 1.1.1
51834 * Copyright(c) 2006-2007, Ext JS, LLC.
51836 * Originally Released Under LGPL - original licence link has changed is not relivant.
51839 * <script type="text/javascript">
51843 // This is a support class used internally by the Grid components
51844 Roo.grid.GridDragZone = function(grid, config){
51845 this.view = grid.getView();
51846 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
51847 if(this.view.lockedBody){
51848 this.setHandleElId(Roo.id(this.view.mainBody.dom));
51849 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
51851 this.scroll = false;
51853 this.ddel = document.createElement('div');
51854 this.ddel.className = 'x-grid-dd-wrap';
51857 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
51858 ddGroup : "GridDD",
51860 getDragData : function(e){
51861 var t = Roo.lib.Event.getTarget(e);
51862 var rowIndex = this.view.findRowIndex(t);
51863 var sm = this.grid.selModel;
51865 //Roo.log(rowIndex);
51867 if (sm.getSelectedCell) {
51868 // cell selection..
51869 if (!sm.getSelectedCell()) {
51872 if (rowIndex != sm.getSelectedCell()[0]) {
51878 if(rowIndex !== false){
51883 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
51885 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
51888 if (e.hasModifier()){
51889 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
51892 Roo.log("getDragData");
51897 rowIndex: rowIndex,
51898 selections:sm.getSelections ? sm.getSelections() : (
51899 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
51906 onInitDrag : function(e){
51907 var data = this.dragData;
51908 this.ddel.innerHTML = this.grid.getDragDropText();
51909 this.proxy.update(this.ddel);
51910 // fire start drag?
51913 afterRepair : function(){
51914 this.dragging = false;
51917 getRepairXY : function(e, data){
51921 onEndDrag : function(data, e){
51925 onValidDrop : function(dd, e, id){
51930 beforeInvalidDrop : function(e, id){
51935 * Ext JS Library 1.1.1
51936 * Copyright(c) 2006-2007, Ext JS, LLC.
51938 * Originally Released Under LGPL - original licence link has changed is not relivant.
51941 * <script type="text/javascript">
51946 * @class Roo.grid.ColumnModel
51947 * @extends Roo.util.Observable
51948 * This is the default implementation of a ColumnModel used by the Grid. It defines
51949 * the columns in the grid.
51952 var colModel = new Roo.grid.ColumnModel([
51953 {header: "Ticker", width: 60, sortable: true, locked: true},
51954 {header: "Company Name", width: 150, sortable: true},
51955 {header: "Market Cap.", width: 100, sortable: true},
51956 {header: "$ Sales", width: 100, sortable: true, renderer: money},
51957 {header: "Employees", width: 100, sortable: true, resizable: false}
51962 * The config options listed for this class are options which may appear in each
51963 * individual column definition.
51964 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
51966 * @param {Object} config An Array of column config objects. See this class's
51967 * config objects for details.
51969 Roo.grid.ColumnModel = function(config){
51971 * The config passed into the constructor
51973 this.config = config;
51976 // if no id, create one
51977 // if the column does not have a dataIndex mapping,
51978 // map it to the order it is in the config
51979 for(var i = 0, len = config.length; i < len; i++){
51981 if(typeof c.dataIndex == "undefined"){
51984 if(typeof c.renderer == "string"){
51985 c.renderer = Roo.util.Format[c.renderer];
51987 if(typeof c.id == "undefined"){
51990 if(c.editor && c.editor.xtype){
51991 c.editor = Roo.factory(c.editor, Roo.grid);
51993 if(c.editor && c.editor.isFormField){
51994 c.editor = new Roo.grid.GridEditor(c.editor);
51996 this.lookup[c.id] = c;
52000 * The width of columns which have no width specified (defaults to 100)
52003 this.defaultWidth = 100;
52006 * Default sortable of columns which have no sortable specified (defaults to false)
52009 this.defaultSortable = false;
52013 * @event widthchange
52014 * Fires when the width of a column changes.
52015 * @param {ColumnModel} this
52016 * @param {Number} columnIndex The column index
52017 * @param {Number} newWidth The new width
52019 "widthchange": true,
52021 * @event headerchange
52022 * Fires when the text of a header changes.
52023 * @param {ColumnModel} this
52024 * @param {Number} columnIndex The column index
52025 * @param {Number} newText The new header text
52027 "headerchange": true,
52029 * @event hiddenchange
52030 * Fires when a column is hidden or "unhidden".
52031 * @param {ColumnModel} this
52032 * @param {Number} columnIndex The column index
52033 * @param {Boolean} hidden true if hidden, false otherwise
52035 "hiddenchange": true,
52037 * @event columnmoved
52038 * Fires when a column is moved.
52039 * @param {ColumnModel} this
52040 * @param {Number} oldIndex
52041 * @param {Number} newIndex
52043 "columnmoved" : true,
52045 * @event columlockchange
52046 * Fires when a column's locked state is changed
52047 * @param {ColumnModel} this
52048 * @param {Number} colIndex
52049 * @param {Boolean} locked true if locked
52051 "columnlockchange" : true
52053 Roo.grid.ColumnModel.superclass.constructor.call(this);
52055 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
52057 * @cfg {String} header The header text to display in the Grid view.
52060 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
52061 * {@link Roo.data.Record} definition from which to draw the column's value. If not
52062 * specified, the column's index is used as an index into the Record's data Array.
52065 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
52066 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
52069 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
52070 * Defaults to the value of the {@link #defaultSortable} property.
52071 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
52074 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
52077 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
52080 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
52083 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
52086 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
52087 * given the cell's data value. See {@link #setRenderer}. If not specified, the
52088 * default renderer uses the raw data value.
52091 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
52094 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
52098 * Returns the id of the column at the specified index.
52099 * @param {Number} index The column index
52100 * @return {String} the id
52102 getColumnId : function(index){
52103 return this.config[index].id;
52107 * Returns the column for a specified id.
52108 * @param {String} id The column id
52109 * @return {Object} the column
52111 getColumnById : function(id){
52112 return this.lookup[id];
52117 * Returns the column for a specified dataIndex.
52118 * @param {String} dataIndex The column dataIndex
52119 * @return {Object|Boolean} the column or false if not found
52121 getColumnByDataIndex: function(dataIndex){
52122 var index = this.findColumnIndex(dataIndex);
52123 return index > -1 ? this.config[index] : false;
52127 * Returns the index for a specified column id.
52128 * @param {String} id The column id
52129 * @return {Number} the index, or -1 if not found
52131 getIndexById : function(id){
52132 for(var i = 0, len = this.config.length; i < len; i++){
52133 if(this.config[i].id == id){
52141 * Returns the index for a specified column dataIndex.
52142 * @param {String} dataIndex The column dataIndex
52143 * @return {Number} the index, or -1 if not found
52146 findColumnIndex : function(dataIndex){
52147 for(var i = 0, len = this.config.length; i < len; i++){
52148 if(this.config[i].dataIndex == dataIndex){
52156 moveColumn : function(oldIndex, newIndex){
52157 var c = this.config[oldIndex];
52158 this.config.splice(oldIndex, 1);
52159 this.config.splice(newIndex, 0, c);
52160 this.dataMap = null;
52161 this.fireEvent("columnmoved", this, oldIndex, newIndex);
52164 isLocked : function(colIndex){
52165 return this.config[colIndex].locked === true;
52168 setLocked : function(colIndex, value, suppressEvent){
52169 if(this.isLocked(colIndex) == value){
52172 this.config[colIndex].locked = value;
52173 if(!suppressEvent){
52174 this.fireEvent("columnlockchange", this, colIndex, value);
52178 getTotalLockedWidth : function(){
52179 var totalWidth = 0;
52180 for(var i = 0; i < this.config.length; i++){
52181 if(this.isLocked(i) && !this.isHidden(i)){
52182 this.totalWidth += this.getColumnWidth(i);
52188 getLockedCount : function(){
52189 for(var i = 0, len = this.config.length; i < len; i++){
52190 if(!this.isLocked(i)){
52197 * Returns the number of columns.
52200 getColumnCount : function(visibleOnly){
52201 if(visibleOnly === true){
52203 for(var i = 0, len = this.config.length; i < len; i++){
52204 if(!this.isHidden(i)){
52210 return this.config.length;
52214 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
52215 * @param {Function} fn
52216 * @param {Object} scope (optional)
52217 * @return {Array} result
52219 getColumnsBy : function(fn, scope){
52221 for(var i = 0, len = this.config.length; i < len; i++){
52222 var c = this.config[i];
52223 if(fn.call(scope||this, c, i) === true){
52231 * Returns true if the specified column is sortable.
52232 * @param {Number} col The column index
52233 * @return {Boolean}
52235 isSortable : function(col){
52236 if(typeof this.config[col].sortable == "undefined"){
52237 return this.defaultSortable;
52239 return this.config[col].sortable;
52243 * Returns the rendering (formatting) function defined for the column.
52244 * @param {Number} col The column index.
52245 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
52247 getRenderer : function(col){
52248 if(!this.config[col].renderer){
52249 return Roo.grid.ColumnModel.defaultRenderer;
52251 return this.config[col].renderer;
52255 * Sets the rendering (formatting) function for a column.
52256 * @param {Number} col The column index
52257 * @param {Function} fn The function to use to process the cell's raw data
52258 * to return HTML markup for the grid view. The render function is called with
52259 * the following parameters:<ul>
52260 * <li>Data value.</li>
52261 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
52262 * <li>css A CSS style string to apply to the table cell.</li>
52263 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
52264 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
52265 * <li>Row index</li>
52266 * <li>Column index</li>
52267 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
52269 setRenderer : function(col, fn){
52270 this.config[col].renderer = fn;
52274 * Returns the width for the specified column.
52275 * @param {Number} col The column index
52278 getColumnWidth : function(col){
52279 return this.config[col].width * 1 || this.defaultWidth;
52283 * Sets the width for a column.
52284 * @param {Number} col The column index
52285 * @param {Number} width The new width
52287 setColumnWidth : function(col, width, suppressEvent){
52288 this.config[col].width = width;
52289 this.totalWidth = null;
52290 if(!suppressEvent){
52291 this.fireEvent("widthchange", this, col, width);
52296 * Returns the total width of all columns.
52297 * @param {Boolean} includeHidden True to include hidden column widths
52300 getTotalWidth : function(includeHidden){
52301 if(!this.totalWidth){
52302 this.totalWidth = 0;
52303 for(var i = 0, len = this.config.length; i < len; i++){
52304 if(includeHidden || !this.isHidden(i)){
52305 this.totalWidth += this.getColumnWidth(i);
52309 return this.totalWidth;
52313 * Returns the header for the specified column.
52314 * @param {Number} col The column index
52317 getColumnHeader : function(col){
52318 return this.config[col].header;
52322 * Sets the header for a column.
52323 * @param {Number} col The column index
52324 * @param {String} header The new header
52326 setColumnHeader : function(col, header){
52327 this.config[col].header = header;
52328 this.fireEvent("headerchange", this, col, header);
52332 * Returns the tooltip for the specified column.
52333 * @param {Number} col The column index
52336 getColumnTooltip : function(col){
52337 return this.config[col].tooltip;
52340 * Sets the tooltip for a column.
52341 * @param {Number} col The column index
52342 * @param {String} tooltip The new tooltip
52344 setColumnTooltip : function(col, tooltip){
52345 this.config[col].tooltip = tooltip;
52349 * Returns the dataIndex for the specified column.
52350 * @param {Number} col The column index
52353 getDataIndex : function(col){
52354 return this.config[col].dataIndex;
52358 * Sets the dataIndex for a column.
52359 * @param {Number} col The column index
52360 * @param {Number} dataIndex The new dataIndex
52362 setDataIndex : function(col, dataIndex){
52363 this.config[col].dataIndex = dataIndex;
52369 * Returns true if the cell is editable.
52370 * @param {Number} colIndex The column index
52371 * @param {Number} rowIndex The row index
52372 * @return {Boolean}
52374 isCellEditable : function(colIndex, rowIndex){
52375 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
52379 * Returns the editor defined for the cell/column.
52380 * return false or null to disable editing.
52381 * @param {Number} colIndex The column index
52382 * @param {Number} rowIndex The row index
52385 getCellEditor : function(colIndex, rowIndex){
52386 return this.config[colIndex].editor;
52390 * Sets if a column is editable.
52391 * @param {Number} col The column index
52392 * @param {Boolean} editable True if the column is editable
52394 setEditable : function(col, editable){
52395 this.config[col].editable = editable;
52400 * Returns true if the column is hidden.
52401 * @param {Number} colIndex The column index
52402 * @return {Boolean}
52404 isHidden : function(colIndex){
52405 return this.config[colIndex].hidden;
52410 * Returns true if the column width cannot be changed
52412 isFixed : function(colIndex){
52413 return this.config[colIndex].fixed;
52417 * Returns true if the column can be resized
52418 * @return {Boolean}
52420 isResizable : function(colIndex){
52421 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
52424 * Sets if a column is hidden.
52425 * @param {Number} colIndex The column index
52426 * @param {Boolean} hidden True if the column is hidden
52428 setHidden : function(colIndex, hidden){
52429 this.config[colIndex].hidden = hidden;
52430 this.totalWidth = null;
52431 this.fireEvent("hiddenchange", this, colIndex, hidden);
52435 * Sets the editor for a column.
52436 * @param {Number} col The column index
52437 * @param {Object} editor The editor object
52439 setEditor : function(col, editor){
52440 this.config[col].editor = editor;
52444 Roo.grid.ColumnModel.defaultRenderer = function(value){
52445 if(typeof value == "string" && value.length < 1){
52451 // Alias for backwards compatibility
52452 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
52455 * Ext JS Library 1.1.1
52456 * Copyright(c) 2006-2007, Ext JS, LLC.
52458 * Originally Released Under LGPL - original licence link has changed is not relivant.
52461 * <script type="text/javascript">
52465 * @class Roo.grid.AbstractSelectionModel
52466 * @extends Roo.util.Observable
52467 * Abstract base class for grid SelectionModels. It provides the interface that should be
52468 * implemented by descendant classes. This class should not be directly instantiated.
52471 Roo.grid.AbstractSelectionModel = function(){
52472 this.locked = false;
52473 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
52476 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
52477 /** @ignore Called by the grid automatically. Do not call directly. */
52478 init : function(grid){
52484 * Locks the selections.
52487 this.locked = true;
52491 * Unlocks the selections.
52493 unlock : function(){
52494 this.locked = false;
52498 * Returns true if the selections are locked.
52499 * @return {Boolean}
52501 isLocked : function(){
52502 return this.locked;
52506 * Ext JS Library 1.1.1
52507 * Copyright(c) 2006-2007, Ext JS, LLC.
52509 * Originally Released Under LGPL - original licence link has changed is not relivant.
52512 * <script type="text/javascript">
52515 * @extends Roo.grid.AbstractSelectionModel
52516 * @class Roo.grid.RowSelectionModel
52517 * The default SelectionModel used by {@link Roo.grid.Grid}.
52518 * It supports multiple selections and keyboard selection/navigation.
52520 * @param {Object} config
52522 Roo.grid.RowSelectionModel = function(config){
52523 Roo.apply(this, config);
52524 this.selections = new Roo.util.MixedCollection(false, function(o){
52529 this.lastActive = false;
52533 * @event selectionchange
52534 * Fires when the selection changes
52535 * @param {SelectionModel} this
52537 "selectionchange" : true,
52539 * @event afterselectionchange
52540 * Fires after the selection changes (eg. by key press or clicking)
52541 * @param {SelectionModel} this
52543 "afterselectionchange" : true,
52545 * @event beforerowselect
52546 * Fires when a row is selected being selected, return false to cancel.
52547 * @param {SelectionModel} this
52548 * @param {Number} rowIndex The selected index
52549 * @param {Boolean} keepExisting False if other selections will be cleared
52551 "beforerowselect" : true,
52554 * Fires when a row is selected.
52555 * @param {SelectionModel} this
52556 * @param {Number} rowIndex The selected index
52557 * @param {Roo.data.Record} r The record
52559 "rowselect" : true,
52561 * @event rowdeselect
52562 * Fires when a row is deselected.
52563 * @param {SelectionModel} this
52564 * @param {Number} rowIndex The selected index
52566 "rowdeselect" : true
52568 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
52569 this.locked = false;
52572 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
52574 * @cfg {Boolean} singleSelect
52575 * True to allow selection of only one row at a time (defaults to false)
52577 singleSelect : false,
52580 initEvents : function(){
52582 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
52583 this.grid.on("mousedown", this.handleMouseDown, this);
52584 }else{ // allow click to work like normal
52585 this.grid.on("rowclick", this.handleDragableRowClick, this);
52588 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
52589 "up" : function(e){
52591 this.selectPrevious(e.shiftKey);
52592 }else if(this.last !== false && this.lastActive !== false){
52593 var last = this.last;
52594 this.selectRange(this.last, this.lastActive-1);
52595 this.grid.getView().focusRow(this.lastActive);
52596 if(last !== false){
52600 this.selectFirstRow();
52602 this.fireEvent("afterselectionchange", this);
52604 "down" : function(e){
52606 this.selectNext(e.shiftKey);
52607 }else if(this.last !== false && this.lastActive !== false){
52608 var last = this.last;
52609 this.selectRange(this.last, this.lastActive+1);
52610 this.grid.getView().focusRow(this.lastActive);
52611 if(last !== false){
52615 this.selectFirstRow();
52617 this.fireEvent("afterselectionchange", this);
52622 var view = this.grid.view;
52623 view.on("refresh", this.onRefresh, this);
52624 view.on("rowupdated", this.onRowUpdated, this);
52625 view.on("rowremoved", this.onRemove, this);
52629 onRefresh : function(){
52630 var ds = this.grid.dataSource, i, v = this.grid.view;
52631 var s = this.selections;
52632 s.each(function(r){
52633 if((i = ds.indexOfId(r.id)) != -1){
52642 onRemove : function(v, index, r){
52643 this.selections.remove(r);
52647 onRowUpdated : function(v, index, r){
52648 if(this.isSelected(r)){
52649 v.onRowSelect(index);
52655 * @param {Array} records The records to select
52656 * @param {Boolean} keepExisting (optional) True to keep existing selections
52658 selectRecords : function(records, keepExisting){
52660 this.clearSelections();
52662 var ds = this.grid.dataSource;
52663 for(var i = 0, len = records.length; i < len; i++){
52664 this.selectRow(ds.indexOf(records[i]), true);
52669 * Gets the number of selected rows.
52672 getCount : function(){
52673 return this.selections.length;
52677 * Selects the first row in the grid.
52679 selectFirstRow : function(){
52684 * Select the last row.
52685 * @param {Boolean} keepExisting (optional) True to keep existing selections
52687 selectLastRow : function(keepExisting){
52688 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
52692 * Selects the row immediately following the last selected row.
52693 * @param {Boolean} keepExisting (optional) True to keep existing selections
52695 selectNext : function(keepExisting){
52696 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
52697 this.selectRow(this.last+1, keepExisting);
52698 this.grid.getView().focusRow(this.last);
52703 * Selects the row that precedes the last selected row.
52704 * @param {Boolean} keepExisting (optional) True to keep existing selections
52706 selectPrevious : function(keepExisting){
52708 this.selectRow(this.last-1, keepExisting);
52709 this.grid.getView().focusRow(this.last);
52714 * Returns the selected records
52715 * @return {Array} Array of selected records
52717 getSelections : function(){
52718 return [].concat(this.selections.items);
52722 * Returns the first selected record.
52725 getSelected : function(){
52726 return this.selections.itemAt(0);
52731 * Clears all selections.
52733 clearSelections : function(fast){
52734 if(this.locked) return;
52736 var ds = this.grid.dataSource;
52737 var s = this.selections;
52738 s.each(function(r){
52739 this.deselectRow(ds.indexOfId(r.id));
52743 this.selections.clear();
52750 * Selects all rows.
52752 selectAll : function(){
52753 if(this.locked) return;
52754 this.selections.clear();
52755 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
52756 this.selectRow(i, true);
52761 * Returns True if there is a selection.
52762 * @return {Boolean}
52764 hasSelection : function(){
52765 return this.selections.length > 0;
52769 * Returns True if the specified row is selected.
52770 * @param {Number/Record} record The record or index of the record to check
52771 * @return {Boolean}
52773 isSelected : function(index){
52774 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
52775 return (r && this.selections.key(r.id) ? true : false);
52779 * Returns True if the specified record id is selected.
52780 * @param {String} id The id of record to check
52781 * @return {Boolean}
52783 isIdSelected : function(id){
52784 return (this.selections.key(id) ? true : false);
52788 handleMouseDown : function(e, t){
52789 var view = this.grid.getView(), rowIndex;
52790 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
52793 if(e.shiftKey && this.last !== false){
52794 var last = this.last;
52795 this.selectRange(last, rowIndex, e.ctrlKey);
52796 this.last = last; // reset the last
52797 view.focusRow(rowIndex);
52799 var isSelected = this.isSelected(rowIndex);
52800 if(e.button !== 0 && isSelected){
52801 view.focusRow(rowIndex);
52802 }else if(e.ctrlKey && isSelected){
52803 this.deselectRow(rowIndex);
52804 }else if(!isSelected){
52805 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
52806 view.focusRow(rowIndex);
52809 this.fireEvent("afterselectionchange", this);
52812 handleDragableRowClick : function(grid, rowIndex, e)
52814 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
52815 this.selectRow(rowIndex, false);
52816 grid.view.focusRow(rowIndex);
52817 this.fireEvent("afterselectionchange", this);
52822 * Selects multiple rows.
52823 * @param {Array} rows Array of the indexes of the row to select
52824 * @param {Boolean} keepExisting (optional) True to keep existing selections
52826 selectRows : function(rows, keepExisting){
52828 this.clearSelections();
52830 for(var i = 0, len = rows.length; i < len; i++){
52831 this.selectRow(rows[i], true);
52836 * Selects a range of rows. All rows in between startRow and endRow are also selected.
52837 * @param {Number} startRow The index of the first row in the range
52838 * @param {Number} endRow The index of the last row in the range
52839 * @param {Boolean} keepExisting (optional) True to retain existing selections
52841 selectRange : function(startRow, endRow, keepExisting){
52842 if(this.locked) return;
52844 this.clearSelections();
52846 if(startRow <= endRow){
52847 for(var i = startRow; i <= endRow; i++){
52848 this.selectRow(i, true);
52851 for(var i = startRow; i >= endRow; i--){
52852 this.selectRow(i, true);
52858 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
52859 * @param {Number} startRow The index of the first row in the range
52860 * @param {Number} endRow The index of the last row in the range
52862 deselectRange : function(startRow, endRow, preventViewNotify){
52863 if(this.locked) return;
52864 for(var i = startRow; i <= endRow; i++){
52865 this.deselectRow(i, preventViewNotify);
52871 * @param {Number} row The index of the row to select
52872 * @param {Boolean} keepExisting (optional) True to keep existing selections
52874 selectRow : function(index, keepExisting, preventViewNotify){
52875 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
52876 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
52877 if(!keepExisting || this.singleSelect){
52878 this.clearSelections();
52880 var r = this.grid.dataSource.getAt(index);
52881 this.selections.add(r);
52882 this.last = this.lastActive = index;
52883 if(!preventViewNotify){
52884 this.grid.getView().onRowSelect(index);
52886 this.fireEvent("rowselect", this, index, r);
52887 this.fireEvent("selectionchange", this);
52893 * @param {Number} row The index of the row to deselect
52895 deselectRow : function(index, preventViewNotify){
52896 if(this.locked) return;
52897 if(this.last == index){
52900 if(this.lastActive == index){
52901 this.lastActive = false;
52903 var r = this.grid.dataSource.getAt(index);
52904 this.selections.remove(r);
52905 if(!preventViewNotify){
52906 this.grid.getView().onRowDeselect(index);
52908 this.fireEvent("rowdeselect", this, index);
52909 this.fireEvent("selectionchange", this);
52913 restoreLast : function(){
52915 this.last = this._last;
52920 acceptsNav : function(row, col, cm){
52921 return !cm.isHidden(col) && cm.isCellEditable(col, row);
52925 onEditorKey : function(field, e){
52926 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
52931 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
52933 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
52935 }else if(k == e.ENTER && !e.ctrlKey){
52939 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
52941 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
52943 }else if(k == e.ESC){
52947 g.startEditing(newCell[0], newCell[1]);
52952 * Ext JS Library 1.1.1
52953 * Copyright(c) 2006-2007, Ext JS, LLC.
52955 * Originally Released Under LGPL - original licence link has changed is not relivant.
52958 * <script type="text/javascript">
52961 * @class Roo.grid.CellSelectionModel
52962 * @extends Roo.grid.AbstractSelectionModel
52963 * This class provides the basic implementation for cell selection in a grid.
52965 * @param {Object} config The object containing the configuration of this model.
52966 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
52968 Roo.grid.CellSelectionModel = function(config){
52969 Roo.apply(this, config);
52971 this.selection = null;
52975 * @event beforerowselect
52976 * Fires before a cell is selected.
52977 * @param {SelectionModel} this
52978 * @param {Number} rowIndex The selected row index
52979 * @param {Number} colIndex The selected cell index
52981 "beforecellselect" : true,
52983 * @event cellselect
52984 * Fires when a cell is selected.
52985 * @param {SelectionModel} this
52986 * @param {Number} rowIndex The selected row index
52987 * @param {Number} colIndex The selected cell index
52989 "cellselect" : true,
52991 * @event selectionchange
52992 * Fires when the active selection changes.
52993 * @param {SelectionModel} this
52994 * @param {Object} selection null for no selection or an object (o) with two properties
52996 <li>o.record: the record object for the row the selection is in</li>
52997 <li>o.cell: An array of [rowIndex, columnIndex]</li>
53000 "selectionchange" : true,
53003 * Fires when the tab (or enter) was pressed on the last editable cell
53004 * You can use this to trigger add new row.
53005 * @param {SelectionModel} this
53009 * @event beforeeditnext
53010 * Fires before the next editable sell is made active
53011 * You can use this to skip to another cell or fire the tabend
53012 * if you set cell to false
53013 * @param {Object} eventdata object : { cell : [ row, col ] }
53015 "beforeeditnext" : true
53017 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
53020 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
53022 enter_is_tab: false,
53025 initEvents : function(){
53026 this.grid.on("mousedown", this.handleMouseDown, this);
53027 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
53028 var view = this.grid.view;
53029 view.on("refresh", this.onViewChange, this);
53030 view.on("rowupdated", this.onRowUpdated, this);
53031 view.on("beforerowremoved", this.clearSelections, this);
53032 view.on("beforerowsinserted", this.clearSelections, this);
53033 if(this.grid.isEditor){
53034 this.grid.on("beforeedit", this.beforeEdit, this);
53039 beforeEdit : function(e){
53040 this.select(e.row, e.column, false, true, e.record);
53044 onRowUpdated : function(v, index, r){
53045 if(this.selection && this.selection.record == r){
53046 v.onCellSelect(index, this.selection.cell[1]);
53051 onViewChange : function(){
53052 this.clearSelections(true);
53056 * Returns the currently selected cell,.
53057 * @return {Array} The selected cell (row, column) or null if none selected.
53059 getSelectedCell : function(){
53060 return this.selection ? this.selection.cell : null;
53064 * Clears all selections.
53065 * @param {Boolean} true to prevent the gridview from being notified about the change.
53067 clearSelections : function(preventNotify){
53068 var s = this.selection;
53070 if(preventNotify !== true){
53071 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
53073 this.selection = null;
53074 this.fireEvent("selectionchange", this, null);
53079 * Returns true if there is a selection.
53080 * @return {Boolean}
53082 hasSelection : function(){
53083 return this.selection ? true : false;
53087 handleMouseDown : function(e, t){
53088 var v = this.grid.getView();
53089 if(this.isLocked()){
53092 var row = v.findRowIndex(t);
53093 var cell = v.findCellIndex(t);
53094 if(row !== false && cell !== false){
53095 this.select(row, cell);
53101 * @param {Number} rowIndex
53102 * @param {Number} collIndex
53104 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
53105 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
53106 this.clearSelections();
53107 r = r || this.grid.dataSource.getAt(rowIndex);
53110 cell : [rowIndex, colIndex]
53112 if(!preventViewNotify){
53113 var v = this.grid.getView();
53114 v.onCellSelect(rowIndex, colIndex);
53115 if(preventFocus !== true){
53116 v.focusCell(rowIndex, colIndex);
53119 this.fireEvent("cellselect", this, rowIndex, colIndex);
53120 this.fireEvent("selectionchange", this, this.selection);
53125 isSelectable : function(rowIndex, colIndex, cm){
53126 return !cm.isHidden(colIndex);
53130 handleKeyDown : function(e){
53131 //Roo.log('Cell Sel Model handleKeyDown');
53132 if(!e.isNavKeyPress()){
53135 var g = this.grid, s = this.selection;
53138 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
53140 this.select(cell[0], cell[1]);
53145 var walk = function(row, col, step){
53146 return g.walkCells(row, col, step, sm.isSelectable, sm);
53148 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
53155 // handled by onEditorKey
53156 if (g.isEditor && g.editing) {
53160 newCell = walk(r, c-1, -1);
53162 newCell = walk(r, c+1, 1);
53167 newCell = walk(r+1, c, 1);
53171 newCell = walk(r-1, c, -1);
53175 newCell = walk(r, c+1, 1);
53179 newCell = walk(r, c-1, -1);
53184 if(g.isEditor && !g.editing){
53185 g.startEditing(r, c);
53194 this.select(newCell[0], newCell[1]);
53200 acceptsNav : function(row, col, cm){
53201 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53205 * @param {Number} field (not used) - as it's normally used as a listener
53206 * @param {Number} e - event - fake it by using
53208 * var e = Roo.EventObjectImpl.prototype;
53209 * e.keyCode = e.TAB
53213 onEditorKey : function(field, e){
53215 var k = e.getKey(),
53218 ed = g.activeEditor,
53220 ///Roo.log('onEditorKey' + k);
53223 if (this.enter_is_tab && k == e.ENTER) {
53229 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53231 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53237 } else if(k == e.ENTER && !e.ctrlKey){
53240 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53242 } else if(k == e.ESC){
53247 var ecall = { cell : newCell, forward : forward };
53248 this.fireEvent('beforeeditnext', ecall );
53249 newCell = ecall.cell;
53250 forward = ecall.forward;
53254 //Roo.log('next cell after edit');
53255 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
53256 } else if (forward) {
53257 // tabbed past last
53258 this.fireEvent.defer(100, this, ['tabend',this]);
53263 * Ext JS Library 1.1.1
53264 * Copyright(c) 2006-2007, Ext JS, LLC.
53266 * Originally Released Under LGPL - original licence link has changed is not relivant.
53269 * <script type="text/javascript">
53273 * @class Roo.grid.EditorGrid
53274 * @extends Roo.grid.Grid
53275 * Class for creating and editable grid.
53276 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53277 * The container MUST have some type of size defined for the grid to fill. The container will be
53278 * automatically set to position relative if it isn't already.
53279 * @param {Object} dataSource The data model to bind to
53280 * @param {Object} colModel The column model with info about this grid's columns
53282 Roo.grid.EditorGrid = function(container, config){
53283 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
53284 this.getGridEl().addClass("xedit-grid");
53286 if(!this.selModel){
53287 this.selModel = new Roo.grid.CellSelectionModel();
53290 this.activeEditor = null;
53294 * @event beforeedit
53295 * Fires before cell editing is triggered. The edit event object has the following properties <br />
53296 * <ul style="padding:5px;padding-left:16px;">
53297 * <li>grid - This grid</li>
53298 * <li>record - The record being edited</li>
53299 * <li>field - The field name being edited</li>
53300 * <li>value - The value for the field being edited.</li>
53301 * <li>row - The grid row index</li>
53302 * <li>column - The grid column index</li>
53303 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53305 * @param {Object} e An edit event (see above for description)
53307 "beforeedit" : true,
53310 * Fires after a cell is edited. <br />
53311 * <ul style="padding:5px;padding-left:16px;">
53312 * <li>grid - This grid</li>
53313 * <li>record - The record being edited</li>
53314 * <li>field - The field name being edited</li>
53315 * <li>value - The value being set</li>
53316 * <li>originalValue - The original value for the field, before the edit.</li>
53317 * <li>row - The grid row index</li>
53318 * <li>column - The grid column index</li>
53320 * @param {Object} e An edit event (see above for description)
53322 "afteredit" : true,
53324 * @event validateedit
53325 * Fires after a cell is edited, but before the value is set in the record.
53326 * You can use this to modify the value being set in the field, Return false
53327 * to cancel the change. The edit event object has the following properties <br />
53328 * <ul style="padding:5px;padding-left:16px;">
53329 * <li>editor - This editor</li>
53330 * <li>grid - This grid</li>
53331 * <li>record - The record being edited</li>
53332 * <li>field - The field name being edited</li>
53333 * <li>value - The value being set</li>
53334 * <li>originalValue - The original value for the field, before the edit.</li>
53335 * <li>row - The grid row index</li>
53336 * <li>column - The grid column index</li>
53337 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53339 * @param {Object} e An edit event (see above for description)
53341 "validateedit" : true
53343 this.on("bodyscroll", this.stopEditing, this);
53344 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
53347 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
53349 * @cfg {Number} clicksToEdit
53350 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
53357 trackMouseOver: false, // causes very odd FF errors
53359 onCellDblClick : function(g, row, col){
53360 this.startEditing(row, col);
53363 onEditComplete : function(ed, value, startValue){
53364 this.editing = false;
53365 this.activeEditor = null;
53366 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
53368 var field = this.colModel.getDataIndex(ed.col);
53373 originalValue: startValue,
53380 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
53383 if(String(value) !== String(startValue)){
53385 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
53386 r.set(field, e.value);
53387 // if we are dealing with a combo box..
53388 // then we also set the 'name' colum to be the displayField
53389 if (ed.field.displayField && ed.field.name) {
53390 r.set(ed.field.name, ed.field.el.dom.value);
53393 delete e.cancel; //?? why!!!
53394 this.fireEvent("afteredit", e);
53397 this.fireEvent("afteredit", e); // always fire it!
53399 this.view.focusCell(ed.row, ed.col);
53403 * Starts editing the specified for the specified row/column
53404 * @param {Number} rowIndex
53405 * @param {Number} colIndex
53407 startEditing : function(row, col){
53408 this.stopEditing();
53409 if(this.colModel.isCellEditable(col, row)){
53410 this.view.ensureVisible(row, col, true);
53412 var r = this.dataSource.getAt(row);
53413 var field = this.colModel.getDataIndex(col);
53414 var cell = Roo.get(this.view.getCell(row,col));
53419 value: r.data[field],
53424 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
53425 this.editing = true;
53426 var ed = this.colModel.getCellEditor(col, row);
53432 ed.render(ed.parentEl || document.body);
53438 (function(){ // complex but required for focus issues in safari, ie and opera
53442 ed.on("complete", this.onEditComplete, this, {single: true});
53443 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
53444 this.activeEditor = ed;
53445 var v = r.data[field];
53446 ed.startEdit(this.view.getCell(row, col), v);
53447 // combo's with 'displayField and name set
53448 if (ed.field.displayField && ed.field.name) {
53449 ed.field.el.dom.value = r.data[ed.field.name];
53453 }).defer(50, this);
53459 * Stops any active editing
53461 stopEditing : function(){
53462 if(this.activeEditor){
53463 this.activeEditor.completeEdit();
53465 this.activeEditor = null;
53469 * Called to get grid's drag proxy text, by default returns this.ddText.
53472 getDragDropText : function(){
53473 var count = this.selModel.getSelectedCell() ? 1 : 0;
53474 return String.format(this.ddText, count, count == 1 ? '' : 's');
53479 * Ext JS Library 1.1.1
53480 * Copyright(c) 2006-2007, Ext JS, LLC.
53482 * Originally Released Under LGPL - original licence link has changed is not relivant.
53485 * <script type="text/javascript">
53488 // private - not really -- you end up using it !
53489 // This is a support class used internally by the Grid components
53492 * @class Roo.grid.GridEditor
53493 * @extends Roo.Editor
53494 * Class for creating and editable grid elements.
53495 * @param {Object} config any settings (must include field)
53497 Roo.grid.GridEditor = function(field, config){
53498 if (!config && field.field) {
53500 field = Roo.factory(config.field, Roo.form);
53502 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
53503 field.monitorTab = false;
53506 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
53509 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
53512 alignment: "tl-tl",
53515 cls: "x-small-editor x-grid-editor",
53520 * Ext JS Library 1.1.1
53521 * Copyright(c) 2006-2007, Ext JS, LLC.
53523 * Originally Released Under LGPL - original licence link has changed is not relivant.
53526 * <script type="text/javascript">
53531 Roo.grid.PropertyRecord = Roo.data.Record.create([
53532 {name:'name',type:'string'}, 'value'
53536 Roo.grid.PropertyStore = function(grid, source){
53538 this.store = new Roo.data.Store({
53539 recordType : Roo.grid.PropertyRecord
53541 this.store.on('update', this.onUpdate, this);
53543 this.setSource(source);
53545 Roo.grid.PropertyStore.superclass.constructor.call(this);
53550 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
53551 setSource : function(o){
53553 this.store.removeAll();
53556 if(this.isEditableValue(o[k])){
53557 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
53560 this.store.loadRecords({records: data}, {}, true);
53563 onUpdate : function(ds, record, type){
53564 if(type == Roo.data.Record.EDIT){
53565 var v = record.data['value'];
53566 var oldValue = record.modified['value'];
53567 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
53568 this.source[record.id] = v;
53570 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
53577 getProperty : function(row){
53578 return this.store.getAt(row);
53581 isEditableValue: function(val){
53582 if(val && val instanceof Date){
53584 }else if(typeof val == 'object' || typeof val == 'function'){
53590 setValue : function(prop, value){
53591 this.source[prop] = value;
53592 this.store.getById(prop).set('value', value);
53595 getSource : function(){
53596 return this.source;
53600 Roo.grid.PropertyColumnModel = function(grid, store){
53603 g.PropertyColumnModel.superclass.constructor.call(this, [
53604 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
53605 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
53607 this.store = store;
53608 this.bselect = Roo.DomHelper.append(document.body, {
53609 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
53610 {tag: 'option', value: 'true', html: 'true'},
53611 {tag: 'option', value: 'false', html: 'false'}
53614 Roo.id(this.bselect);
53617 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
53618 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
53619 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
53620 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
53621 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
53623 this.renderCellDelegate = this.renderCell.createDelegate(this);
53624 this.renderPropDelegate = this.renderProp.createDelegate(this);
53627 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
53631 valueText : 'Value',
53633 dateFormat : 'm/j/Y',
53636 renderDate : function(dateVal){
53637 return dateVal.dateFormat(this.dateFormat);
53640 renderBool : function(bVal){
53641 return bVal ? 'true' : 'false';
53644 isCellEditable : function(colIndex, rowIndex){
53645 return colIndex == 1;
53648 getRenderer : function(col){
53650 this.renderCellDelegate : this.renderPropDelegate;
53653 renderProp : function(v){
53654 return this.getPropertyName(v);
53657 renderCell : function(val){
53659 if(val instanceof Date){
53660 rv = this.renderDate(val);
53661 }else if(typeof val == 'boolean'){
53662 rv = this.renderBool(val);
53664 return Roo.util.Format.htmlEncode(rv);
53667 getPropertyName : function(name){
53668 var pn = this.grid.propertyNames;
53669 return pn && pn[name] ? pn[name] : name;
53672 getCellEditor : function(colIndex, rowIndex){
53673 var p = this.store.getProperty(rowIndex);
53674 var n = p.data['name'], val = p.data['value'];
53676 if(typeof(this.grid.customEditors[n]) == 'string'){
53677 return this.editors[this.grid.customEditors[n]];
53679 if(typeof(this.grid.customEditors[n]) != 'undefined'){
53680 return this.grid.customEditors[n];
53682 if(val instanceof Date){
53683 return this.editors['date'];
53684 }else if(typeof val == 'number'){
53685 return this.editors['number'];
53686 }else if(typeof val == 'boolean'){
53687 return this.editors['boolean'];
53689 return this.editors['string'];
53695 * @class Roo.grid.PropertyGrid
53696 * @extends Roo.grid.EditorGrid
53697 * This class represents the interface of a component based property grid control.
53698 * <br><br>Usage:<pre><code>
53699 var grid = new Roo.grid.PropertyGrid("my-container-id", {
53707 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53708 * The container MUST have some type of size defined for the grid to fill. The container will be
53709 * automatically set to position relative if it isn't already.
53710 * @param {Object} config A config object that sets properties on this grid.
53712 Roo.grid.PropertyGrid = function(container, config){
53713 config = config || {};
53714 var store = new Roo.grid.PropertyStore(this);
53715 this.store = store;
53716 var cm = new Roo.grid.PropertyColumnModel(this, store);
53717 store.store.sort('name', 'ASC');
53718 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
53721 enableColLock:false,
53722 enableColumnMove:false,
53724 trackMouseOver: false,
53727 this.getGridEl().addClass('x-props-grid');
53728 this.lastEditRow = null;
53729 this.on('columnresize', this.onColumnResize, this);
53732 * @event beforepropertychange
53733 * Fires before a property changes (return false to stop?)
53734 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53735 * @param {String} id Record Id
53736 * @param {String} newval New Value
53737 * @param {String} oldval Old Value
53739 "beforepropertychange": true,
53741 * @event propertychange
53742 * Fires after a property changes
53743 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53744 * @param {String} id Record Id
53745 * @param {String} newval New Value
53746 * @param {String} oldval Old Value
53748 "propertychange": true
53750 this.customEditors = this.customEditors || {};
53752 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
53755 * @cfg {Object} customEditors map of colnames=> custom editors.
53756 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
53757 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
53758 * false disables editing of the field.
53762 * @cfg {Object} propertyNames map of property Names to their displayed value
53765 render : function(){
53766 Roo.grid.PropertyGrid.superclass.render.call(this);
53767 this.autoSize.defer(100, this);
53770 autoSize : function(){
53771 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
53773 this.view.fitColumns();
53777 onColumnResize : function(){
53778 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
53782 * Sets the data for the Grid
53783 * accepts a Key => Value object of all the elements avaiable.
53784 * @param {Object} data to appear in grid.
53786 setSource : function(source){
53787 this.store.setSource(source);
53791 * Gets all the data from the grid.
53792 * @return {Object} data data stored in grid
53794 getSource : function(){
53795 return this.store.getSource();
53799 * Ext JS Library 1.1.1
53800 * Copyright(c) 2006-2007, Ext JS, LLC.
53802 * Originally Released Under LGPL - original licence link has changed is not relivant.
53805 * <script type="text/javascript">
53809 * @class Roo.LoadMask
53810 * A simple utility class for generically masking elements while loading data. If the element being masked has
53811 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
53812 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
53813 * element's UpdateManager load indicator and will be destroyed after the initial load.
53815 * Create a new LoadMask
53816 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
53817 * @param {Object} config The config object
53819 Roo.LoadMask = function(el, config){
53820 this.el = Roo.get(el);
53821 Roo.apply(this, config);
53823 this.store.on('beforeload', this.onBeforeLoad, this);
53824 this.store.on('load', this.onLoad, this);
53825 this.store.on('loadexception', this.onLoadException, this);
53826 this.removeMask = false;
53828 var um = this.el.getUpdateManager();
53829 um.showLoadIndicator = false; // disable the default indicator
53830 um.on('beforeupdate', this.onBeforeLoad, this);
53831 um.on('update', this.onLoad, this);
53832 um.on('failure', this.onLoad, this);
53833 this.removeMask = true;
53837 Roo.LoadMask.prototype = {
53839 * @cfg {Boolean} removeMask
53840 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
53841 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
53844 * @cfg {String} msg
53845 * The text to display in a centered loading message box (defaults to 'Loading...')
53847 msg : 'Loading...',
53849 * @cfg {String} msgCls
53850 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
53852 msgCls : 'x-mask-loading',
53855 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
53861 * Disables the mask to prevent it from being displayed
53863 disable : function(){
53864 this.disabled = true;
53868 * Enables the mask so that it can be displayed
53870 enable : function(){
53871 this.disabled = false;
53874 onLoadException : function()
53876 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
53877 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
53879 this.el.unmask(this.removeMask);
53882 onLoad : function()
53884 this.el.unmask(this.removeMask);
53888 onBeforeLoad : function(){
53889 if(!this.disabled){
53890 this.el.mask(this.msg, this.msgCls);
53895 destroy : function(){
53897 this.store.un('beforeload', this.onBeforeLoad, this);
53898 this.store.un('load', this.onLoad, this);
53899 this.store.un('loadexception', this.onLoadException, this);
53901 var um = this.el.getUpdateManager();
53902 um.un('beforeupdate', this.onBeforeLoad, this);
53903 um.un('update', this.onLoad, this);
53904 um.un('failure', this.onLoad, this);
53909 * Ext JS Library 1.1.1
53910 * Copyright(c) 2006-2007, Ext JS, LLC.
53912 * Originally Released Under LGPL - original licence link has changed is not relivant.
53915 * <script type="text/javascript">
53920 * @class Roo.XTemplate
53921 * @extends Roo.Template
53922 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
53924 var t = new Roo.XTemplate(
53925 '<select name="{name}">',
53926 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
53930 // then append, applying the master template values
53933 * Supported features:
53938 {a_variable} - output encoded.
53939 {a_variable.format:("Y-m-d")} - call a method on the variable
53940 {a_variable:raw} - unencoded output
53941 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
53942 {a_variable:this.method_on_template(...)} - call a method on the template object.
53947 <tpl for="a_variable or condition.."></tpl>
53948 <tpl if="a_variable or condition"></tpl>
53949 <tpl exec="some javascript"></tpl>
53950 <tpl name="named_template"></tpl> (experimental)
53952 <tpl for="."></tpl> - just iterate the property..
53953 <tpl for=".."></tpl> - iterates with the parent (probably the template)
53957 Roo.XTemplate = function()
53959 Roo.XTemplate.superclass.constructor.apply(this, arguments);
53966 Roo.extend(Roo.XTemplate, Roo.Template, {
53969 * The various sub templates
53974 * basic tag replacing syntax
53977 * // you can fake an object call by doing this
53981 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
53984 * compile the template
53986 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
53989 compile: function()
53993 s = ['<tpl>', s, '</tpl>'].join('');
53995 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
53996 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
53997 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
53998 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
53999 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
54004 while(true == !!(m = s.match(re))){
54005 var forMatch = m[0].match(nameRe),
54006 ifMatch = m[0].match(ifRe),
54007 execMatch = m[0].match(execRe),
54008 namedMatch = m[0].match(namedRe),
54013 name = forMatch && forMatch[1] ? forMatch[1] : '';
54016 // if - puts fn into test..
54017 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
54019 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
54024 // exec - calls a function... returns empty if true is returned.
54025 exp = execMatch && execMatch[1] ? execMatch[1] : null;
54027 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
54035 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
54036 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
54037 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
54040 var uid = namedMatch ? namedMatch[1] : id;
54044 id: namedMatch ? namedMatch[1] : id,
54051 s = s.replace(m[0], '');
54053 s = s.replace(m[0], '{xtpl'+ id + '}');
54058 for(var i = tpls.length-1; i >= 0; --i){
54059 this.compileTpl(tpls[i]);
54060 this.tpls[tpls[i].id] = tpls[i];
54062 this.master = tpls[tpls.length-1];
54066 * same as applyTemplate, except it's done to one of the subTemplates
54067 * when using named templates, you can do:
54069 * var str = pl.applySubTemplate('your-name', values);
54072 * @param {Number} id of the template
54073 * @param {Object} values to apply to template
54074 * @param {Object} parent (normaly the instance of this object)
54076 applySubTemplate : function(id, values, parent)
54080 var t = this.tpls[id];
54084 if(t.test && !t.test.call(this, values, parent)){
54088 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
54089 Roo.log(e.toString());
54095 if(t.exec && t.exec.call(this, values, parent)){
54099 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
54100 Roo.log(e.toString());
54105 var vs = t.target ? t.target.call(this, values, parent) : values;
54106 parent = t.target ? values : parent;
54107 if(t.target && vs instanceof Array){
54109 for(var i = 0, len = vs.length; i < len; i++){
54110 buf[buf.length] = t.compiled.call(this, vs[i], parent);
54112 return buf.join('');
54114 return t.compiled.call(this, vs, parent);
54116 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
54117 Roo.log(e.toString());
54118 Roo.log(t.compiled);
54123 compileTpl : function(tpl)
54125 var fm = Roo.util.Format;
54126 var useF = this.disableFormats !== true;
54127 var sep = Roo.isGecko ? "+" : ",";
54128 var undef = function(str) {
54129 Roo.log("Property not found :" + str);
54133 var fn = function(m, name, format, args)
54135 //Roo.log(arguments);
54136 args = args ? args.replace(/\\'/g,"'") : args;
54137 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
54138 if (typeof(format) == 'undefined') {
54139 format= 'htmlEncode';
54141 if (format == 'raw' ) {
54145 if(name.substr(0, 4) == 'xtpl'){
54146 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
54149 // build an array of options to determine if value is undefined..
54151 // basically get 'xxxx.yyyy' then do
54152 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
54153 // (function () { Roo.log("Property not found"); return ''; })() :
54158 Roo.each(name.split('.'), function(st) {
54159 lookfor += (lookfor.length ? '.': '') + st;
54160 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
54163 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
54166 if(format && useF){
54168 args = args ? ',' + args : "";
54170 if(format.substr(0, 5) != "this."){
54171 format = "fm." + format + '(';
54173 format = 'this.call("'+ format.substr(5) + '", ';
54177 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
54181 // called with xxyx.yuu:(test,test)
54183 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
54185 // raw.. - :raw modifier..
54186 return "'"+ sep + udef_st + name + ")"+sep+"'";
54190 // branched to use + in gecko and [].join() in others
54192 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
54193 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
54196 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
54197 body.push(tpl.body.replace(/(\r\n|\n)/g,
54198 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
54199 body.push("'].join('');};};");
54200 body = body.join('');
54203 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
54205 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
54211 applyTemplate : function(values){
54212 return this.master.compiled.call(this, values, {});
54213 //var s = this.subs;
54216 apply : function(){
54217 return this.applyTemplate.apply(this, arguments);
54222 Roo.XTemplate.from = function(el){
54223 el = Roo.getDom(el);
54224 return new Roo.XTemplate(el.value || el.innerHTML);
54226 * Original code for Roojs - LGPL
54227 * <script type="text/javascript">
54231 * @class Roo.XComponent
54232 * A delayed Element creator...
54233 * Or a way to group chunks of interface together.
54235 * Mypart.xyx = new Roo.XComponent({
54237 parent : 'Mypart.xyz', // empty == document.element.!!
54241 disabled : function() {}
54243 tree : function() { // return an tree of xtype declared components
54247 xtype : 'NestedLayoutPanel',
54254 * It can be used to build a big heiracy, with parent etc.
54255 * or you can just use this to render a single compoent to a dom element
54256 * MYPART.render(Roo.Element | String(id) | dom_element )
54258 * @extends Roo.util.Observable
54260 * @param cfg {Object} configuration of component
54263 Roo.XComponent = function(cfg) {
54264 Roo.apply(this, cfg);
54268 * Fires when this the componnt is built
54269 * @param {Roo.XComponent} c the component
54274 this.region = this.region || 'center'; // default..
54275 Roo.XComponent.register(this);
54276 this.modules = false;
54277 this.el = false; // where the layout goes..
54281 Roo.extend(Roo.XComponent, Roo.util.Observable, {
54284 * The created element (with Roo.factory())
54285 * @type {Roo.Layout}
54291 * for BC - use el in new code
54292 * @type {Roo.Layout}
54298 * for BC - use el in new code
54299 * @type {Roo.Layout}
54304 * @cfg {Function|boolean} disabled
54305 * If this module is disabled by some rule, return true from the funtion
54310 * @cfg {String} parent
54311 * Name of parent element which it get xtype added to..
54316 * @cfg {String} order
54317 * Used to set the order in which elements are created (usefull for multiple tabs)
54322 * @cfg {String} name
54323 * String to display while loading.
54327 * @cfg {String} region
54328 * Region to render component to (defaults to center)
54333 * @cfg {Array} items
54334 * A single item array - the first element is the root of the tree..
54335 * It's done this way to stay compatible with the Xtype system...
54341 * The method that retuns the tree of parts that make up this compoennt
54348 * render element to dom or tree
54349 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
54352 render : function(el)
54356 var hp = this.parent ? 1 : 0;
54358 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
54359 // if parent is a '#.....' string, then let's use that..
54360 var ename = this.parent.substr(1)
54361 this.parent = false;
54362 el = Roo.get(ename);
54364 Roo.log("Warning - element can not be found :#" + ename );
54370 if (!this.parent) {
54372 el = el ? Roo.get(el) : false;
54374 // it's a top level one..
54376 el : new Roo.BorderLayout(el || document.body, {
54382 tabPosition: 'top',
54383 //resizeTabs: true,
54384 alwaysShowTabs: el && hp? false : true,
54385 hideTabs: el || !hp ? true : false,
54392 if (!this.parent.el) {
54393 // probably an old style ctor, which has been disabled.
54397 // The 'tree' method is '_tree now'
54399 var tree = this._tree ? this._tree() : this.tree();
54400 tree.region = tree.region || this.region;
54401 this.el = this.parent.el.addxtype(tree);
54402 this.fireEvent('built', this);
54404 this.panel = this.el;
54405 this.layout = this.panel.layout;
54406 this.parentLayout = this.parent.layout || false;
54412 Roo.apply(Roo.XComponent, {
54414 * @property hideProgress
54415 * true to disable the building progress bar.. usefull on single page renders.
54418 hideProgress : false,
54420 * @property buildCompleted
54421 * True when the builder has completed building the interface.
54424 buildCompleted : false,
54427 * @property topModule
54428 * the upper most module - uses document.element as it's constructor.
54435 * @property modules
54436 * array of modules to be created by registration system.
54437 * @type {Array} of Roo.XComponent
54442 * @property elmodules
54443 * array of modules to be created by which use #ID
54444 * @type {Array} of Roo.XComponent
54451 * Register components to be built later.
54453 * This solves the following issues
54454 * - Building is not done on page load, but after an authentication process has occured.
54455 * - Interface elements are registered on page load
54456 * - Parent Interface elements may not be loaded before child, so this handles that..
54463 module : 'Pman.Tab.projectMgr',
54465 parent : 'Pman.layout',
54466 disabled : false, // or use a function..
54469 * * @param {Object} details about module
54471 register : function(obj) {
54473 Roo.XComponent.event.fireEvent('register', obj);
54474 switch(typeof(obj.disabled) ) {
54480 if ( obj.disabled() ) {
54486 if (obj.disabled) {
54492 this.modules.push(obj);
54496 * convert a string to an object..
54497 * eg. 'AAA.BBB' -> finds AAA.BBB
54501 toObject : function(str)
54503 if (!str || typeof(str) == 'object') {
54506 if (str.substring(0,1) == '#') {
54510 var ar = str.split('.');
54515 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
54517 throw "Module not found : " + str;
54521 throw "Module not found : " + str;
54523 Roo.each(ar, function(e) {
54524 if (typeof(o[e]) == 'undefined') {
54525 throw "Module not found : " + str;
54536 * move modules into their correct place in the tree..
54539 preBuild : function ()
54542 Roo.each(this.modules , function (obj)
54544 Roo.XComponent.event.fireEvent('beforebuild', obj);
54546 var opar = obj.parent;
54548 obj.parent = this.toObject(opar);
54550 Roo.log("parent:toObject failed: " + e.toString());
54555 Roo.debug && Roo.log("GOT top level module");
54556 Roo.debug && Roo.log(obj);
54557 obj.modules = new Roo.util.MixedCollection(false,
54558 function(o) { return o.order + '' }
54560 this.topModule = obj;
54563 // parent is a string (usually a dom element name..)
54564 if (typeof(obj.parent) == 'string') {
54565 this.elmodules.push(obj);
54568 if (obj.parent.constructor != Roo.XComponent) {
54569 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
54571 if (!obj.parent.modules) {
54572 obj.parent.modules = new Roo.util.MixedCollection(false,
54573 function(o) { return o.order + '' }
54576 if (obj.parent.disabled) {
54577 obj.disabled = true;
54579 obj.parent.modules.add(obj);
54584 * make a list of modules to build.
54585 * @return {Array} list of modules.
54588 buildOrder : function()
54591 var cmp = function(a,b) {
54592 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
54594 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
54595 throw "No top level modules to build";
54598 // make a flat list in order of modules to build.
54599 var mods = this.topModule ? [ this.topModule ] : [];
54601 // elmodules (is a list of DOM based modules )
54602 Roo.each(this.elmodules, function(e) {
54607 // add modules to their parents..
54608 var addMod = function(m) {
54609 Roo.debug && Roo.log("build Order: add: " + m.name);
54612 if (m.modules && !m.disabled) {
54613 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
54614 m.modules.keySort('ASC', cmp );
54615 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
54617 m.modules.each(addMod);
54619 Roo.debug && Roo.log("build Order: no child modules");
54621 // not sure if this is used any more..
54623 m.finalize.name = m.name + " (clean up) ";
54624 mods.push(m.finalize);
54628 if (this.topModule) {
54629 this.topModule.modules.keySort('ASC', cmp );
54630 this.topModule.modules.each(addMod);
54636 * Build the registered modules.
54637 * @param {Object} parent element.
54638 * @param {Function} optional method to call after module has been added.
54646 var mods = this.buildOrder();
54648 //this.allmods = mods;
54649 //Roo.debug && Roo.log(mods);
54651 if (!mods.length) { // should not happen
54652 throw "NO modules!!!";
54656 var msg = "Building Interface...";
54657 // flash it up as modal - so we store the mask!?
54658 if (!this.hideProgress) {
54659 Roo.MessageBox.show({ title: 'loading' });
54660 Roo.MessageBox.show({
54661 title: "Please wait...",
54670 var total = mods.length;
54673 var progressRun = function() {
54674 if (!mods.length) {
54675 Roo.debug && Roo.log('hide?');
54676 if (!this.hideProgress) {
54677 Roo.MessageBox.hide();
54679 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
54685 var m = mods.shift();
54688 Roo.debug && Roo.log(m);
54689 // not sure if this is supported any more.. - modules that are are just function
54690 if (typeof(m) == 'function') {
54692 return progressRun.defer(10, _this);
54696 msg = "Building Interface " + (total - mods.length) +
54698 (m.name ? (' - ' + m.name) : '');
54699 Roo.debug && Roo.log(msg);
54700 if (!this.hideProgress) {
54701 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
54705 // is the module disabled?
54706 var disabled = (typeof(m.disabled) == 'function') ?
54707 m.disabled.call(m.module.disabled) : m.disabled;
54711 return progressRun(); // we do not update the display!
54719 // it's 10 on top level, and 1 on others??? why...
54720 return progressRun.defer(10, _this);
54723 progressRun.defer(1, _this);
54737 * wrapper for event.on - aliased later..
54738 * Typically use to register a event handler for register:
54740 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
54749 Roo.XComponent.event = new Roo.util.Observable({
54753 * Fires when an Component is registered,
54754 * set the disable property on the Component to stop registration.
54755 * @param {Roo.XComponent} c the component being registerd.
54760 * @event beforebuild
54761 * Fires before each Component is built
54762 * can be used to apply permissions.
54763 * @param {Roo.XComponent} c the component being registerd.
54766 'beforebuild' : true,
54768 * @event buildcomplete
54769 * Fires on the top level element when all elements have been built
54770 * @param {Roo.XComponent} the top level component.
54772 'buildcomplete' : true
54777 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
54778 //<script type="text/javascript">
54783 * @extends Roo.LayoutDialog
54784 * A generic Login Dialog..... - only one needed in theory!?!?
54786 * Fires XComponent builder on success...
54789 * username,password, lang = for login actions.
54790 * check = 1 for periodic checking that sesion is valid.
54791 * passwordRequest = email request password
54792 * logout = 1 = to logout
54794 * Affects: (this id="????" elements)
54795 * loading (removed) (used to indicate application is loading)
54796 * loading-mask (hides) (used to hide application when it's building loading)
54802 * Myapp.login = Roo.Login({
54818 Roo.Login = function(cfg)
54824 Roo.apply(this,cfg);
54826 Roo.onReady(function() {
54832 Roo.Login.superclass.constructor.call(this, this);
54833 //this.addxtype(this.items[0]);
54839 Roo.extend(Roo.Login, Roo.LayoutDialog, {
54842 * @cfg {String} method
54843 * Method used to query for login details.
54848 * @cfg {String} url
54849 * URL to query login data. - eg. baseURL + '/Login.php'
54855 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
54860 * @property checkFails
54861 * Number of times we have attempted to get authentication check, and failed.
54866 * @property intervalID
54867 * The window interval that does the constant login checking.
54873 onLoad : function() // called on page load...
54877 if (Roo.get('loading')) { // clear any loading indicator..
54878 Roo.get('loading').remove();
54881 //this.switchLang('en'); // set the language to english..
54884 success: function(response, opts) { // check successfull...
54886 var res = this.processResponse(response);
54887 this.checkFails =0;
54888 if (!res.success) { // error!
54889 this.checkFails = 5;
54890 //console.log('call failure');
54891 return this.failure(response,opts);
54894 if (!res.data.id) { // id=0 == login failure.
54895 return this.show();
54899 //console.log(success);
54900 this.fillAuth(res.data);
54901 this.checkFails =0;
54902 Roo.XComponent.build();
54904 failure : this.show
54910 check: function(cfg) // called every so often to refresh cookie etc..
54912 if (cfg.again) { // could be undefined..
54915 this.checkFails = 0;
54918 if (this.sending) {
54919 if ( this.checkFails > 4) {
54920 Roo.MessageBox.alert("Error",
54921 "Error getting authentication status. - try reloading, or wait a while", function() {
54922 _this.sending = false;
54927 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
54930 this.sending = true;
54937 method: this.method,
54938 success: cfg.success || this.success,
54939 failure : cfg.failure || this.failure,
54949 window.onbeforeunload = function() { }; // false does not work for IE..
54959 failure : function() {
54960 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
54961 document.location = document.location.toString() + '?ts=' + Math.random();
54965 success : function() {
54966 _this.user = false;
54967 this.checkFails =0;
54969 document.location = document.location.toString() + '?ts=' + Math.random();
54976 processResponse : function (response)
54980 res = Roo.decode(response.responseText);
54982 if (typeof(res) != 'object') {
54983 res = { success : false, errorMsg : res, errors : true };
54985 if (typeof(res.success) == 'undefined') {
54986 res.success = false;
54990 res = { success : false, errorMsg : response.responseText, errors : true };
54995 success : function(response, opts) // check successfull...
54997 this.sending = false;
54998 var res = this.processResponse(response);
54999 if (!res.success) {
55000 return this.failure(response, opts);
55002 if (!res.data || !res.data.id) {
55003 return this.failure(response,opts);
55005 //console.log(res);
55006 this.fillAuth(res.data);
55008 this.checkFails =0;
55013 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
55015 this.authUser = -1;
55016 this.sending = false;
55017 var res = this.processResponse(response);
55018 //console.log(res);
55019 if ( this.checkFails > 2) {
55021 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
55022 "Error getting authentication status. - try reloading");
55025 opts.callCfg.again = true;
55026 this.check.defer(1000, this, [ opts.callCfg ]);
55032 fillAuth: function(au) {
55033 this.startAuthCheck();
55034 this.authUserId = au.id;
55035 this.authUser = au;
55036 this.lastChecked = new Date();
55037 this.fireEvent('refreshed', au);
55038 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
55039 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
55040 au.lang = au.lang || 'en';
55041 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
55042 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
55043 this.switchLang(au.lang );
55046 // open system... - -on setyp..
55047 if (this.authUserId < 0) {
55048 Roo.MessageBox.alert("Warning",
55049 "This is an open system - please set up a admin user with a password.");
55052 //Pman.onload(); // which should do nothing if it's a re-auth result...
55057 startAuthCheck : function() // starter for timeout checking..
55059 if (this.intervalID) { // timer already in place...
55063 this.intervalID = window.setInterval(function() {
55064 _this.check(false);
55065 }, 120000); // every 120 secs = 2mins..
55071 switchLang : function (lang)
55073 _T = typeof(_T) == 'undefined' ? false : _T;
55074 if (!_T || !lang.length) {
55078 if (!_T && lang != 'en') {
55079 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
55083 if (typeof(_T.en) == 'undefined') {
55085 Roo.apply(_T.en, _T);
55088 if (typeof(_T[lang]) == 'undefined') {
55089 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
55094 Roo.apply(_T, _T[lang]);
55095 // just need to set the text values for everything...
55097 /* this will not work ...
55101 function formLabel(name, val) {
55102 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
55105 formLabel('password', "Password"+':');
55106 formLabel('username', "Email Address"+':');
55107 formLabel('lang', "Language"+':');
55108 this.dialog.setTitle("Login");
55109 this.dialog.buttons[0].setText("Forgot Password");
55110 this.dialog.buttons[1].setText("Login");
55129 collapsible: false,
55131 center: { // needed??
55134 // tabPosition: 'top',
55137 alwaysShowTabs: false
55141 show : function(dlg)
55143 //console.log(this);
55144 this.form = this.layout.getRegion('center').activePanel.form;
55145 this.form.dialog = dlg;
55146 this.buttons[0].form = this.form;
55147 this.buttons[0].dialog = dlg;
55148 this.buttons[1].form = this.form;
55149 this.buttons[1].dialog = dlg;
55151 //this.resizeToLogo.defer(1000,this);
55152 // this is all related to resizing for logos..
55153 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
55155 // this.resizeToLogo.defer(1000,this);
55158 //var w = Ext.lib.Dom.getViewWidth() - 100;
55159 //var h = Ext.lib.Dom.getViewHeight() - 100;
55160 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
55162 if (this.disabled) {
55167 if (this.user.id < 0) { // used for inital setup situations.
55171 if (this.intervalID) {
55172 // remove the timer
55173 window.clearInterval(this.intervalID);
55174 this.intervalID = false;
55178 if (Roo.get('loading')) {
55179 Roo.get('loading').remove();
55181 if (Roo.get('loading-mask')) {
55182 Roo.get('loading-mask').hide();
55185 //incomming._node = tnode;
55187 //this.dialog.modal = !modal;
55188 //this.dialog.show();
55192 this.form.setValues({
55193 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
55194 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
55197 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
55198 if (this.form.findField('username').getValue().length > 0 ){
55199 this.form.findField('password').focus();
55201 this.form.findField('username').focus();
55209 xtype : 'ContentPanel',
55221 style : 'margin: 10px;',
55224 actionfailed : function(f, act) {
55225 // form can return { errors: .... }
55227 //act.result.errors // invalid form element list...
55228 //act.result.errorMsg// invalid form element list...
55230 this.dialog.el.unmask();
55231 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
55232 "Login failed - communication error - try again.");
55235 actioncomplete: function(re, act) {
55237 Roo.state.Manager.set(
55238 this.dialog.realm + '.username',
55239 this.findField('username').getValue()
55241 Roo.state.Manager.set(
55242 this.dialog.realm + '.lang',
55243 this.findField('lang').getValue()
55246 this.dialog.fillAuth(act.result.data);
55248 this.dialog.hide();
55250 if (Roo.get('loading-mask')) {
55251 Roo.get('loading-mask').show();
55253 Roo.XComponent.build();
55261 xtype : 'TextField',
55263 fieldLabel: "Email Address",
55266 autoCreate : {tag: "input", type: "text", size: "20"}
55269 xtype : 'TextField',
55271 fieldLabel: "Password",
55272 inputType: 'password',
55275 autoCreate : {tag: "input", type: "text", size: "20"},
55277 specialkey : function(e,ev) {
55278 if (ev.keyCode == 13) {
55279 this.form.dialog.el.mask("Logging in");
55280 this.form.doAction('submit', {
55281 url: this.form.dialog.url,
55282 method: this.form.dialog.method
55289 xtype : 'ComboBox',
55291 fieldLabel: "Language",
55294 xtype : 'SimpleStore',
55295 fields: ['lang', 'ldisp'],
55297 [ 'en', 'English' ],
55298 [ 'zh_HK' , '\u7E41\u4E2D' ],
55299 [ 'zh_CN', '\u7C21\u4E2D' ]
55303 valueField : 'lang',
55304 hiddenName: 'lang',
55306 displayField:'ldisp',
55310 triggerAction: 'all',
55311 emptyText:'Select a Language...',
55312 selectOnFocus:true,
55314 select : function(cb, rec, ix) {
55315 this.form.switchLang(rec.data.lang);
55331 text : "Forgot Password",
55333 click : function() {
55334 //console.log(this);
55335 var n = this.form.findField('username').getValue();
55337 Roo.MessageBox.alert("Error", "Fill in your email address");
55341 url: this.dialog.url,
55345 method: this.dialog.method,
55346 success: function(response, opts) { // check successfull...
55348 var res = this.dialog.processResponse(response);
55349 if (!res.success) { // error!
55350 Roo.MessageBox.alert("Error" ,
55351 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
55354 Roo.MessageBox.alert("Notice" ,
55355 "Please check you email for the Password Reset message");
55357 failure : function() {
55358 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
55371 click : function () {
55373 this.dialog.el.mask("Logging in");
55374 this.form.doAction('submit', {
55375 url: this.dialog.url,
55376 method: this.dialog.method