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) {
2714 this.timeout[o.tId] = window.setTimeout(function() {
2715 oConn.abort(o, callback, true);
2716 }, callback.timeout);
2719 this.poll[o.tId] = window.setInterval(
2721 if (o.conn && o.conn.readyState == 4) {
2722 window.clearInterval(oConn.poll[o.tId]);
2723 delete oConn.poll[o.tId];
2725 if(callback && callback.timeout) {
2726 window.clearTimeout(oConn.timeout[o.tId]);
2727 delete oConn.timeout[o.tId];
2730 oConn.handleTransactionResponse(o, callback);
2733 , this.pollInterval);
2736 handleTransactionResponse:function(o, callback, isAbort)
2740 this.releaseObject(o);
2744 var httpStatus, responseObject;
2748 if (o.conn.status !== undefined && o.conn.status != 0) {
2749 httpStatus = o.conn.status;
2761 if (httpStatus >= 200 && httpStatus < 300) {
2762 responseObject = this.createResponseObject(o, callback.argument);
2763 if (callback.success) {
2764 if (!callback.scope) {
2765 callback.success(responseObject);
2770 callback.success.apply(callback.scope, [responseObject]);
2775 switch (httpStatus) {
2783 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2784 if (callback.failure) {
2785 if (!callback.scope) {
2786 callback.failure(responseObject);
2789 callback.failure.apply(callback.scope, [responseObject]);
2794 responseObject = this.createResponseObject(o, callback.argument);
2795 if (callback.failure) {
2796 if (!callback.scope) {
2797 callback.failure(responseObject);
2800 callback.failure.apply(callback.scope, [responseObject]);
2806 this.releaseObject(o);
2807 responseObject = null;
2810 createResponseObject:function(o, callbackArg)
2817 var headerStr = o.conn.getAllResponseHeaders();
2818 var header = headerStr.split('\n');
2819 for (var i = 0; i < header.length; i++) {
2820 var delimitPos = header[i].indexOf(':');
2821 if (delimitPos != -1) {
2822 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2830 obj.status = o.conn.status;
2831 obj.statusText = o.conn.statusText;
2832 obj.getResponseHeader = headerObj;
2833 obj.getAllResponseHeaders = headerStr;
2834 obj.responseText = o.conn.responseText;
2835 obj.responseXML = o.conn.responseXML;
2837 if (typeof callbackArg !== undefined) {
2838 obj.argument = callbackArg;
2844 createExceptionObject:function(tId, callbackArg, isAbort)
2847 var COMM_ERROR = 'communication failure';
2848 var ABORT_CODE = -1;
2849 var ABORT_ERROR = 'transaction aborted';
2855 obj.status = ABORT_CODE;
2856 obj.statusText = ABORT_ERROR;
2859 obj.status = COMM_CODE;
2860 obj.statusText = COMM_ERROR;
2864 obj.argument = callbackArg;
2870 initHeader:function(label, value, isDefault)
2872 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2874 if (headerObj[label] === undefined) {
2875 headerObj[label] = value;
2880 headerObj[label] = value + "," + headerObj[label];
2884 this.hasDefaultHeaders = true;
2887 this.hasHeaders = true;
2892 setHeader:function(o)
2894 if (this.hasDefaultHeaders) {
2895 for (var prop in this.defaultHeaders) {
2896 if (this.defaultHeaders.hasOwnProperty(prop)) {
2897 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2902 if (this.hasHeaders) {
2903 for (var prop in this.headers) {
2904 if (this.headers.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.headers[prop]);
2909 this.hasHeaders = false;
2913 resetDefaultHeaders:function() {
2914 delete this.defaultHeaders;
2915 this.defaultHeaders = {};
2916 this.hasDefaultHeaders = false;
2919 abort:function(o, callback, isTimeout)
2921 if(this.isCallInProgress(o)) {
2923 window.clearInterval(this.poll[o.tId]);
2924 delete this.poll[o.tId];
2926 delete this.timeout[o.tId];
2929 this.handleTransactionResponse(o, callback, true);
2939 isCallInProgress:function(o)
2942 return o.conn.readyState != 4 && o.conn.readyState != 0;
2951 releaseObject:function(o)
2960 'MSXML2.XMLHTTP.3.0',
2968 * Portions of this file are based on pieces of Yahoo User Interface Library
2969 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2970 * YUI licensed under the BSD License:
2971 * http://developer.yahoo.net/yui/license.txt
2972 * <script type="text/javascript">
2976 Roo.lib.Region = function(t, r, b, l) {
2986 Roo.lib.Region.prototype = {
2987 contains : function(region) {
2988 return ( region.left >= this.left &&
2989 region.right <= this.right &&
2990 region.top >= this.top &&
2991 region.bottom <= this.bottom );
2995 getArea : function() {
2996 return ( (this.bottom - this.top) * (this.right - this.left) );
2999 intersect : function(region) {
3000 var t = Math.max(this.top, region.top);
3001 var r = Math.min(this.right, region.right);
3002 var b = Math.min(this.bottom, region.bottom);
3003 var l = Math.max(this.left, region.left);
3005 if (b >= t && r >= l) {
3006 return new Roo.lib.Region(t, r, b, l);
3011 union : function(region) {
3012 var t = Math.min(this.top, region.top);
3013 var r = Math.max(this.right, region.right);
3014 var b = Math.max(this.bottom, region.bottom);
3015 var l = Math.min(this.left, region.left);
3017 return new Roo.lib.Region(t, r, b, l);
3020 adjust : function(t, l, b, r) {
3029 Roo.lib.Region.getRegion = function(el) {
3030 var p = Roo.lib.Dom.getXY(el);
3033 var r = p[0] + el.offsetWidth;
3034 var b = p[1] + el.offsetHeight;
3037 return new Roo.lib.Region(t, r, b, l);
3040 * Portions of this file are based on pieces of Yahoo User Interface Library
3041 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3042 * YUI licensed under the BSD License:
3043 * http://developer.yahoo.net/yui/license.txt
3044 * <script type="text/javascript">
3047 //@@dep Roo.lib.Region
3050 Roo.lib.Point = function(x, y) {
3051 if (x instanceof Array) {
3055 this.x = this.right = this.left = this[0] = x;
3056 this.y = this.top = this.bottom = this[1] = y;
3059 Roo.lib.Point.prototype = new Roo.lib.Region();
3061 * Portions of this file are based on pieces of Yahoo User Interface Library
3062 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3063 * YUI licensed under the BSD License:
3064 * http://developer.yahoo.net/yui/license.txt
3065 * <script type="text/javascript">
3072 scroll : function(el, args, duration, easing, cb, scope) {
3073 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3076 motion : function(el, args, duration, easing, cb, scope) {
3077 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3080 color : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3084 run : function(el, args, duration, easing, cb, scope, type) {
3085 type = type || Roo.lib.AnimBase;
3086 if (typeof easing == "string") {
3087 easing = Roo.lib.Easing[easing];
3089 var anim = new type(el, args, duration, easing);
3090 anim.animateX(function() {
3091 Roo.callback(cb, scope);
3097 * Portions of this file are based on pieces of Yahoo User Interface Library
3098 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3099 * YUI licensed under the BSD License:
3100 * http://developer.yahoo.net/yui/license.txt
3101 * <script type="text/javascript">
3109 if (!libFlyweight) {
3110 libFlyweight = new Roo.Element.Flyweight();
3112 libFlyweight.dom = el;
3113 return libFlyweight;
3116 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3120 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3122 this.init(el, attributes, duration, method);
3126 Roo.lib.AnimBase.fly = fly;
3130 Roo.lib.AnimBase.prototype = {
3132 toString: function() {
3133 var el = this.getEl();
3134 var id = el.id || el.tagName;
3135 return ("Anim " + id);
3139 noNegatives: /width|height|opacity|padding/i,
3140 offsetAttribute: /^((width|height)|(top|left))$/,
3141 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3142 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3146 doMethod: function(attr, start, end) {
3147 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3151 setAttribute: function(attr, val, unit) {
3152 if (this.patterns.noNegatives.test(attr)) {
3153 val = (val > 0) ? val : 0;
3156 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3160 getAttribute: function(attr) {
3161 var el = this.getEl();
3162 var val = fly(el).getStyle(attr);
3164 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3165 return parseFloat(val);
3168 var a = this.patterns.offsetAttribute.exec(attr) || [];
3169 var pos = !!( a[3] );
3170 var box = !!( a[2] );
3173 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3174 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3183 getDefaultUnit: function(attr) {
3184 if (this.patterns.defaultUnit.test(attr)) {
3191 animateX : function(callback, scope) {
3192 var f = function() {
3193 this.onComplete.removeListener(f);
3194 if (typeof callback == "function") {
3195 callback.call(scope || this, this);
3198 this.onComplete.addListener(f, this);
3203 setRuntimeAttribute: function(attr) {
3206 var attributes = this.attributes;
3208 this.runtimeAttributes[attr] = {};
3210 var isset = function(prop) {
3211 return (typeof prop !== 'undefined');
3214 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3218 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3221 if (isset(attributes[attr]['to'])) {
3222 end = attributes[attr]['to'];
3223 } else if (isset(attributes[attr]['by'])) {
3224 if (start.constructor == Array) {
3226 for (var i = 0, len = start.length; i < len; ++i) {
3227 end[i] = start[i] + attributes[attr]['by'][i];
3230 end = start + attributes[attr]['by'];
3234 this.runtimeAttributes[attr].start = start;
3235 this.runtimeAttributes[attr].end = end;
3238 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3242 init: function(el, attributes, duration, method) {
3244 var isAnimated = false;
3247 var startTime = null;
3250 var actualFrames = 0;
3253 el = Roo.getDom(el);
3256 this.attributes = attributes || {};
3259 this.duration = duration || 1;
3262 this.method = method || Roo.lib.Easing.easeNone;
3265 this.useSeconds = true;
3268 this.currentFrame = 0;
3271 this.totalFrames = Roo.lib.AnimMgr.fps;
3274 this.getEl = function() {
3279 this.isAnimated = function() {
3284 this.getStartTime = function() {
3288 this.runtimeAttributes = {};
3291 this.animate = function() {
3292 if (this.isAnimated()) {
3296 this.currentFrame = 0;
3298 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3300 Roo.lib.AnimMgr.registerElement(this);
3304 this.stop = function(finish) {
3306 this.currentFrame = this.totalFrames;
3307 this._onTween.fire();
3309 Roo.lib.AnimMgr.stop(this);
3312 var onStart = function() {
3313 this.onStart.fire();
3315 this.runtimeAttributes = {};
3316 for (var attr in this.attributes) {
3317 this.setRuntimeAttribute(attr);
3322 startTime = new Date();
3326 var onTween = function() {
3328 duration: new Date() - this.getStartTime(),
3329 currentFrame: this.currentFrame
3332 data.toString = function() {
3334 'duration: ' + data.duration +
3335 ', currentFrame: ' + data.currentFrame
3339 this.onTween.fire(data);
3341 var runtimeAttributes = this.runtimeAttributes;
3343 for (var attr in runtimeAttributes) {
3344 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3350 var onComplete = function() {
3351 var actual_duration = (new Date() - startTime) / 1000 ;
3354 duration: actual_duration,
3355 frames: actualFrames,
3356 fps: actualFrames / actual_duration
3359 data.toString = function() {
3361 'duration: ' + data.duration +
3362 ', frames: ' + data.frames +
3363 ', fps: ' + data.fps
3369 this.onComplete.fire(data);
3373 this._onStart = new Roo.util.Event(this);
3374 this.onStart = new Roo.util.Event(this);
3375 this.onTween = new Roo.util.Event(this);
3376 this._onTween = new Roo.util.Event(this);
3377 this.onComplete = new Roo.util.Event(this);
3378 this._onComplete = new Roo.util.Event(this);
3379 this._onStart.addListener(onStart);
3380 this._onTween.addListener(onTween);
3381 this._onComplete.addListener(onComplete);
3386 * Portions of this file are based on pieces of Yahoo User Interface Library
3387 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3388 * YUI licensed under the BSD License:
3389 * http://developer.yahoo.net/yui/license.txt
3390 * <script type="text/javascript">
3394 Roo.lib.AnimMgr = new function() {
3411 this.registerElement = function(tween) {
3412 queue[queue.length] = tween;
3414 tween._onStart.fire();
3419 this.unRegister = function(tween, index) {
3420 tween._onComplete.fire();
3421 index = index || getIndex(tween);
3423 queue.splice(index, 1);
3427 if (tweenCount <= 0) {
3433 this.start = function() {
3434 if (thread === null) {
3435 thread = setInterval(this.run, this.delay);
3440 this.stop = function(tween) {
3442 clearInterval(thread);
3444 for (var i = 0, len = queue.length; i < len; ++i) {
3445 if (queue[0].isAnimated()) {
3446 this.unRegister(queue[0], 0);
3455 this.unRegister(tween);
3460 this.run = function() {
3461 for (var i = 0, len = queue.length; i < len; ++i) {
3462 var tween = queue[i];
3463 if (!tween || !tween.isAnimated()) {
3467 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3469 tween.currentFrame += 1;
3471 if (tween.useSeconds) {
3472 correctFrame(tween);
3474 tween._onTween.fire();
3477 Roo.lib.AnimMgr.stop(tween, i);
3482 var getIndex = function(anim) {
3483 for (var i = 0, len = queue.length; i < len; ++i) {
3484 if (queue[i] == anim) {
3492 var correctFrame = function(tween) {
3493 var frames = tween.totalFrames;
3494 var frame = tween.currentFrame;
3495 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3496 var elapsed = (new Date() - tween.getStartTime());
3499 if (elapsed < tween.duration * 1000) {
3500 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3502 tweak = frames - (frame + 1);
3504 if (tweak > 0 && isFinite(tweak)) {
3505 if (tween.currentFrame + tweak >= frames) {
3506 tweak = frames - (frame + 1);
3509 tween.currentFrame += tweak;
3513 * Portions of this file are based on pieces of Yahoo User Interface Library
3514 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3515 * YUI licensed under the BSD License:
3516 * http://developer.yahoo.net/yui/license.txt
3517 * <script type="text/javascript">
3520 Roo.lib.Bezier = new function() {
3522 this.getPosition = function(points, t) {
3523 var n = points.length;
3526 for (var i = 0; i < n; ++i) {
3527 tmp[i] = [points[i][0], points[i][1]];
3530 for (var j = 1; j < n; ++j) {
3531 for (i = 0; i < n - j; ++i) {
3532 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3533 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3537 return [ tmp[0][0], tmp[0][1] ];
3541 * Portions of this file are based on pieces of Yahoo User Interface Library
3542 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3543 * YUI licensed under the BSD License:
3544 * http://developer.yahoo.net/yui/license.txt
3545 * <script type="text/javascript">
3550 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3551 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3554 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3556 var fly = Roo.lib.AnimBase.fly;
3558 var superclass = Y.ColorAnim.superclass;
3559 var proto = Y.ColorAnim.prototype;
3561 proto.toString = function() {
3562 var el = this.getEl();
3563 var id = el.id || el.tagName;
3564 return ("ColorAnim " + id);
3567 proto.patterns.color = /color$/i;
3568 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3569 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3570 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3571 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3574 proto.parseColor = function(s) {
3575 if (s.length == 3) {
3579 var c = this.patterns.hex.exec(s);
3580 if (c && c.length == 4) {
3581 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3584 c = this.patterns.rgb.exec(s);
3585 if (c && c.length == 4) {
3586 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3589 c = this.patterns.hex3.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3596 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3597 proto.getAttribute = function(attr) {
3598 var el = this.getEl();
3599 if (this.patterns.color.test(attr)) {
3600 var val = fly(el).getStyle(attr);
3602 if (this.patterns.transparent.test(val)) {
3603 var parent = el.parentNode;
3604 val = fly(parent).getStyle(attr);
3606 while (parent && this.patterns.transparent.test(val)) {
3607 parent = parent.parentNode;
3608 val = fly(parent).getStyle(attr);
3609 if (parent.tagName.toUpperCase() == 'HTML') {
3615 val = superclass.getAttribute.call(this, attr);
3620 proto.getAttribute = function(attr) {
3621 var el = this.getEl();
3622 if (this.patterns.color.test(attr)) {
3623 var val = fly(el).getStyle(attr);
3625 if (this.patterns.transparent.test(val)) {
3626 var parent = el.parentNode;
3627 val = fly(parent).getStyle(attr);
3629 while (parent && this.patterns.transparent.test(val)) {
3630 parent = parent.parentNode;
3631 val = fly(parent).getStyle(attr);
3632 if (parent.tagName.toUpperCase() == 'HTML') {
3638 val = superclass.getAttribute.call(this, attr);
3644 proto.doMethod = function(attr, start, end) {
3647 if (this.patterns.color.test(attr)) {
3649 for (var i = 0, len = start.length; i < len; ++i) {
3650 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3653 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3656 val = superclass.doMethod.call(this, attr, start, end);
3662 proto.setRuntimeAttribute = function(attr) {
3663 superclass.setRuntimeAttribute.call(this, attr);
3665 if (this.patterns.color.test(attr)) {
3666 var attributes = this.attributes;
3667 var start = this.parseColor(this.runtimeAttributes[attr].start);
3668 var end = this.parseColor(this.runtimeAttributes[attr].end);
3670 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3671 end = this.parseColor(attributes[attr].by);
3673 for (var i = 0, len = start.length; i < len; ++i) {
3674 end[i] = start[i] + end[i];
3678 this.runtimeAttributes[attr].start = start;
3679 this.runtimeAttributes[attr].end = end;
3685 * Portions of this file are based on pieces of Yahoo User Interface Library
3686 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3687 * YUI licensed under the BSD License:
3688 * http://developer.yahoo.net/yui/license.txt
3689 * <script type="text/javascript">
3695 easeNone: function (t, b, c, d) {
3696 return c * t / d + b;
3700 easeIn: function (t, b, c, d) {
3701 return c * (t /= d) * t + b;
3705 easeOut: function (t, b, c, d) {
3706 return -c * (t /= d) * (t - 2) + b;
3710 easeBoth: function (t, b, c, d) {
3711 if ((t /= d / 2) < 1) {
3712 return c / 2 * t * t + b;
3715 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3719 easeInStrong: function (t, b, c, d) {
3720 return c * (t /= d) * t * t * t + b;
3724 easeOutStrong: function (t, b, c, d) {
3725 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3729 easeBothStrong: function (t, b, c, d) {
3730 if ((t /= d / 2) < 1) {
3731 return c / 2 * t * t * t * t + b;
3734 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3739 elasticIn: function (t, b, c, d, a, p) {
3743 if ((t /= d) == 1) {
3750 if (!a || a < Math.abs(c)) {
3755 var s = p / (2 * Math.PI) * Math.asin(c / a);
3758 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3762 elasticOut: function (t, b, c, d, a, p) {
3766 if ((t /= d) == 1) {
3773 if (!a || a < Math.abs(c)) {
3778 var s = p / (2 * Math.PI) * Math.asin(c / a);
3781 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3785 elasticBoth: function (t, b, c, d, a, p) {
3790 if ((t /= d / 2) == 2) {
3798 if (!a || a < Math.abs(c)) {
3803 var s = p / (2 * Math.PI) * Math.asin(c / a);
3807 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3808 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3810 return a * Math.pow(2, -10 * (t -= 1)) *
3811 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3816 backIn: function (t, b, c, d, s) {
3817 if (typeof s == 'undefined') {
3820 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3824 backOut: function (t, b, c, d, s) {
3825 if (typeof s == 'undefined') {
3828 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3832 backBoth: function (t, b, c, d, s) {
3833 if (typeof s == 'undefined') {
3837 if ((t /= d / 2 ) < 1) {
3838 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3840 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3844 bounceIn: function (t, b, c, d) {
3845 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3849 bounceOut: function (t, b, c, d) {
3850 if ((t /= d) < (1 / 2.75)) {
3851 return c * (7.5625 * t * t) + b;
3852 } else if (t < (2 / 2.75)) {
3853 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3854 } else if (t < (2.5 / 2.75)) {
3855 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3857 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3861 bounceBoth: function (t, b, c, d) {
3863 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3865 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3868 * Portions of this file are based on pieces of Yahoo User Interface Library
3869 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3870 * YUI licensed under the BSD License:
3871 * http://developer.yahoo.net/yui/license.txt
3872 * <script type="text/javascript">
3876 Roo.lib.Motion = function(el, attributes, duration, method) {
3878 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3882 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3886 var superclass = Y.Motion.superclass;
3887 var proto = Y.Motion.prototype;
3889 proto.toString = function() {
3890 var el = this.getEl();
3891 var id = el.id || el.tagName;
3892 return ("Motion " + id);
3895 proto.patterns.points = /^points$/i;
3897 proto.setAttribute = function(attr, val, unit) {
3898 if (this.patterns.points.test(attr)) {
3899 unit = unit || 'px';
3900 superclass.setAttribute.call(this, 'left', val[0], unit);
3901 superclass.setAttribute.call(this, 'top', val[1], unit);
3903 superclass.setAttribute.call(this, attr, val, unit);
3907 proto.getAttribute = function(attr) {
3908 if (this.patterns.points.test(attr)) {
3910 superclass.getAttribute.call(this, 'left'),
3911 superclass.getAttribute.call(this, 'top')
3914 val = superclass.getAttribute.call(this, attr);
3920 proto.doMethod = function(attr, start, end) {
3923 if (this.patterns.points.test(attr)) {
3924 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3925 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3927 val = superclass.doMethod.call(this, attr, start, end);
3932 proto.setRuntimeAttribute = function(attr) {
3933 if (this.patterns.points.test(attr)) {
3934 var el = this.getEl();
3935 var attributes = this.attributes;
3937 var control = attributes['points']['control'] || [];
3941 if (control.length > 0 && !(control[0] instanceof Array)) {
3942 control = [control];
3945 for (i = 0,len = control.length; i < len; ++i) {
3946 tmp[i] = control[i];
3951 Roo.fly(el).position();
3953 if (isset(attributes['points']['from'])) {
3954 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3957 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3960 start = this.getAttribute('points');
3963 if (isset(attributes['points']['to'])) {
3964 end = translateValues.call(this, attributes['points']['to'], start);
3966 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3967 for (i = 0,len = control.length; i < len; ++i) {
3968 control[i] = translateValues.call(this, control[i], start);
3972 } else if (isset(attributes['points']['by'])) {
3973 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3975 for (i = 0,len = control.length; i < len; ++i) {
3976 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3980 this.runtimeAttributes[attr] = [start];
3982 if (control.length > 0) {
3983 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3986 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3989 superclass.setRuntimeAttribute.call(this, attr);
3993 var translateValues = function(val, start) {
3994 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3995 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4000 var isset = function(prop) {
4001 return (typeof prop !== 'undefined');
4005 * Portions of this file are based on pieces of Yahoo User Interface Library
4006 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4007 * YUI licensed under the BSD License:
4008 * http://developer.yahoo.net/yui/license.txt
4009 * <script type="text/javascript">
4013 Roo.lib.Scroll = function(el, attributes, duration, method) {
4015 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4019 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4023 var superclass = Y.Scroll.superclass;
4024 var proto = Y.Scroll.prototype;
4026 proto.toString = function() {
4027 var el = this.getEl();
4028 var id = el.id || el.tagName;
4029 return ("Scroll " + id);
4032 proto.doMethod = function(attr, start, end) {
4035 if (attr == 'scroll') {
4037 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4038 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4042 val = superclass.doMethod.call(this, attr, start, end);
4047 proto.getAttribute = function(attr) {
4049 var el = this.getEl();
4051 if (attr == 'scroll') {
4052 val = [ el.scrollLeft, el.scrollTop ];
4054 val = superclass.getAttribute.call(this, attr);
4060 proto.setAttribute = function(attr, val, unit) {
4061 var el = this.getEl();
4063 if (attr == 'scroll') {
4064 el.scrollLeft = val[0];
4065 el.scrollTop = val[1];
4067 superclass.setAttribute.call(this, attr, val, unit);
4073 * Ext JS Library 1.1.1
4074 * Copyright(c) 2006-2007, Ext JS, LLC.
4076 * Originally Released Under LGPL - original licence link has changed is not relivant.
4079 * <script type="text/javascript">
4083 // nasty IE9 hack - what a pile of crap that is..
4085 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4086 Range.prototype.createContextualFragment = function (html) {
4087 var doc = window.document;
4088 var container = doc.createElement("div");
4089 container.innerHTML = html;
4090 var frag = doc.createDocumentFragment(), n;
4091 while ((n = container.firstChild)) {
4092 frag.appendChild(n);
4099 * @class Roo.DomHelper
4100 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4101 * 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>.
4104 Roo.DomHelper = function(){
4105 var tempTableEl = null;
4106 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4107 var tableRe = /^table|tbody|tr|td$/i;
4109 // build as innerHTML where available
4111 var createHtml = function(o){
4112 if(typeof o == 'string'){
4121 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4122 if(attr == "style"){
4124 if(typeof s == "function"){
4127 if(typeof s == "string"){
4128 b += ' style="' + s + '"';
4129 }else if(typeof s == "object"){
4132 if(typeof s[key] != "function"){
4133 b += key + ":" + s[key] + ";";
4140 b += ' class="' + o["cls"] + '"';
4141 }else if(attr == "htmlFor"){
4142 b += ' for="' + o["htmlFor"] + '"';
4144 b += " " + attr + '="' + o[attr] + '"';
4148 if(emptyTags.test(o.tag)){
4152 var cn = o.children || o.cn;
4154 //http://bugs.kde.org/show_bug.cgi?id=71506
4155 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4156 for(var i = 0, len = cn.length; i < len; i++) {
4157 b += createHtml(cn[i], b);
4160 b += createHtml(cn, b);
4166 b += "</" + o.tag + ">";
4173 var createDom = function(o, parentNode){
4175 // defininition craeted..
4177 if (o.ns && o.ns != 'html') {
4179 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4180 xmlns[o.ns] = o.xmlns;
4183 if (typeof(xmlns[o.ns]) == 'undefined') {
4184 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4190 if (typeof(o) == 'string') {
4191 return parentNode.appendChild(document.createTextNode(o));
4193 o.tag = o.tag || div;
4194 if (o.ns && Roo.isIE) {
4196 o.tag = o.ns + ':' + o.tag;
4199 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4200 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4203 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4204 attr == "style" || typeof o[attr] == "function") continue;
4206 if(attr=="cls" && Roo.isIE){
4207 el.className = o["cls"];
4209 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4210 else el[attr] = o[attr];
4213 Roo.DomHelper.applyStyles(el, o.style);
4214 var cn = o.children || o.cn;
4216 //http://bugs.kde.org/show_bug.cgi?id=71506
4217 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4218 for(var i = 0, len = cn.length; i < len; i++) {
4219 createDom(cn[i], el);
4226 el.innerHTML = o.html;
4229 parentNode.appendChild(el);
4234 var ieTable = function(depth, s, h, e){
4235 tempTableEl.innerHTML = [s, h, e].join('');
4236 var i = -1, el = tempTableEl;
4243 // kill repeat to save bytes
4247 tbe = '</tbody>'+te,
4253 * Nasty code for IE's broken table implementation
4255 var insertIntoTable = function(tag, where, el, html){
4257 tempTableEl = document.createElement('div');
4262 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4265 if(where == 'beforebegin'){
4269 before = el.nextSibling;
4272 node = ieTable(4, trs, html, tre);
4274 else if(tag == 'tr'){
4275 if(where == 'beforebegin'){
4278 node = ieTable(3, tbs, html, tbe);
4279 } else if(where == 'afterend'){
4280 before = el.nextSibling;
4282 node = ieTable(3, tbs, html, tbe);
4283 } else{ // INTO a TR
4284 if(where == 'afterbegin'){
4285 before = el.firstChild;
4287 node = ieTable(4, trs, html, tre);
4289 } else if(tag == 'tbody'){
4290 if(where == 'beforebegin'){
4293 node = ieTable(2, ts, html, te);
4294 } else if(where == 'afterend'){
4295 before = el.nextSibling;
4297 node = ieTable(2, ts, html, te);
4299 if(where == 'afterbegin'){
4300 before = el.firstChild;
4302 node = ieTable(3, tbs, html, tbe);
4305 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4308 if(where == 'afterbegin'){
4309 before = el.firstChild;
4311 node = ieTable(2, ts, html, te);
4313 el.insertBefore(node, before);
4318 /** True to force the use of DOM instead of html fragments @type Boolean */
4322 * Returns the markup for the passed Element(s) config
4323 * @param {Object} o The Dom object spec (and children)
4326 markup : function(o){
4327 return createHtml(o);
4331 * Applies a style specification to an element
4332 * @param {String/HTMLElement} el The element to apply styles to
4333 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4334 * a function which returns such a specification.
4336 applyStyles : function(el, styles){
4339 if(typeof styles == "string"){
4340 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4342 while ((matches = re.exec(styles)) != null){
4343 el.setStyle(matches[1], matches[2]);
4345 }else if (typeof styles == "object"){
4346 for (var style in styles){
4347 el.setStyle(style, styles[style]);
4349 }else if (typeof styles == "function"){
4350 Roo.DomHelper.applyStyles(el, styles.call());
4356 * Inserts an HTML fragment into the Dom
4357 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4358 * @param {HTMLElement} el The context element
4359 * @param {String} html The HTML fragmenet
4360 * @return {HTMLElement} The new node
4362 insertHtml : function(where, el, html){
4363 where = where.toLowerCase();
4364 if(el.insertAdjacentHTML){
4365 if(tableRe.test(el.tagName)){
4367 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4373 el.insertAdjacentHTML('BeforeBegin', html);
4374 return el.previousSibling;
4376 el.insertAdjacentHTML('AfterBegin', html);
4377 return el.firstChild;
4379 el.insertAdjacentHTML('BeforeEnd', html);
4380 return el.lastChild;
4382 el.insertAdjacentHTML('AfterEnd', html);
4383 return el.nextSibling;
4385 throw 'Illegal insertion point -> "' + where + '"';
4387 var range = el.ownerDocument.createRange();
4391 range.setStartBefore(el);
4392 frag = range.createContextualFragment(html);
4393 el.parentNode.insertBefore(frag, el);
4394 return el.previousSibling;
4397 range.setStartBefore(el.firstChild);
4398 frag = range.createContextualFragment(html);
4399 el.insertBefore(frag, el.firstChild);
4400 return el.firstChild;
4402 el.innerHTML = html;
4403 return el.firstChild;
4407 range.setStartAfter(el.lastChild);
4408 frag = range.createContextualFragment(html);
4409 el.appendChild(frag);
4410 return el.lastChild;
4412 el.innerHTML = html;
4413 return el.lastChild;
4416 range.setStartAfter(el);
4417 frag = range.createContextualFragment(html);
4418 el.parentNode.insertBefore(frag, el.nextSibling);
4419 return el.nextSibling;
4421 throw 'Illegal insertion point -> "' + where + '"';
4425 * Creates new Dom element(s) and inserts them before el
4426 * @param {String/HTMLElement/Element} el The context element
4427 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4428 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4429 * @return {HTMLElement/Roo.Element} The new node
4431 insertBefore : function(el, o, returnElement){
4432 return this.doInsert(el, o, returnElement, "beforeBegin");
4436 * Creates new Dom element(s) and inserts them after el
4437 * @param {String/HTMLElement/Element} el The context element
4438 * @param {Object} o The Dom object spec (and children)
4439 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4440 * @return {HTMLElement/Roo.Element} The new node
4442 insertAfter : function(el, o, returnElement){
4443 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4447 * Creates new Dom element(s) and inserts them as the first child of el
4448 * @param {String/HTMLElement/Element} el The context element
4449 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4450 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4451 * @return {HTMLElement/Roo.Element} The new node
4453 insertFirst : function(el, o, returnElement){
4454 return this.doInsert(el, o, returnElement, "afterBegin");
4458 doInsert : function(el, o, returnElement, pos, sibling){
4459 el = Roo.getDom(el);
4461 if(this.useDom || o.ns){
4462 newNode = createDom(o, null);
4463 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4465 var html = createHtml(o);
4466 newNode = this.insertHtml(pos, el, html);
4468 return returnElement ? Roo.get(newNode, true) : newNode;
4472 * Creates new Dom element(s) and appends them to el
4473 * @param {String/HTMLElement/Element} el The context element
4474 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476 * @return {HTMLElement/Roo.Element} The new node
4478 append : function(el, o, returnElement){
4479 el = Roo.getDom(el);
4481 if(this.useDom || o.ns){
4482 newNode = createDom(o, null);
4483 el.appendChild(newNode);
4485 var html = createHtml(o);
4486 newNode = this.insertHtml("beforeEnd", el, html);
4488 return returnElement ? Roo.get(newNode, true) : newNode;
4492 * Creates new Dom element(s) and overwrites the contents of el with them
4493 * @param {String/HTMLElement/Element} el The context element
4494 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4495 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4496 * @return {HTMLElement/Roo.Element} The new node
4498 overwrite : function(el, o, returnElement){
4499 el = Roo.getDom(el);
4502 while (el.childNodes.length) {
4503 el.removeChild(el.firstChild);
4507 el.innerHTML = createHtml(o);
4510 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4514 * Creates a new Roo.DomHelper.Template from the Dom object spec
4515 * @param {Object} o The Dom object spec (and children)
4516 * @return {Roo.DomHelper.Template} The new template
4518 createTemplate : function(o){
4519 var html = createHtml(o);
4520 return new Roo.Template(html);
4526 * Ext JS Library 1.1.1
4527 * Copyright(c) 2006-2007, Ext JS, LLC.
4529 * Originally Released Under LGPL - original licence link has changed is not relivant.
4532 * <script type="text/javascript">
4536 * @class Roo.Template
4537 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4538 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4541 var t = new Roo.Template({
4542 html : '<div name="{id}">' +
4543 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4545 myformat: function (value, allValues) {
4546 return 'XX' + value;
4549 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4551 * For more information see this blog post with examples:
4552 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4553 - Create Elements using DOM, HTML fragments and Templates</a>.
4555 * @param {Object} cfg - Configuration object.
4557 Roo.Template = function(cfg){
4559 if(cfg instanceof Array){
4561 }else if(arguments.length > 1){
4562 cfg = Array.prototype.join.call(arguments, "");
4566 if (typeof(cfg) == 'object') {
4577 Roo.Template.prototype = {
4580 * @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..
4581 * it should be fixed so that template is observable...
4585 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4589 * Returns an HTML fragment of this template with the specified values applied.
4590 * @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'})
4591 * @return {String} The HTML fragment
4593 applyTemplate : function(values){
4597 return this.compiled(values);
4599 var useF = this.disableFormats !== true;
4600 var fm = Roo.util.Format, tpl = this;
4601 var fn = function(m, name, format, args){
4603 if(format.substr(0, 5) == "this."){
4604 return tpl.call(format.substr(5), values[name], values);
4607 // quoted values are required for strings in compiled templates,
4608 // but for non compiled we need to strip them
4609 // quoted reversed for jsmin
4610 var re = /^\s*['"](.*)["']\s*$/;
4611 args = args.split(',');
4612 for(var i = 0, len = args.length; i < len; i++){
4613 args[i] = args[i].replace(re, "$1");
4615 args = [values[name]].concat(args);
4617 args = [values[name]];
4619 return fm[format].apply(fm, args);
4622 return values[name] !== undefined ? values[name] : "";
4625 return this.html.replace(this.re, fn);
4643 this.loading = true;
4644 this.compiled = false;
4646 var cx = new Roo.data.Connection();
4650 success : function (response) {
4652 _t.html = response.responseText;
4656 failure : function(response) {
4657 Roo.log("Template failed to load from " + _t.url);
4664 * Sets the HTML used as the template and optionally compiles it.
4665 * @param {String} html
4666 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4667 * @return {Roo.Template} this
4669 set : function(html, compile){
4671 this.compiled = null;
4679 * True to disable format functions (defaults to false)
4682 disableFormats : false,
4685 * The regular expression used to match template variables
4689 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4692 * Compiles the template into an internal function, eliminating the RegEx overhead.
4693 * @return {Roo.Template} this
4695 compile : function(){
4696 var fm = Roo.util.Format;
4697 var useF = this.disableFormats !== true;
4698 var sep = Roo.isGecko ? "+" : ",";
4699 var fn = function(m, name, format, args){
4701 args = args ? ',' + args : "";
4702 if(format.substr(0, 5) != "this."){
4703 format = "fm." + format + '(';
4705 format = 'this.call("'+ format.substr(5) + '", ';
4709 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4711 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4714 // branched to use + in gecko and [].join() in others
4716 body = "this.compiled = function(values){ return '" +
4717 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4720 body = ["this.compiled = function(values){ return ['"];
4721 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4722 body.push("'].join('');};");
4723 body = body.join('');
4733 // private function used to call members
4734 call : function(fnName, value, allValues){
4735 return this[fnName](value, allValues);
4739 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4740 * @param {String/HTMLElement/Roo.Element} el The context element
4741 * @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'})
4742 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4743 * @return {HTMLElement/Roo.Element} The new node or Element
4745 insertFirst: function(el, values, returnElement){
4746 return this.doInsert('afterBegin', el, values, returnElement);
4750 * Applies the supplied values to the template and inserts the new node(s) before el.
4751 * @param {String/HTMLElement/Roo.Element} el The context element
4752 * @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'})
4753 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4754 * @return {HTMLElement/Roo.Element} The new node or Element
4756 insertBefore: function(el, values, returnElement){
4757 return this.doInsert('beforeBegin', el, values, returnElement);
4761 * Applies the supplied values to the template and inserts the new node(s) after el.
4762 * @param {String/HTMLElement/Roo.Element} el The context element
4763 * @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'})
4764 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4765 * @return {HTMLElement/Roo.Element} The new node or Element
4767 insertAfter : function(el, values, returnElement){
4768 return this.doInsert('afterEnd', el, values, returnElement);
4772 * Applies the supplied values to the template and appends the new node(s) to el.
4773 * @param {String/HTMLElement/Roo.Element} el The context element
4774 * @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'})
4775 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4776 * @return {HTMLElement/Roo.Element} The new node or Element
4778 append : function(el, values, returnElement){
4779 return this.doInsert('beforeEnd', el, values, returnElement);
4782 doInsert : function(where, el, values, returnEl){
4783 el = Roo.getDom(el);
4784 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4785 return returnEl ? Roo.get(newNode, true) : newNode;
4789 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4790 * @param {String/HTMLElement/Roo.Element} el The context element
4791 * @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'})
4792 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4793 * @return {HTMLElement/Roo.Element} The new node or Element
4795 overwrite : function(el, values, returnElement){
4796 el = Roo.getDom(el);
4797 el.innerHTML = this.applyTemplate(values);
4798 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4802 * Alias for {@link #applyTemplate}
4805 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4808 Roo.DomHelper.Template = Roo.Template;
4811 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4812 * @param {String/HTMLElement} el A DOM element or its id
4813 * @returns {Roo.Template} The created template
4816 Roo.Template.from = function(el){
4817 el = Roo.getDom(el);
4818 return new Roo.Template(el.value || el.innerHTML);
4821 * Ext JS Library 1.1.1
4822 * Copyright(c) 2006-2007, Ext JS, LLC.
4824 * Originally Released Under LGPL - original licence link has changed is not relivant.
4827 * <script type="text/javascript">
4832 * This is code is also distributed under MIT license for use
4833 * with jQuery and prototype JavaScript libraries.
4836 * @class Roo.DomQuery
4837 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).
4839 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>
4842 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.
4844 <h4>Element Selectors:</h4>
4846 <li> <b>*</b> any element</li>
4847 <li> <b>E</b> an element with the tag E</li>
4848 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4849 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4850 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4851 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4853 <h4>Attribute Selectors:</h4>
4854 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4856 <li> <b>E[foo]</b> has an attribute "foo"</li>
4857 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4858 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4859 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4860 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4861 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4862 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4864 <h4>Pseudo Classes:</h4>
4866 <li> <b>E:first-child</b> E is the first child of its parent</li>
4867 <li> <b>E:last-child</b> E is the last child of its parent</li>
4868 <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>
4869 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4870 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4871 <li> <b>E:only-child</b> E is the only child of its parent</li>
4872 <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>
4873 <li> <b>E:first</b> the first E in the resultset</li>
4874 <li> <b>E:last</b> the last E in the resultset</li>
4875 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4876 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4877 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4878 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4879 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4880 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4881 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4882 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4883 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4885 <h4>CSS Value Selectors:</h4>
4887 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4888 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4889 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4890 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4891 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4892 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4896 Roo.DomQuery = function(){
4897 var cache = {}, simpleCache = {}, valueCache = {};
4898 var nonSpace = /\S/;
4899 var trimRe = /^\s+|\s+$/g;
4900 var tplRe = /\{(\d+)\}/g;
4901 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4902 var tagTokenRe = /^(#)?([\w-\*]+)/;
4903 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4905 function child(p, index){
4907 var n = p.firstChild;
4909 if(n.nodeType == 1){
4920 while((n = n.nextSibling) && n.nodeType != 1);
4925 while((n = n.previousSibling) && n.nodeType != 1);
4929 function children(d){
4930 var n = d.firstChild, ni = -1;
4932 var nx = n.nextSibling;
4933 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4943 function byClassName(c, a, v){
4947 var r = [], ri = -1, cn;
4948 for(var i = 0, ci; ci = c[i]; i++){
4949 if((' '+ci.className+' ').indexOf(v) != -1){
4956 function attrValue(n, attr){
4957 if(!n.tagName && typeof n.length != "undefined"){
4966 if(attr == "class" || attr == "className"){
4969 return n.getAttribute(attr) || n[attr];
4973 function getNodes(ns, mode, tagName){
4974 var result = [], ri = -1, cs;
4978 tagName = tagName || "*";
4979 if(typeof ns.getElementsByTagName != "undefined"){
4983 for(var i = 0, ni; ni = ns[i]; i++){
4984 cs = ni.getElementsByTagName(tagName);
4985 for(var j = 0, ci; ci = cs[j]; j++){
4989 }else if(mode == "/" || mode == ">"){
4990 var utag = tagName.toUpperCase();
4991 for(var i = 0, ni, cn; ni = ns[i]; i++){
4992 cn = ni.children || ni.childNodes;
4993 for(var j = 0, cj; cj = cn[j]; j++){
4994 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4999 }else if(mode == "+"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, n; n = ns[i]; i++){
5002 while((n = n.nextSibling) && n.nodeType != 1);
5003 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5007 }else if(mode == "~"){
5008 for(var i = 0, n; n = ns[i]; i++){
5009 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5018 function concat(a, b){
5022 for(var i = 0, l = b.length; i < l; i++){
5028 function byTag(cs, tagName){
5029 if(cs.tagName || cs == document){
5035 var r = [], ri = -1;
5036 tagName = tagName.toLowerCase();
5037 for(var i = 0, ci; ci = cs[i]; i++){
5038 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5045 function byId(cs, attr, id){
5046 if(cs.tagName || cs == document){
5052 var r = [], ri = -1;
5053 for(var i = 0,ci; ci = cs[i]; i++){
5054 if(ci && ci.id == id){
5062 function byAttribute(cs, attr, value, op, custom){
5063 var r = [], ri = -1, st = custom=="{";
5064 var f = Roo.DomQuery.operators[op];
5065 for(var i = 0, ci; ci = cs[i]; i++){
5068 a = Roo.DomQuery.getStyle(ci, attr);
5070 else if(attr == "class" || attr == "className"){
5072 }else if(attr == "for"){
5074 }else if(attr == "href"){
5075 a = ci.getAttribute("href", 2);
5077 a = ci.getAttribute(attr);
5079 if((f && f(a, value)) || (!f && a)){
5086 function byPseudo(cs, name, value){
5087 return Roo.DomQuery.pseudos[name](cs, value);
5090 // This is for IE MSXML which does not support expandos.
5091 // IE runs the same speed using setAttribute, however FF slows way down
5092 // and Safari completely fails so they need to continue to use expandos.
5093 var isIE = window.ActiveXObject ? true : false;
5095 // this eval is stop the compressor from
5096 // renaming the variable to something shorter
5098 /** eval:var:batch */
5103 function nodupIEXml(cs){
5105 cs[0].setAttribute("_nodup", d);
5107 for(var i = 1, len = cs.length; i < len; i++){
5109 if(!c.getAttribute("_nodup") != d){
5110 c.setAttribute("_nodup", d);
5114 for(var i = 0, len = cs.length; i < len; i++){
5115 cs[i].removeAttribute("_nodup");
5124 var len = cs.length, c, i, r = cs, cj, ri = -1;
5125 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5128 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5129 return nodupIEXml(cs);
5133 for(i = 1; c = cs[i]; i++){
5138 for(var j = 0; j < i; j++){
5141 for(j = i+1; cj = cs[j]; j++){
5153 function quickDiffIEXml(c1, c2){
5155 for(var i = 0, len = c1.length; i < len; i++){
5156 c1[i].setAttribute("_qdiff", d);
5159 for(var i = 0, len = c2.length; i < len; i++){
5160 if(c2[i].getAttribute("_qdiff") != d){
5161 r[r.length] = c2[i];
5164 for(var i = 0, len = c1.length; i < len; i++){
5165 c1[i].removeAttribute("_qdiff");
5170 function quickDiff(c1, c2){
5171 var len1 = c1.length;
5175 if(isIE && c1[0].selectSingleNode){
5176 return quickDiffIEXml(c1, c2);
5179 for(var i = 0; i < len1; i++){
5183 for(var i = 0, len = c2.length; i < len; i++){
5184 if(c2[i]._qdiff != d){
5185 r[r.length] = c2[i];
5191 function quickId(ns, mode, root, id){
5193 var d = root.ownerDocument || root;
5194 return d.getElementById(id);
5196 ns = getNodes(ns, mode, "*");
5197 return byId(ns, null, id);
5201 getStyle : function(el, name){
5202 return Roo.fly(el).getStyle(name);
5205 * Compiles a selector/xpath query into a reusable function. The returned function
5206 * takes one parameter "root" (optional), which is the context node from where the query should start.
5207 * @param {String} selector The selector/xpath query
5208 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5209 * @return {Function}
5211 compile : function(path, type){
5212 type = type || "select";
5214 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5215 var q = path, mode, lq;
5216 var tk = Roo.DomQuery.matchers;
5217 var tklen = tk.length;
5220 // accept leading mode switch
5221 var lmode = q.match(modeRe);
5222 if(lmode && lmode[1]){
5223 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5224 q = q.replace(lmode[1], "");
5226 // strip leading slashes
5227 while(path.substr(0, 1)=="/"){
5228 path = path.substr(1);
5231 while(q && lq != q){
5233 var tm = q.match(tagTokenRe);
5234 if(type == "select"){
5237 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5239 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5241 q = q.replace(tm[0], "");
5242 }else if(q.substr(0, 1) != '@'){
5243 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5248 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5250 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5252 q = q.replace(tm[0], "");
5255 while(!(mm = q.match(modeRe))){
5256 var matched = false;
5257 for(var j = 0; j < tklen; j++){
5259 var m = q.match(t.re);
5261 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5264 q = q.replace(m[0], "");
5269 // prevent infinite loop on bad selector
5271 throw 'Error parsing selector, parsing failed at "' + q + '"';
5275 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5276 q = q.replace(mm[1], "");
5279 fn[fn.length] = "return nodup(n);\n}";
5282 * list of variables that need from compression as they are used by eval.
5292 * eval:var:byClassName
5294 * eval:var:byAttribute
5295 * eval:var:attrValue
5303 * Selects a group of elements.
5304 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5305 * @param {Node} root (optional) The start of the query (defaults to document).
5308 select : function(path, root, type){
5309 if(!root || root == document){
5312 if(typeof root == "string"){
5313 root = document.getElementById(root);
5315 var paths = path.split(",");
5317 for(var i = 0, len = paths.length; i < len; i++){
5318 var p = paths[i].replace(trimRe, "");
5320 cache[p] = Roo.DomQuery.compile(p);
5322 throw p + " is not a valid selector";
5325 var result = cache[p](root);
5326 if(result && result != document){
5327 results = results.concat(result);
5330 if(paths.length > 1){
5331 return nodup(results);
5337 * Selects a single element.
5338 * @param {String} selector The selector/xpath query
5339 * @param {Node} root (optional) The start of the query (defaults to document).
5342 selectNode : function(path, root){
5343 return Roo.DomQuery.select(path, root)[0];
5347 * Selects the value of a node, optionally replacing null with the defaultValue.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5350 * @param {String} defaultValue
5352 selectValue : function(path, root, defaultValue){
5353 path = path.replace(trimRe, "");
5354 if(!valueCache[path]){
5355 valueCache[path] = Roo.DomQuery.compile(path, "select");
5357 var n = valueCache[path](root);
5358 n = n[0] ? n[0] : n;
5359 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5360 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5364 * Selects the value of a node, parsing integers and floats.
5365 * @param {String} selector The selector/xpath query
5366 * @param {Node} root (optional) The start of the query (defaults to document).
5367 * @param {Number} defaultValue
5370 selectNumber : function(path, root, defaultValue){
5371 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5372 return parseFloat(v);
5376 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5377 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5378 * @param {String} selector The simple selector to test
5381 is : function(el, ss){
5382 if(typeof el == "string"){
5383 el = document.getElementById(el);
5385 var isArray = (el instanceof Array);
5386 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5387 return isArray ? (result.length == el.length) : (result.length > 0);
5391 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5392 * @param {Array} el An array of elements to filter
5393 * @param {String} selector The simple selector to test
5394 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5395 * the selector instead of the ones that match
5398 filter : function(els, ss, nonMatches){
5399 ss = ss.replace(trimRe, "");
5400 if(!simpleCache[ss]){
5401 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5403 var result = simpleCache[ss](els);
5404 return nonMatches ? quickDiff(result, els) : result;
5408 * Collection of matching regular expressions and code snippets.
5412 select: 'n = byClassName(n, null, " {1} ");'
5414 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5415 select: 'n = byPseudo(n, "{1}", "{2}");'
5417 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5418 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5421 select: 'n = byId(n, null, "{1}");'
5424 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5429 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5430 * 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, > <.
5433 "=" : function(a, v){
5436 "!=" : function(a, v){
5439 "^=" : function(a, v){
5440 return a && a.substr(0, v.length) == v;
5442 "$=" : function(a, v){
5443 return a && a.substr(a.length-v.length) == v;
5445 "*=" : function(a, v){
5446 return a && a.indexOf(v) !== -1;
5448 "%=" : function(a, v){
5449 return (a % v) == 0;
5451 "|=" : function(a, v){
5452 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5454 "~=" : function(a, v){
5455 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5460 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5461 * and the argument (if any) supplied in the selector.
5464 "first-child" : function(c){
5465 var r = [], ri = -1, n;
5466 for(var i = 0, ci; ci = n = c[i]; i++){
5467 while((n = n.previousSibling) && n.nodeType != 1);
5475 "last-child" : function(c){
5476 var r = [], ri = -1, n;
5477 for(var i = 0, ci; ci = n = c[i]; i++){
5478 while((n = n.nextSibling) && n.nodeType != 1);
5486 "nth-child" : function(c, a) {
5487 var r = [], ri = -1;
5488 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5489 var f = (m[1] || 1) - 0, l = m[2] - 0;
5490 for(var i = 0, n; n = c[i]; i++){
5491 var pn = n.parentNode;
5492 if (batch != pn._batch) {
5494 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5495 if(cn.nodeType == 1){
5502 if (l == 0 || n.nodeIndex == l){
5505 } else if ((n.nodeIndex + l) % f == 0){
5513 "only-child" : function(c){
5514 var r = [], ri = -1;;
5515 for(var i = 0, ci; ci = c[i]; i++){
5516 if(!prev(ci) && !next(ci)){
5523 "empty" : function(c){
5524 var r = [], ri = -1;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 var cns = ci.childNodes, j = 0, cn, empty = true;
5529 if(cn.nodeType == 1 || cn.nodeType == 3){
5541 "contains" : function(c, v){
5542 var r = [], ri = -1;
5543 for(var i = 0, ci; ci = c[i]; i++){
5544 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5551 "nodeValue" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if(ci.firstChild && ci.firstChild.nodeValue == v){
5561 "checked" : function(c){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.checked == true){
5571 "not" : function(c, ss){
5572 return Roo.DomQuery.filter(c, ss, true);
5575 "odd" : function(c){
5576 return this["nth-child"](c, "odd");
5579 "even" : function(c){
5580 return this["nth-child"](c, "even");
5583 "nth" : function(c, a){
5584 return c[a-1] || [];
5587 "first" : function(c){
5591 "last" : function(c){
5592 return c[c.length-1] || [];
5595 "has" : function(c, ss){
5596 var s = Roo.DomQuery.select;
5597 var r = [], ri = -1;
5598 for(var i = 0, ci; ci = c[i]; i++){
5599 if(s(ss, ci).length > 0){
5606 "next" : function(c, ss){
5607 var is = Roo.DomQuery.is;
5608 var r = [], ri = -1;
5609 for(var i = 0, ci; ci = c[i]; i++){
5618 "prev" : function(c, ss){
5619 var is = Roo.DomQuery.is;
5620 var r = [], ri = -1;
5621 for(var i = 0, ci; ci = c[i]; i++){
5634 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5635 * @param {String} path The selector/xpath query
5636 * @param {Node} root (optional) The start of the query (defaults to document).
5641 Roo.query = Roo.DomQuery.select;
5644 * Ext JS Library 1.1.1
5645 * Copyright(c) 2006-2007, Ext JS, LLC.
5647 * Originally Released Under LGPL - original licence link has changed is not relivant.
5650 * <script type="text/javascript">
5654 * @class Roo.util.Observable
5655 * Base class that provides a common interface for publishing events. Subclasses are expected to
5656 * to have a property "events" with all the events defined.<br>
5659 Employee = function(name){
5666 Roo.extend(Employee, Roo.util.Observable);
5668 * @param {Object} config properties to use (incuding events / listeners)
5671 Roo.util.Observable = function(cfg){
5674 this.addEvents(cfg.events || {});
5676 delete cfg.events; // make sure
5679 Roo.apply(this, cfg);
5682 this.on(this.listeners);
5683 delete this.listeners;
5686 Roo.util.Observable.prototype = {
5688 * @cfg {Object} listeners list of events and functions to call for this object,
5692 'click' : function(e) {
5702 * Fires the specified event with the passed parameters (minus the event name).
5703 * @param {String} eventName
5704 * @param {Object...} args Variable number of parameters are passed to handlers
5705 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5707 fireEvent : function(){
5708 var ce = this.events[arguments[0].toLowerCase()];
5709 if(typeof ce == "object"){
5710 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5717 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5720 * Appends an event handler to this component
5721 * @param {String} eventName The type of event to listen for
5722 * @param {Function} handler The method the event invokes
5723 * @param {Object} scope (optional) The scope in which to execute the handler
5724 * function. The handler function's "this" context.
5725 * @param {Object} options (optional) An object containing handler configuration
5726 * properties. This may contain any of the following properties:<ul>
5727 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5728 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5729 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5730 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5731 * by the specified number of milliseconds. If the event fires again within that time, the original
5732 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5735 * <b>Combining Options</b><br>
5736 * Using the options argument, it is possible to combine different types of listeners:<br>
5738 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5740 el.on('click', this.onClick, this, {
5747 * <b>Attaching multiple handlers in 1 call</b><br>
5748 * The method also allows for a single argument to be passed which is a config object containing properties
5749 * which specify multiple handlers.
5758 fn: this.onMouseOver,
5762 fn: this.onMouseOut,
5768 * Or a shorthand syntax which passes the same scope object to all handlers:
5771 'click': this.onClick,
5772 'mouseover': this.onMouseOver,
5773 'mouseout': this.onMouseOut,
5778 addListener : function(eventName, fn, scope, o){
5779 if(typeof eventName == "object"){
5782 if(this.filterOptRe.test(e)){
5785 if(typeof o[e] == "function"){
5787 this.addListener(e, o[e], o.scope, o);
5789 // individual options
5790 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5795 o = (!o || typeof o == "boolean") ? {} : o;
5796 eventName = eventName.toLowerCase();
5797 var ce = this.events[eventName] || true;
5798 if(typeof ce == "boolean"){
5799 ce = new Roo.util.Event(this, eventName);
5800 this.events[eventName] = ce;
5802 ce.addListener(fn, scope, o);
5806 * Removes a listener
5807 * @param {String} eventName The type of event to listen for
5808 * @param {Function} handler The handler to remove
5809 * @param {Object} scope (optional) The scope (this object) for the handler
5811 removeListener : function(eventName, fn, scope){
5812 var ce = this.events[eventName.toLowerCase()];
5813 if(typeof ce == "object"){
5814 ce.removeListener(fn, scope);
5819 * Removes all listeners for this object
5821 purgeListeners : function(){
5822 for(var evt in this.events){
5823 if(typeof this.events[evt] == "object"){
5824 this.events[evt].clearListeners();
5829 relayEvents : function(o, events){
5830 var createHandler = function(ename){
5832 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5835 for(var i = 0, len = events.length; i < len; i++){
5836 var ename = events[i];
5837 if(!this.events[ename]){ this.events[ename] = true; };
5838 o.on(ename, createHandler(ename), this);
5843 * Used to define events on this Observable
5844 * @param {Object} object The object with the events defined
5846 addEvents : function(o){
5850 Roo.applyIf(this.events, o);
5854 * Checks to see if this object has any listeners for a specified event
5855 * @param {String} eventName The name of the event to check for
5856 * @return {Boolean} True if the event is being listened for, else false
5858 hasListener : function(eventName){
5859 var e = this.events[eventName];
5860 return typeof e == "object" && e.listeners.length > 0;
5864 * Appends an event handler to this element (shorthand for addListener)
5865 * @param {String} eventName The type of event to listen for
5866 * @param {Function} handler The method the event invokes
5867 * @param {Object} scope (optional) The scope in which to execute the handler
5868 * function. The handler function's "this" context.
5869 * @param {Object} options (optional)
5872 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5874 * Removes a listener (shorthand for removeListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The handler to remove
5877 * @param {Object} scope (optional) The scope (this object) for the handler
5880 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5883 * Starts capture on the specified Observable. All events will be passed
5884 * to the supplied function with the event name + standard signature of the event
5885 * <b>before</b> the event is fired. If the supplied function returns false,
5886 * the event will not fire.
5887 * @param {Observable} o The Observable to capture
5888 * @param {Function} fn The function to call
5889 * @param {Object} scope (optional) The scope (this object) for the fn
5892 Roo.util.Observable.capture = function(o, fn, scope){
5893 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5897 * Removes <b>all</b> added captures from the Observable.
5898 * @param {Observable} o The Observable to release
5901 Roo.util.Observable.releaseCapture = function(o){
5902 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5907 var createBuffered = function(h, o, scope){
5908 var task = new Roo.util.DelayedTask();
5910 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5914 var createSingle = function(h, e, fn, scope){
5916 e.removeListener(fn, scope);
5917 return h.apply(scope, arguments);
5921 var createDelayed = function(h, o, scope){
5923 var args = Array.prototype.slice.call(arguments, 0);
5924 setTimeout(function(){
5925 h.apply(scope, args);
5930 Roo.util.Event = function(obj, name){
5933 this.listeners = [];
5936 Roo.util.Event.prototype = {
5937 addListener : function(fn, scope, options){
5938 var o = options || {};
5939 scope = scope || this.obj;
5940 if(!this.isListening(fn, scope)){
5941 var l = {fn: fn, scope: scope, options: o};
5944 h = createDelayed(h, o, scope);
5947 h = createSingle(h, this, fn, scope);
5950 h = createBuffered(h, o, scope);
5953 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5954 this.listeners.push(l);
5956 this.listeners = this.listeners.slice(0);
5957 this.listeners.push(l);
5962 findListener : function(fn, scope){
5963 scope = scope || this.obj;
5964 var ls = this.listeners;
5965 for(var i = 0, len = ls.length; i < len; i++){
5967 if(l.fn == fn && l.scope == scope){
5974 isListening : function(fn, scope){
5975 return this.findListener(fn, scope) != -1;
5978 removeListener : function(fn, scope){
5980 if((index = this.findListener(fn, scope)) != -1){
5982 this.listeners.splice(index, 1);
5984 this.listeners = this.listeners.slice(0);
5985 this.listeners.splice(index, 1);
5992 clearListeners : function(){
5993 this.listeners = [];
5997 var ls = this.listeners, scope, len = ls.length;
6000 var args = Array.prototype.slice.call(arguments, 0);
6001 for(var i = 0; i < len; i++){
6003 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6004 this.firing = false;
6008 this.firing = false;
6015 * Ext JS Library 1.1.1
6016 * Copyright(c) 2006-2007, Ext JS, LLC.
6018 * Originally Released Under LGPL - original licence link has changed is not relivant.
6021 * <script type="text/javascript">
6025 * @class Roo.EventManager
6026 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6027 * several useful events directly.
6028 * See {@link Roo.EventObject} for more details on normalized event objects.
6031 Roo.EventManager = function(){
6032 var docReadyEvent, docReadyProcId, docReadyState = false;
6033 var resizeEvent, resizeTask, textEvent, textSize;
6034 var E = Roo.lib.Event;
6035 var D = Roo.lib.Dom;
6038 var fireDocReady = function(){
6040 docReadyState = true;
6043 clearInterval(docReadyProcId);
6045 if(Roo.isGecko || Roo.isOpera) {
6046 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6049 var defer = document.getElementById("ie-deferred-loader");
6051 defer.onreadystatechange = null;
6052 defer.parentNode.removeChild(defer);
6056 docReadyEvent.fire();
6057 docReadyEvent.clearListeners();
6062 var initDocReady = function(){
6063 docReadyEvent = new Roo.util.Event();
6064 if(Roo.isGecko || Roo.isOpera) {
6065 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6067 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6068 var defer = document.getElementById("ie-deferred-loader");
6069 defer.onreadystatechange = function(){
6070 if(this.readyState == "complete"){
6074 }else if(Roo.isSafari){
6075 docReadyProcId = setInterval(function(){
6076 var rs = document.readyState;
6077 if(rs == "complete") {
6082 // no matter what, make sure it fires on load
6083 E.on(window, "load", fireDocReady);
6086 var createBuffered = function(h, o){
6087 var task = new Roo.util.DelayedTask(h);
6089 // create new event object impl so new events don't wipe out properties
6090 e = new Roo.EventObjectImpl(e);
6091 task.delay(o.buffer, h, null, [e]);
6095 var createSingle = function(h, el, ename, fn){
6097 Roo.EventManager.removeListener(el, ename, fn);
6102 var createDelayed = function(h, o){
6104 // create new event object impl so new events don't wipe out properties
6105 e = new Roo.EventObjectImpl(e);
6106 setTimeout(function(){
6112 var listen = function(element, ename, opt, fn, scope){
6113 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6114 fn = fn || o.fn; scope = scope || o.scope;
6115 var el = Roo.getDom(element);
6117 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6119 var h = function(e){
6120 e = Roo.EventObject.setEvent(e);
6123 t = e.getTarget(o.delegate, el);
6130 if(o.stopEvent === true){
6133 if(o.preventDefault === true){
6136 if(o.stopPropagation === true){
6137 e.stopPropagation();
6140 if(o.normalized === false){
6144 fn.call(scope || el, e, t, o);
6147 h = createDelayed(h, o);
6150 h = createSingle(h, el, ename, fn);
6153 h = createBuffered(h, o);
6155 fn._handlers = fn._handlers || [];
6156 fn._handlers.push([Roo.id(el), ename, h]);
6159 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6160 el.addEventListener("DOMMouseScroll", h, false);
6161 E.on(window, 'unload', function(){
6162 el.removeEventListener("DOMMouseScroll", h, false);
6165 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6166 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6171 var stopListening = function(el, ename, fn){
6172 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6174 for(var i = 0, len = hds.length; i < len; i++){
6176 if(h[0] == id && h[1] == ename){
6183 E.un(el, ename, hd);
6184 el = Roo.getDom(el);
6185 if(ename == "mousewheel" && el.addEventListener){
6186 el.removeEventListener("DOMMouseScroll", hd, false);
6188 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6189 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6193 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6200 * @scope Roo.EventManager
6205 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6206 * object with a Roo.EventObject
6207 * @param {Function} fn The method the event invokes
6208 * @param {Object} scope An object that becomes the scope of the handler
6209 * @param {boolean} override If true, the obj passed in becomes
6210 * the execution scope of the listener
6211 * @return {Function} The wrapped function
6214 wrap : function(fn, scope, override){
6216 Roo.EventObject.setEvent(e);
6217 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6222 * Appends an event handler to an element (shorthand for addListener)
6223 * @param {String/HTMLElement} element The html element or id to assign the
6224 * @param {String} eventName The type of event to listen for
6225 * @param {Function} handler The method the event invokes
6226 * @param {Object} scope (optional) The scope in which to execute the handler
6227 * function. The handler function's "this" context.
6228 * @param {Object} options (optional) An object containing handler configuration
6229 * properties. This may contain any of the following properties:<ul>
6230 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6231 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6232 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6233 * <li>preventDefault {Boolean} True to prevent the default action</li>
6234 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6235 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6236 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6237 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6238 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6239 * by the specified number of milliseconds. If the event fires again within that time, the original
6240 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6243 * <b>Combining Options</b><br>
6244 * Using the options argument, it is possible to combine different types of listeners:<br>
6246 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6248 el.on('click', this.onClick, this, {
6255 * <b>Attaching multiple handlers in 1 call</b><br>
6256 * The method also allows for a single argument to be passed which is a config object containing properties
6257 * which specify multiple handlers.
6267 fn: this.onMouseOver
6276 * Or a shorthand syntax:<br>
6279 'click' : this.onClick,
6280 'mouseover' : this.onMouseOver,
6281 'mouseout' : this.onMouseOut
6285 addListener : function(element, eventName, fn, scope, options){
6286 if(typeof eventName == "object"){
6292 if(typeof o[e] == "function"){
6294 listen(element, e, o, o[e], o.scope);
6296 // individual options
6297 listen(element, e, o[e]);
6302 return listen(element, eventName, options, fn, scope);
6306 * Removes an event handler
6308 * @param {String/HTMLElement} element The id or html element to remove the
6310 * @param {String} eventName The type of event
6311 * @param {Function} fn
6312 * @return {Boolean} True if a listener was actually removed
6314 removeListener : function(element, eventName, fn){
6315 return stopListening(element, eventName, fn);
6319 * Fires when the document is ready (before onload and before images are loaded). Can be
6320 * accessed shorthanded Roo.onReady().
6321 * @param {Function} fn The method the event invokes
6322 * @param {Object} scope An object that becomes the scope of the handler
6323 * @param {boolean} options
6325 onDocumentReady : function(fn, scope, options){
6326 if(docReadyState){ // if it already fired
6327 docReadyEvent.addListener(fn, scope, options);
6328 docReadyEvent.fire();
6329 docReadyEvent.clearListeners();
6335 docReadyEvent.addListener(fn, scope, options);
6339 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6340 * @param {Function} fn The method the event invokes
6341 * @param {Object} scope An object that becomes the scope of the handler
6342 * @param {boolean} options
6344 onWindowResize : function(fn, scope, options){
6346 resizeEvent = new Roo.util.Event();
6347 resizeTask = new Roo.util.DelayedTask(function(){
6348 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6350 E.on(window, "resize", function(){
6352 resizeTask.delay(50);
6354 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6358 resizeEvent.addListener(fn, scope, options);
6362 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6363 * @param {Function} fn The method the event invokes
6364 * @param {Object} scope An object that becomes the scope of the handler
6365 * @param {boolean} options
6367 onTextResize : function(fn, scope, options){
6369 textEvent = new Roo.util.Event();
6370 var textEl = new Roo.Element(document.createElement('div'));
6371 textEl.dom.className = 'x-text-resize';
6372 textEl.dom.innerHTML = 'X';
6373 textEl.appendTo(document.body);
6374 textSize = textEl.dom.offsetHeight;
6375 setInterval(function(){
6376 if(textEl.dom.offsetHeight != textSize){
6377 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6379 }, this.textResizeInterval);
6381 textEvent.addListener(fn, scope, options);
6385 * Removes the passed window resize listener.
6386 * @param {Function} fn The method the event invokes
6387 * @param {Object} scope The scope of handler
6389 removeResizeListener : function(fn, scope){
6391 resizeEvent.removeListener(fn, scope);
6396 fireResize : function(){
6398 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6402 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6406 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6408 textResizeInterval : 50
6413 * @scopeAlias pub=Roo.EventManager
6417 * Appends an event handler to an element (shorthand for addListener)
6418 * @param {String/HTMLElement} element The html element or id to assign the
6419 * @param {String} eventName The type of event to listen for
6420 * @param {Function} handler The method the event invokes
6421 * @param {Object} scope (optional) The scope in which to execute the handler
6422 * function. The handler function's "this" context.
6423 * @param {Object} options (optional) An object containing handler configuration
6424 * properties. This may contain any of the following properties:<ul>
6425 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6426 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6427 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6428 * <li>preventDefault {Boolean} True to prevent the default action</li>
6429 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6430 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6431 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6432 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6433 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6434 * by the specified number of milliseconds. If the event fires again within that time, the original
6435 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6438 * <b>Combining Options</b><br>
6439 * Using the options argument, it is possible to combine different types of listeners:<br>
6441 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6443 el.on('click', this.onClick, this, {
6450 * <b>Attaching multiple handlers in 1 call</b><br>
6451 * The method also allows for a single argument to be passed which is a config object containing properties
6452 * which specify multiple handlers.
6462 fn: this.onMouseOver
6471 * Or a shorthand syntax:<br>
6474 'click' : this.onClick,
6475 'mouseover' : this.onMouseOver,
6476 'mouseout' : this.onMouseOut
6480 pub.on = pub.addListener;
6481 pub.un = pub.removeListener;
6483 pub.stoppedMouseDownEvent = new Roo.util.Event();
6487 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6488 * @param {Function} fn The method the event invokes
6489 * @param {Object} scope An object that becomes the scope of the handler
6490 * @param {boolean} override If true, the obj passed in becomes
6491 * the execution scope of the listener
6495 Roo.onReady = Roo.EventManager.onDocumentReady;
6497 Roo.onReady(function(){
6498 var bd = Roo.get(document.body);
6503 : Roo.isGecko ? "roo-gecko"
6504 : Roo.isOpera ? "roo-opera"
6505 : Roo.isSafari ? "roo-safari" : ""];
6508 cls.push("roo-mac");
6511 cls.push("roo-linux");
6513 if(Roo.isBorderBox){
6514 cls.push('roo-border-box');
6516 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6517 var p = bd.dom.parentNode;
6519 p.className += ' roo-strict';
6522 bd.addClass(cls.join(' '));
6526 * @class Roo.EventObject
6527 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6528 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6531 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6533 var target = e.getTarget();
6536 var myDiv = Roo.get("myDiv");
6537 myDiv.on("click", handleClick);
6539 Roo.EventManager.on("myDiv", 'click', handleClick);
6540 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6544 Roo.EventObject = function(){
6546 var E = Roo.lib.Event;
6548 // safari keypress events for special keys return bad keycodes
6551 63235 : 39, // right
6554 63276 : 33, // page up
6555 63277 : 34, // page down
6556 63272 : 46, // delete
6561 // normalize button clicks
6562 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6563 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6565 Roo.EventObjectImpl = function(e){
6567 this.setEvent(e.browserEvent || e);
6570 Roo.EventObjectImpl.prototype = {
6572 * Used to fix doc tools.
6573 * @scope Roo.EventObject.prototype
6579 /** The normal browser event */
6580 browserEvent : null,
6581 /** The button pressed in a mouse event */
6583 /** True if the shift key was down during the event */
6585 /** True if the control key was down during the event */
6587 /** True if the alt key was down during the event */
6646 setEvent : function(e){
6647 if(e == this || (e && e.browserEvent)){ // already wrapped
6650 this.browserEvent = e;
6652 // normalize buttons
6653 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6654 if(e.type == 'click' && this.button == -1){
6658 this.shiftKey = e.shiftKey;
6659 // mac metaKey behaves like ctrlKey
6660 this.ctrlKey = e.ctrlKey || e.metaKey;
6661 this.altKey = e.altKey;
6662 // in getKey these will be normalized for the mac
6663 this.keyCode = e.keyCode;
6664 // keyup warnings on firefox.
6665 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6666 // cache the target for the delayed and or buffered events
6667 this.target = E.getTarget(e);
6669 this.xy = E.getXY(e);
6672 this.shiftKey = false;
6673 this.ctrlKey = false;
6674 this.altKey = false;
6684 * Stop the event (preventDefault and stopPropagation)
6686 stopEvent : function(){
6687 if(this.browserEvent){
6688 if(this.browserEvent.type == 'mousedown'){
6689 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6691 E.stopEvent(this.browserEvent);
6696 * Prevents the browsers default handling of the event.
6698 preventDefault : function(){
6699 if(this.browserEvent){
6700 E.preventDefault(this.browserEvent);
6705 isNavKeyPress : function(){
6706 var k = this.keyCode;
6707 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6708 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6711 isSpecialKey : function(){
6712 var k = this.keyCode;
6713 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6714 (k == 16) || (k == 17) ||
6715 (k >= 18 && k <= 20) ||
6716 (k >= 33 && k <= 35) ||
6717 (k >= 36 && k <= 39) ||
6718 (k >= 44 && k <= 45);
6721 * Cancels bubbling of the event.
6723 stopPropagation : function(){
6724 if(this.browserEvent){
6725 if(this.type == 'mousedown'){
6726 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6728 E.stopPropagation(this.browserEvent);
6733 * Gets the key code for the event.
6736 getCharCode : function(){
6737 return this.charCode || this.keyCode;
6741 * Returns a normalized keyCode for the event.
6742 * @return {Number} The key code
6744 getKey : function(){
6745 var k = this.keyCode || this.charCode;
6746 return Roo.isSafari ? (safariKeys[k] || k) : k;
6750 * Gets the x coordinate of the event.
6753 getPageX : function(){
6758 * Gets the y coordinate of the event.
6761 getPageY : function(){
6766 * Gets the time of the event.
6769 getTime : function(){
6770 if(this.browserEvent){
6771 return E.getTime(this.browserEvent);
6777 * Gets the page coordinates of the event.
6778 * @return {Array} The xy values like [x, y]
6785 * Gets the target for the event.
6786 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6787 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6788 search as a number or element (defaults to 10 || document.body)
6789 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6790 * @return {HTMLelement}
6792 getTarget : function(selector, maxDepth, returnEl){
6793 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6796 * Gets the related target.
6797 * @return {HTMLElement}
6799 getRelatedTarget : function(){
6800 if(this.browserEvent){
6801 return E.getRelatedTarget(this.browserEvent);
6807 * Normalizes mouse wheel delta across browsers
6808 * @return {Number} The delta
6810 getWheelDelta : function(){
6811 var e = this.browserEvent;
6813 if(e.wheelDelta){ /* IE/Opera. */
6814 delta = e.wheelDelta/120;
6815 }else if(e.detail){ /* Mozilla case. */
6816 delta = -e.detail/3;
6822 * Returns true if the control, meta, shift or alt key was pressed during this event.
6825 hasModifier : function(){
6826 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6830 * Returns true if the target of this event equals el or is a child of el
6831 * @param {String/HTMLElement/Element} el
6832 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6835 within : function(el, related){
6836 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6837 return t && Roo.fly(el).contains(t);
6840 getPoint : function(){
6841 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6845 return new Roo.EventObjectImpl();
6850 * Ext JS Library 1.1.1
6851 * Copyright(c) 2006-2007, Ext JS, LLC.
6853 * Originally Released Under LGPL - original licence link has changed is not relivant.
6856 * <script type="text/javascript">
6860 // was in Composite Element!??!?!
6863 var D = Roo.lib.Dom;
6864 var E = Roo.lib.Event;
6865 var A = Roo.lib.Anim;
6867 // local style camelizing for speed
6869 var camelRe = /(-[a-z])/gi;
6870 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6871 var view = document.defaultView;
6874 * @class Roo.Element
6875 * Represents an Element in the DOM.<br><br>
6878 var el = Roo.get("my-div");
6881 var el = getEl("my-div");
6883 // or with a DOM element
6884 var el = Roo.get(myDivElement);
6886 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6887 * each call instead of constructing a new one.<br><br>
6888 * <b>Animations</b><br />
6889 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6890 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6892 Option Default Description
6893 --------- -------- ---------------------------------------------
6894 duration .35 The duration of the animation in seconds
6895 easing easeOut The YUI easing method
6896 callback none A function to execute when the anim completes
6897 scope this The scope (this) of the callback function
6899 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6900 * manipulate the animation. Here's an example:
6902 var el = Roo.get("my-div");
6907 // default animation
6908 el.setWidth(100, true);
6910 // animation with some options set
6917 // using the "anim" property to get the Anim object
6923 el.setWidth(100, opt);
6925 if(opt.anim.isAnimated()){
6929 * <b> Composite (Collections of) Elements</b><br />
6930 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6931 * @constructor Create a new Element directly.
6932 * @param {String/HTMLElement} element
6933 * @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).
6935 Roo.Element = function(element, forceNew){
6936 var dom = typeof element == "string" ?
6937 document.getElementById(element) : element;
6938 if(!dom){ // invalid id/element
6942 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6943 return Roo.Element.cache[id];
6953 * The DOM element ID
6956 this.id = id || Roo.id(dom);
6959 var El = Roo.Element;
6963 * The element's default display mode (defaults to "")
6966 originalDisplay : "",
6970 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6975 * Sets the element's visibility mode. When setVisible() is called it
6976 * will use this to determine whether to set the visibility or the display property.
6977 * @param visMode Element.VISIBILITY or Element.DISPLAY
6978 * @return {Roo.Element} this
6980 setVisibilityMode : function(visMode){
6981 this.visibilityMode = visMode;
6985 * Convenience method for setVisibilityMode(Element.DISPLAY)
6986 * @param {String} display (optional) What to set display to when visible
6987 * @return {Roo.Element} this
6989 enableDisplayMode : function(display){
6990 this.setVisibilityMode(El.DISPLAY);
6991 if(typeof display != "undefined") this.originalDisplay = display;
6996 * 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)
6997 * @param {String} selector The simple selector to test
6998 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6999 search as a number or element (defaults to 10 || document.body)
7000 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7001 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7003 findParent : function(simpleSelector, maxDepth, returnEl){
7004 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7005 maxDepth = maxDepth || 50;
7006 if(typeof maxDepth != "number"){
7007 stopEl = Roo.getDom(maxDepth);
7010 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7011 if(dq.is(p, simpleSelector)){
7012 return returnEl ? Roo.get(p) : p;
7022 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7023 * @param {String} selector The simple selector to test
7024 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7025 search as a number or element (defaults to 10 || document.body)
7026 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7027 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7029 findParentNode : function(simpleSelector, maxDepth, returnEl){
7030 var p = Roo.fly(this.dom.parentNode, '_internal');
7031 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7035 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7036 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7037 * @param {String} selector The simple selector to test
7038 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7039 search as a number or element (defaults to 10 || document.body)
7040 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7042 up : function(simpleSelector, maxDepth){
7043 return this.findParentNode(simpleSelector, maxDepth, true);
7049 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7050 * @param {String} selector The simple selector to test
7051 * @return {Boolean} True if this element matches the selector, else false
7053 is : function(simpleSelector){
7054 return Roo.DomQuery.is(this.dom, simpleSelector);
7058 * Perform animation on this element.
7059 * @param {Object} args The YUI animation control args
7060 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7061 * @param {Function} onComplete (optional) Function to call when animation completes
7062 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7063 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7064 * @return {Roo.Element} this
7066 animate : function(args, duration, onComplete, easing, animType){
7067 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7072 * @private Internal animation call
7074 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7075 animType = animType || 'run';
7077 var anim = Roo.lib.Anim[animType](
7079 (opt.duration || defaultDur) || .35,
7080 (opt.easing || defaultEase) || 'easeOut',
7082 Roo.callback(cb, this);
7083 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7091 // private legacy anim prep
7092 preanim : function(a, i){
7093 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7097 * Removes worthless text nodes
7098 * @param {Boolean} forceReclean (optional) By default the element
7099 * keeps track if it has been cleaned already so
7100 * you can call this over and over. However, if you update the element and
7101 * need to force a reclean, you can pass true.
7103 clean : function(forceReclean){
7104 if(this.isCleaned && forceReclean !== true){
7108 var d = this.dom, n = d.firstChild, ni = -1;
7110 var nx = n.nextSibling;
7111 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7118 this.isCleaned = true;
7123 calcOffsetsTo : function(el){
7126 var restorePos = false;
7127 if(el.getStyle('position') == 'static'){
7128 el.position('relative');
7133 while(op && op != d && op.tagName != 'HTML'){
7136 op = op.offsetParent;
7139 el.position('static');
7145 * Scrolls this element into view within the passed container.
7146 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7147 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7148 * @return {Roo.Element} this
7150 scrollIntoView : function(container, hscroll){
7151 var c = Roo.getDom(container) || document.body;
7154 var o = this.calcOffsetsTo(c),
7157 b = t+el.offsetHeight,
7158 r = l+el.offsetWidth;
7160 var ch = c.clientHeight;
7161 var ct = parseInt(c.scrollTop, 10);
7162 var cl = parseInt(c.scrollLeft, 10);
7164 var cr = cl + c.clientWidth;
7172 if(hscroll !== false){
7176 c.scrollLeft = r-c.clientWidth;
7183 scrollChildIntoView : function(child, hscroll){
7184 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7188 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7189 * the new height may not be available immediately.
7190 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7191 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7192 * @param {Function} onComplete (optional) Function to call when animation completes
7193 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7194 * @return {Roo.Element} this
7196 autoHeight : function(animate, duration, onComplete, easing){
7197 var oldHeight = this.getHeight();
7199 this.setHeight(1); // force clipping
7200 setTimeout(function(){
7201 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7203 this.setHeight(height);
7205 if(typeof onComplete == "function"){
7209 this.setHeight(oldHeight); // restore original height
7210 this.setHeight(height, animate, duration, function(){
7212 if(typeof onComplete == "function") onComplete();
7213 }.createDelegate(this), easing);
7215 }.createDelegate(this), 0);
7220 * Returns true if this element is an ancestor of the passed element
7221 * @param {HTMLElement/String} el The element to check
7222 * @return {Boolean} True if this element is an ancestor of el, else false
7224 contains : function(el){
7225 if(!el){return false;}
7226 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7230 * Checks whether the element is currently visible using both visibility and display properties.
7231 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7232 * @return {Boolean} True if the element is currently visible, else false
7234 isVisible : function(deep) {
7235 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7236 if(deep !== true || !vis){
7239 var p = this.dom.parentNode;
7240 while(p && p.tagName.toLowerCase() != "body"){
7241 if(!Roo.fly(p, '_isVisible').isVisible()){
7250 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7251 * @param {String} selector The CSS selector
7252 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7253 * @return {CompositeElement/CompositeElementLite} The composite element
7255 select : function(selector, unique){
7256 return El.select(selector, unique, this.dom);
7260 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @return {Array} An array of the matched nodes
7264 query : function(selector, unique){
7265 return Roo.DomQuery.select(selector, this.dom);
7269 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7270 * @param {String} selector The CSS selector
7271 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7272 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7274 child : function(selector, returnDom){
7275 var n = Roo.DomQuery.selectNode(selector, this.dom);
7276 return returnDom ? n : Roo.get(n);
7280 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7281 * @param {String} selector The CSS selector
7282 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7283 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7285 down : function(selector, returnDom){
7286 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7287 return returnDom ? n : Roo.get(n);
7291 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7292 * @param {String} group The group the DD object is member of
7293 * @param {Object} config The DD config object
7294 * @param {Object} overrides An object containing methods to override/implement on the DD object
7295 * @return {Roo.dd.DD} The DD object
7297 initDD : function(group, config, overrides){
7298 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7299 return Roo.apply(dd, overrides);
7303 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7304 * @param {String} group The group the DDProxy object is member of
7305 * @param {Object} config The DDProxy config object
7306 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7307 * @return {Roo.dd.DDProxy} The DDProxy object
7309 initDDProxy : function(group, config, overrides){
7310 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7311 return Roo.apply(dd, overrides);
7315 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7316 * @param {String} group The group the DDTarget object is member of
7317 * @param {Object} config The DDTarget config object
7318 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7319 * @return {Roo.dd.DDTarget} The DDTarget object
7321 initDDTarget : function(group, config, overrides){
7322 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7323 return Roo.apply(dd, overrides);
7327 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7328 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7329 * @param {Boolean} visible Whether the element is visible
7330 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7331 * @return {Roo.Element} this
7333 setVisible : function(visible, animate){
7335 if(this.visibilityMode == El.DISPLAY){
7336 this.setDisplayed(visible);
7339 this.dom.style.visibility = visible ? "visible" : "hidden";
7342 // closure for composites
7344 var visMode = this.visibilityMode;
7346 this.setOpacity(.01);
7347 this.setVisible(true);
7349 this.anim({opacity: { to: (visible?1:0) }},
7350 this.preanim(arguments, 1),
7351 null, .35, 'easeIn', function(){
7353 if(visMode == El.DISPLAY){
7354 dom.style.display = "none";
7356 dom.style.visibility = "hidden";
7358 Roo.get(dom).setOpacity(1);
7366 * Returns true if display is not "none"
7369 isDisplayed : function() {
7370 return this.getStyle("display") != "none";
7374 * Toggles the element's visibility or display, depending on visibility mode.
7375 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7376 * @return {Roo.Element} this
7378 toggle : function(animate){
7379 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7384 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7385 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7386 * @return {Roo.Element} this
7388 setDisplayed : function(value) {
7389 if(typeof value == "boolean"){
7390 value = value ? this.originalDisplay : "none";
7392 this.setStyle("display", value);
7397 * Tries to focus the element. Any exceptions are caught and ignored.
7398 * @return {Roo.Element} this
7400 focus : function() {
7408 * Tries to blur the element. Any exceptions are caught and ignored.
7409 * @return {Roo.Element} this
7419 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7420 * @param {String/Array} className The CSS class to add, or an array of classes
7421 * @return {Roo.Element} this
7423 addClass : function(className){
7424 if(className instanceof Array){
7425 for(var i = 0, len = className.length; i < len; i++) {
7426 this.addClass(className[i]);
7429 if(className && !this.hasClass(className)){
7430 this.dom.className = this.dom.className + " " + className;
7437 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7438 * @param {String/Array} className The CSS class to add, or an array of classes
7439 * @return {Roo.Element} this
7441 radioClass : function(className){
7442 var siblings = this.dom.parentNode.childNodes;
7443 for(var i = 0; i < siblings.length; i++) {
7444 var s = siblings[i];
7445 if(s.nodeType == 1){
7446 Roo.get(s).removeClass(className);
7449 this.addClass(className);
7454 * Removes one or more CSS classes from the element.
7455 * @param {String/Array} className The CSS class to remove, or an array of classes
7456 * @return {Roo.Element} this
7458 removeClass : function(className){
7459 if(!className || !this.dom.className){
7462 if(className instanceof Array){
7463 for(var i = 0, len = className.length; i < len; i++) {
7464 this.removeClass(className[i]);
7467 if(this.hasClass(className)){
7468 var re = this.classReCache[className];
7470 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7471 this.classReCache[className] = re;
7473 this.dom.className =
7474 this.dom.className.replace(re, " ");
7484 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7485 * @param {String} className The CSS class to toggle
7486 * @return {Roo.Element} this
7488 toggleClass : function(className){
7489 if(this.hasClass(className)){
7490 this.removeClass(className);
7492 this.addClass(className);
7498 * Checks if the specified CSS class exists on this element's DOM node.
7499 * @param {String} className The CSS class to check for
7500 * @return {Boolean} True if the class exists, else false
7502 hasClass : function(className){
7503 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7507 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7508 * @param {String} oldClassName The CSS class to replace
7509 * @param {String} newClassName The replacement CSS class
7510 * @return {Roo.Element} this
7512 replaceClass : function(oldClassName, newClassName){
7513 this.removeClass(oldClassName);
7514 this.addClass(newClassName);
7519 * Returns an object with properties matching the styles requested.
7520 * For example, el.getStyles('color', 'font-size', 'width') might return
7521 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7522 * @param {String} style1 A style name
7523 * @param {String} style2 A style name
7524 * @param {String} etc.
7525 * @return {Object} The style object
7527 getStyles : function(){
7528 var a = arguments, len = a.length, r = {};
7529 for(var i = 0; i < len; i++){
7530 r[a[i]] = this.getStyle(a[i]);
7536 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7537 * @param {String} property The style property whose value is returned.
7538 * @return {String} The current value of the style property for this element.
7540 getStyle : function(){
7541 return view && view.getComputedStyle ?
7543 var el = this.dom, v, cs, camel;
7544 if(prop == 'float'){
7547 if(el.style && (v = el.style[prop])){
7550 if(cs = view.getComputedStyle(el, "")){
7551 if(!(camel = propCache[prop])){
7552 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7559 var el = this.dom, v, cs, camel;
7560 if(prop == 'opacity'){
7561 if(typeof el.style.filter == 'string'){
7562 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7564 var fv = parseFloat(m[1]);
7566 return fv ? fv / 100 : 0;
7571 }else if(prop == 'float'){
7572 prop = "styleFloat";
7574 if(!(camel = propCache[prop])){
7575 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7577 if(v = el.style[camel]){
7580 if(cs = el.currentStyle){
7588 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7589 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7590 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7591 * @return {Roo.Element} this
7593 setStyle : function(prop, value){
7594 if(typeof prop == "string"){
7596 if (prop == 'float') {
7597 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7602 if(!(camel = propCache[prop])){
7603 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7606 if(camel == 'opacity') {
7607 this.setOpacity(value);
7609 this.dom.style[camel] = value;
7612 for(var style in prop){
7613 if(typeof prop[style] != "function"){
7614 this.setStyle(style, prop[style]);
7622 * More flexible version of {@link #setStyle} for setting style properties.
7623 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7624 * a function which returns such a specification.
7625 * @return {Roo.Element} this
7627 applyStyles : function(style){
7628 Roo.DomHelper.applyStyles(this.dom, style);
7633 * 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).
7634 * @return {Number} The X position of the element
7637 return D.getX(this.dom);
7641 * 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).
7642 * @return {Number} The Y position of the element
7645 return D.getY(this.dom);
7649 * 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).
7650 * @return {Array} The XY position of the element
7653 return D.getXY(this.dom);
7657 * 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).
7658 * @param {Number} The X position of the element
7659 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7660 * @return {Roo.Element} this
7662 setX : function(x, animate){
7664 D.setX(this.dom, x);
7666 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7672 * 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).
7673 * @param {Number} The Y position of the element
7674 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7675 * @return {Roo.Element} this
7677 setY : function(y, animate){
7679 D.setY(this.dom, y);
7681 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7687 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7688 * @param {String} left The left CSS property value
7689 * @return {Roo.Element} this
7691 setLeft : function(left){
7692 this.setStyle("left", this.addUnits(left));
7697 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7698 * @param {String} top The top CSS property value
7699 * @return {Roo.Element} this
7701 setTop : function(top){
7702 this.setStyle("top", this.addUnits(top));
7707 * Sets the element's CSS right style.
7708 * @param {String} right The right CSS property value
7709 * @return {Roo.Element} this
7711 setRight : function(right){
7712 this.setStyle("right", this.addUnits(right));
7717 * Sets the element's CSS bottom style.
7718 * @param {String} bottom The bottom CSS property value
7719 * @return {Roo.Element} this
7721 setBottom : function(bottom){
7722 this.setStyle("bottom", this.addUnits(bottom));
7727 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7728 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7729 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7730 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7731 * @return {Roo.Element} this
7733 setXY : function(pos, animate){
7735 D.setXY(this.dom, pos);
7737 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7743 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7744 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7745 * @param {Number} x X value for new position (coordinates are page-based)
7746 * @param {Number} y Y value for new position (coordinates are page-based)
7747 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7748 * @return {Roo.Element} this
7750 setLocation : function(x, y, animate){
7751 this.setXY([x, y], this.preanim(arguments, 2));
7756 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7757 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7758 * @param {Number} x X value for new position (coordinates are page-based)
7759 * @param {Number} y Y value for new position (coordinates are page-based)
7760 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7761 * @return {Roo.Element} this
7763 moveTo : function(x, y, animate){
7764 this.setXY([x, y], this.preanim(arguments, 2));
7769 * Returns the region of the given element.
7770 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7771 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7773 getRegion : function(){
7774 return D.getRegion(this.dom);
7778 * Returns the offset height of the element
7779 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7780 * @return {Number} The element's height
7782 getHeight : function(contentHeight){
7783 var h = this.dom.offsetHeight || 0;
7784 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7788 * Returns the offset width of the element
7789 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7790 * @return {Number} The element's width
7792 getWidth : function(contentWidth){
7793 var w = this.dom.offsetWidth || 0;
7794 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7798 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7799 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7800 * if a height has not been set using CSS.
7803 getComputedHeight : function(){
7804 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7806 h = parseInt(this.getStyle('height'), 10) || 0;
7807 if(!this.isBorderBox()){
7808 h += this.getFrameWidth('tb');
7815 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7816 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7817 * if a width has not been set using CSS.
7820 getComputedWidth : function(){
7821 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7823 w = parseInt(this.getStyle('width'), 10) || 0;
7824 if(!this.isBorderBox()){
7825 w += this.getFrameWidth('lr');
7832 * Returns the size of the element.
7833 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7834 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7836 getSize : function(contentSize){
7837 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7841 * Returns the width and height of the viewport.
7842 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7844 getViewSize : function(){
7845 var d = this.dom, doc = document, aw = 0, ah = 0;
7846 if(d == doc || d == doc.body){
7847 return {width : D.getViewWidth(), height: D.getViewHeight()};
7850 width : d.clientWidth,
7851 height: d.clientHeight
7857 * Returns the value of the "value" attribute
7858 * @param {Boolean} asNumber true to parse the value as a number
7859 * @return {String/Number}
7861 getValue : function(asNumber){
7862 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7866 adjustWidth : function(width){
7867 if(typeof width == "number"){
7868 if(this.autoBoxAdjust && !this.isBorderBox()){
7869 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7879 adjustHeight : function(height){
7880 if(typeof height == "number"){
7881 if(this.autoBoxAdjust && !this.isBorderBox()){
7882 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7892 * Set the width of the element
7893 * @param {Number} width The new width
7894 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7895 * @return {Roo.Element} this
7897 setWidth : function(width, animate){
7898 width = this.adjustWidth(width);
7900 this.dom.style.width = this.addUnits(width);
7902 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7908 * Set the height of the element
7909 * @param {Number} height The new height
7910 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7911 * @return {Roo.Element} this
7913 setHeight : function(height, animate){
7914 height = this.adjustHeight(height);
7916 this.dom.style.height = this.addUnits(height);
7918 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7924 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7925 * @param {Number} width The new width
7926 * @param {Number} height The new height
7927 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7928 * @return {Roo.Element} this
7930 setSize : function(width, height, animate){
7931 if(typeof width == "object"){ // in case of object from getSize()
7932 height = width.height; width = width.width;
7934 width = this.adjustWidth(width); height = this.adjustHeight(height);
7936 this.dom.style.width = this.addUnits(width);
7937 this.dom.style.height = this.addUnits(height);
7939 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7945 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7946 * @param {Number} x X value for new position (coordinates are page-based)
7947 * @param {Number} y Y value for new position (coordinates are page-based)
7948 * @param {Number} width The new width
7949 * @param {Number} height The new height
7950 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7951 * @return {Roo.Element} this
7953 setBounds : function(x, y, width, height, animate){
7955 this.setSize(width, height);
7956 this.setLocation(x, y);
7958 width = this.adjustWidth(width); height = this.adjustHeight(height);
7959 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7960 this.preanim(arguments, 4), 'motion');
7966 * 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.
7967 * @param {Roo.lib.Region} region The region to fill
7968 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7969 * @return {Roo.Element} this
7971 setRegion : function(region, animate){
7972 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7977 * Appends an event handler
7979 * @param {String} eventName The type of event to append
7980 * @param {Function} fn The method the event invokes
7981 * @param {Object} scope (optional) The scope (this object) of the fn
7982 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7984 addListener : function(eventName, fn, scope, options){
7986 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7991 * Removes an event handler from this element
7992 * @param {String} eventName the type of event to remove
7993 * @param {Function} fn the method the event invokes
7994 * @return {Roo.Element} this
7996 removeListener : function(eventName, fn){
7997 Roo.EventManager.removeListener(this.dom, eventName, fn);
8002 * Removes all previous added listeners from this element
8003 * @return {Roo.Element} this
8005 removeAllListeners : function(){
8006 E.purgeElement(this.dom);
8010 relayEvent : function(eventName, observable){
8011 this.on(eventName, function(e){
8012 observable.fireEvent(eventName, e);
8017 * Set the opacity of the element
8018 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8019 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8020 * @return {Roo.Element} this
8022 setOpacity : function(opacity, animate){
8024 var s = this.dom.style;
8027 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8028 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8030 s.opacity = opacity;
8033 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8039 * Gets the left X coordinate
8040 * @param {Boolean} local True to get the local css position instead of page coordinate
8043 getLeft : function(local){
8047 return parseInt(this.getStyle("left"), 10) || 0;
8052 * Gets the right X coordinate of the element (element X position + element width)
8053 * @param {Boolean} local True to get the local css position instead of page coordinate
8056 getRight : function(local){
8058 return this.getX() + this.getWidth();
8060 return (this.getLeft(true) + this.getWidth()) || 0;
8065 * Gets the top Y coordinate
8066 * @param {Boolean} local True to get the local css position instead of page coordinate
8069 getTop : function(local) {
8073 return parseInt(this.getStyle("top"), 10) || 0;
8078 * Gets the bottom Y coordinate of the element (element Y position + element height)
8079 * @param {Boolean} local True to get the local css position instead of page coordinate
8082 getBottom : function(local){
8084 return this.getY() + this.getHeight();
8086 return (this.getTop(true) + this.getHeight()) || 0;
8091 * Initializes positioning on this element. If a desired position is not passed, it will make the
8092 * the element positioned relative IF it is not already positioned.
8093 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8094 * @param {Number} zIndex (optional) The zIndex to apply
8095 * @param {Number} x (optional) Set the page X position
8096 * @param {Number} y (optional) Set the page Y position
8098 position : function(pos, zIndex, x, y){
8100 if(this.getStyle('position') == 'static'){
8101 this.setStyle('position', 'relative');
8104 this.setStyle("position", pos);
8107 this.setStyle("z-index", zIndex);
8109 if(x !== undefined && y !== undefined){
8111 }else if(x !== undefined){
8113 }else if(y !== undefined){
8119 * Clear positioning back to the default when the document was loaded
8120 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8121 * @return {Roo.Element} this
8123 clearPositioning : function(value){
8131 "position" : "static"
8137 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8138 * snapshot before performing an update and then restoring the element.
8141 getPositioning : function(){
8142 var l = this.getStyle("left");
8143 var t = this.getStyle("top");
8145 "position" : this.getStyle("position"),
8147 "right" : l ? "" : this.getStyle("right"),
8149 "bottom" : t ? "" : this.getStyle("bottom"),
8150 "z-index" : this.getStyle("z-index")
8155 * Gets the width of the border(s) for the specified side(s)
8156 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8157 * passing lr would get the border (l)eft width + the border (r)ight width.
8158 * @return {Number} The width of the sides passed added together
8160 getBorderWidth : function(side){
8161 return this.addStyles(side, El.borders);
8165 * Gets the width of the padding(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the padding (l)eft + the padding (r)ight.
8168 * @return {Number} The padding of the sides passed added together
8170 getPadding : function(side){
8171 return this.addStyles(side, El.paddings);
8175 * Set positioning with an object returned by getPositioning().
8176 * @param {Object} posCfg
8177 * @return {Roo.Element} this
8179 setPositioning : function(pc){
8180 this.applyStyles(pc);
8181 if(pc.right == "auto"){
8182 this.dom.style.right = "";
8184 if(pc.bottom == "auto"){
8185 this.dom.style.bottom = "";
8191 fixDisplay : function(){
8192 if(this.getStyle("display") == "none"){
8193 this.setStyle("visibility", "hidden");
8194 this.setStyle("display", this.originalDisplay); // first try reverting to default
8195 if(this.getStyle("display") == "none"){ // if that fails, default to block
8196 this.setStyle("display", "block");
8202 * Quick set left and top adding default units
8203 * @param {String} left The left CSS property value
8204 * @param {String} top The top CSS property value
8205 * @return {Roo.Element} this
8207 setLeftTop : function(left, top){
8208 this.dom.style.left = this.addUnits(left);
8209 this.dom.style.top = this.addUnits(top);
8214 * Move this element relative to its current position.
8215 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8216 * @param {Number} distance How far to move the element in pixels
8217 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8218 * @return {Roo.Element} this
8220 move : function(direction, distance, animate){
8221 var xy = this.getXY();
8222 direction = direction.toLowerCase();
8226 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8230 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8235 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8240 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8247 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8248 * @return {Roo.Element} this
8251 if(!this.isClipped){
8252 this.isClipped = true;
8253 this.originalClip = {
8254 "o": this.getStyle("overflow"),
8255 "x": this.getStyle("overflow-x"),
8256 "y": this.getStyle("overflow-y")
8258 this.setStyle("overflow", "hidden");
8259 this.setStyle("overflow-x", "hidden");
8260 this.setStyle("overflow-y", "hidden");
8266 * Return clipping (overflow) to original clipping before clip() was called
8267 * @return {Roo.Element} this
8269 unclip : function(){
8271 this.isClipped = false;
8272 var o = this.originalClip;
8273 if(o.o){this.setStyle("overflow", o.o);}
8274 if(o.x){this.setStyle("overflow-x", o.x);}
8275 if(o.y){this.setStyle("overflow-y", o.y);}
8282 * Gets the x,y coordinates specified by the anchor position on the element.
8283 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8284 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8285 * {width: (target width), height: (target height)} (defaults to the element's current size)
8286 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8287 * @return {Array} [x, y] An array containing the element's x and y coordinates
8289 getAnchorXY : function(anchor, local, s){
8290 //Passing a different size is useful for pre-calculating anchors,
8291 //especially for anchored animations that change the el size.
8293 var w, h, vp = false;
8296 if(d == document.body || d == document){
8298 w = D.getViewWidth(); h = D.getViewHeight();
8300 w = this.getWidth(); h = this.getHeight();
8303 w = s.width; h = s.height;
8305 var x = 0, y = 0, r = Math.round;
8306 switch((anchor || "tl").toLowerCase()){
8348 var sc = this.getScroll();
8349 return [x + sc.left, y + sc.top];
8351 //Add the element's offset xy
8352 var o = this.getXY();
8353 return [x+o[0], y+o[1]];
8357 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8358 * supported position values.
8359 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8360 * @param {String} position The position to align to.
8361 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8362 * @return {Array} [x, y]
8364 getAlignToXY : function(el, p, o){
8368 throw "Element.alignTo with an element that doesn't exist";
8370 var c = false; //constrain to viewport
8371 var p1 = "", p2 = "";
8378 }else if(p.indexOf("-") == -1){
8381 p = p.toLowerCase();
8382 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8384 throw "Element.alignTo with an invalid alignment " + p;
8386 p1 = m[1]; p2 = m[2]; c = !!m[3];
8388 //Subtract the aligned el's internal xy from the target's offset xy
8389 //plus custom offset to get the aligned el's new offset xy
8390 var a1 = this.getAnchorXY(p1, true);
8391 var a2 = el.getAnchorXY(p2, false);
8392 var x = a2[0] - a1[0] + o[0];
8393 var y = a2[1] - a1[1] + o[1];
8395 //constrain the aligned el to viewport if necessary
8396 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8397 // 5px of margin for ie
8398 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8400 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8401 //perpendicular to the vp border, allow the aligned el to slide on that border,
8402 //otherwise swap the aligned el to the opposite border of the target.
8403 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8404 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8405 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8406 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8409 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8410 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8412 if((x+w) > dw + scrollX){
8413 x = swapX ? r.left-w : dw+scrollX-w;
8416 x = swapX ? r.right : scrollX;
8418 if((y+h) > dh + scrollY){
8419 y = swapY ? r.top-h : dh+scrollY-h;
8422 y = swapY ? r.bottom : scrollY;
8429 getConstrainToXY : function(){
8430 var os = {top:0, left:0, bottom:0, right: 0};
8432 return function(el, local, offsets, proposedXY){
8434 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8436 var vw, vh, vx = 0, vy = 0;
8437 if(el.dom == document.body || el.dom == document){
8438 vw = Roo.lib.Dom.getViewWidth();
8439 vh = Roo.lib.Dom.getViewHeight();
8441 vw = el.dom.clientWidth;
8442 vh = el.dom.clientHeight;
8444 var vxy = el.getXY();
8450 var s = el.getScroll();
8452 vx += offsets.left + s.left;
8453 vy += offsets.top + s.top;
8455 vw -= offsets.right;
8456 vh -= offsets.bottom;
8461 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8462 var x = xy[0], y = xy[1];
8463 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8465 // only move it if it needs it
8468 // first validate right/bottom
8477 // then make sure top/left isn't negative
8486 return moved ? [x, y] : false;
8491 adjustForConstraints : function(xy, parent, offsets){
8492 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8496 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8497 * document it aligns it to the viewport.
8498 * The position parameter is optional, and can be specified in any one of the following formats:
8500 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8501 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8502 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8503 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8504 * <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
8505 * element's anchor point, and the second value is used as the target's anchor point.</li>
8507 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8508 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8509 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8510 * that specified in order to enforce the viewport constraints.
8511 * Following are all of the supported anchor positions:
8514 ----- -----------------------------
8515 tl The top left corner (default)
8516 t The center of the top edge
8517 tr The top right corner
8518 l The center of the left edge
8519 c In the center of the element
8520 r The center of the right edge
8521 bl The bottom left corner
8522 b The center of the bottom edge
8523 br The bottom right corner
8527 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8528 el.alignTo("other-el");
8530 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8531 el.alignTo("other-el", "tr?");
8533 // align the bottom right corner of el with the center left edge of other-el
8534 el.alignTo("other-el", "br-l?");
8536 // align the center of el with the bottom left corner of other-el and
8537 // adjust the x position by -6 pixels (and the y position by 0)
8538 el.alignTo("other-el", "c-bl", [-6, 0]);
8540 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8541 * @param {String} position The position to align to.
8542 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8543 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8544 * @return {Roo.Element} this
8546 alignTo : function(element, position, offsets, animate){
8547 var xy = this.getAlignToXY(element, position, offsets);
8548 this.setXY(xy, this.preanim(arguments, 3));
8553 * Anchors an element to another element and realigns it when the window is resized.
8554 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8555 * @param {String} position The position to align to.
8556 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8557 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8558 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8559 * is a number, it is used as the buffer delay (defaults to 50ms).
8560 * @param {Function} callback The function to call after the animation finishes
8561 * @return {Roo.Element} this
8563 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8564 var action = function(){
8565 this.alignTo(el, alignment, offsets, animate);
8566 Roo.callback(callback, this);
8568 Roo.EventManager.onWindowResize(action, this);
8569 var tm = typeof monitorScroll;
8570 if(tm != 'undefined'){
8571 Roo.EventManager.on(window, 'scroll', action, this,
8572 {buffer: tm == 'number' ? monitorScroll : 50});
8574 action.call(this); // align immediately
8578 * Clears any opacity settings from this element. Required in some cases for IE.
8579 * @return {Roo.Element} this
8581 clearOpacity : function(){
8582 if (window.ActiveXObject) {
8583 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8584 this.dom.style.filter = "";
8587 this.dom.style.opacity = "";
8588 this.dom.style["-moz-opacity"] = "";
8589 this.dom.style["-khtml-opacity"] = "";
8595 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8596 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8597 * @return {Roo.Element} this
8599 hide : function(animate){
8600 this.setVisible(false, this.preanim(arguments, 0));
8605 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 show : function(animate){
8610 this.setVisible(true, this.preanim(arguments, 0));
8615 * @private Test if size has a unit, otherwise appends the default
8617 addUnits : function(size){
8618 return Roo.Element.addUnits(size, this.defaultUnit);
8622 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8623 * @return {Roo.Element} this
8625 beginMeasure : function(){
8627 if(el.offsetWidth || el.offsetHeight){
8628 return this; // offsets work already
8631 var p = this.dom, b = document.body; // start with this element
8632 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8633 var pe = Roo.get(p);
8634 if(pe.getStyle('display') == 'none'){
8635 changed.push({el: p, visibility: pe.getStyle("visibility")});
8636 p.style.visibility = "hidden";
8637 p.style.display = "block";
8641 this._measureChanged = changed;
8647 * Restores displays to before beginMeasure was called
8648 * @return {Roo.Element} this
8650 endMeasure : function(){
8651 var changed = this._measureChanged;
8653 for(var i = 0, len = changed.length; i < len; i++) {
8655 r.el.style.visibility = r.visibility;
8656 r.el.style.display = "none";
8658 this._measureChanged = null;
8664 * Update the innerHTML of this element, optionally searching for and processing scripts
8665 * @param {String} html The new HTML
8666 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8667 * @param {Function} callback For async script loading you can be noticed when the update completes
8668 * @return {Roo.Element} this
8670 update : function(html, loadScripts, callback){
8671 if(typeof html == "undefined"){
8674 if(loadScripts !== true){
8675 this.dom.innerHTML = html;
8676 if(typeof callback == "function"){
8684 html += '<span id="' + id + '"></span>';
8686 E.onAvailable(id, function(){
8687 var hd = document.getElementsByTagName("head")[0];
8688 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8689 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8690 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8693 while(match = re.exec(html)){
8694 var attrs = match[1];
8695 var srcMatch = attrs ? attrs.match(srcRe) : false;
8696 if(srcMatch && srcMatch[2]){
8697 var s = document.createElement("script");
8698 s.src = srcMatch[2];
8699 var typeMatch = attrs.match(typeRe);
8700 if(typeMatch && typeMatch[2]){
8701 s.type = typeMatch[2];
8704 }else if(match[2] && match[2].length > 0){
8705 if(window.execScript) {
8706 window.execScript(match[2]);
8714 window.eval(match[2]);
8718 var el = document.getElementById(id);
8719 if(el){el.parentNode.removeChild(el);}
8720 if(typeof callback == "function"){
8724 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8729 * Direct access to the UpdateManager update() method (takes the same parameters).
8730 * @param {String/Function} url The url for this request or a function to call to get the url
8731 * @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}
8732 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8733 * @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.
8734 * @return {Roo.Element} this
8737 var um = this.getUpdateManager();
8738 um.update.apply(um, arguments);
8743 * Gets this element's UpdateManager
8744 * @return {Roo.UpdateManager} The UpdateManager
8746 getUpdateManager : function(){
8747 if(!this.updateManager){
8748 this.updateManager = new Roo.UpdateManager(this);
8750 return this.updateManager;
8754 * Disables text selection for this element (normalized across browsers)
8755 * @return {Roo.Element} this
8757 unselectable : function(){
8758 this.dom.unselectable = "on";
8759 this.swallowEvent("selectstart", true);
8760 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8761 this.addClass("x-unselectable");
8766 * Calculates the x, y to center this element on the screen
8767 * @return {Array} The x, y values [x, y]
8769 getCenterXY : function(){
8770 return this.getAlignToXY(document, 'c-c');
8774 * Centers the Element in either the viewport, or another Element.
8775 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8777 center : function(centerIn){
8778 this.alignTo(centerIn || document, 'c-c');
8783 * Tests various css rules/browsers to determine if this element uses a border box
8786 isBorderBox : function(){
8787 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8791 * Return a box {x, y, width, height} that can be used to set another elements
8792 * size/location to match this element.
8793 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8794 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8795 * @return {Object} box An object in the format {x, y, width, height}
8797 getBox : function(contentBox, local){
8802 var left = parseInt(this.getStyle("left"), 10) || 0;
8803 var top = parseInt(this.getStyle("top"), 10) || 0;
8806 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8808 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8810 var l = this.getBorderWidth("l")+this.getPadding("l");
8811 var r = this.getBorderWidth("r")+this.getPadding("r");
8812 var t = this.getBorderWidth("t")+this.getPadding("t");
8813 var b = this.getBorderWidth("b")+this.getPadding("b");
8814 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)};
8816 bx.right = bx.x + bx.width;
8817 bx.bottom = bx.y + bx.height;
8822 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8823 for more information about the sides.
8824 * @param {String} sides
8827 getFrameWidth : function(sides, onlyContentBox){
8828 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8832 * 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.
8833 * @param {Object} box The box to fill {x, y, width, height}
8834 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8835 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8836 * @return {Roo.Element} this
8838 setBox : function(box, adjust, animate){
8839 var w = box.width, h = box.height;
8840 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8841 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8842 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8844 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8849 * Forces the browser to repaint this element
8850 * @return {Roo.Element} this
8852 repaint : function(){
8854 this.addClass("x-repaint");
8855 setTimeout(function(){
8856 Roo.get(dom).removeClass("x-repaint");
8862 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8863 * then it returns the calculated width of the sides (see getPadding)
8864 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8865 * @return {Object/Number}
8867 getMargins : function(side){
8870 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8871 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8872 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8873 right: parseInt(this.getStyle("margin-right"), 10) || 0
8876 return this.addStyles(side, El.margins);
8881 addStyles : function(sides, styles){
8883 for(var i = 0, len = sides.length; i < len; i++){
8884 v = this.getStyle(styles[sides.charAt(i)]);
8886 w = parseInt(v, 10);
8894 * Creates a proxy element of this element
8895 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8896 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8897 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8898 * @return {Roo.Element} The new proxy element
8900 createProxy : function(config, renderTo, matchBox){
8902 renderTo = Roo.getDom(renderTo);
8904 renderTo = document.body;
8906 config = typeof config == "object" ?
8907 config : {tag : "div", cls: config};
8908 var proxy = Roo.DomHelper.append(renderTo, config, true);
8910 proxy.setBox(this.getBox());
8916 * Puts a mask over this element to disable user interaction. Requires core.css.
8917 * This method can only be applied to elements which accept child nodes.
8918 * @param {String} msg (optional) A message to display in the mask
8919 * @param {String} msgCls (optional) A css class to apply to the msg element
8920 * @return {Element} The mask element
8922 mask : function(msg, msgCls)
8924 if(this.getStyle("position") == "static"){
8925 this.setStyle("position", "relative");
8928 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8930 this.addClass("x-masked");
8931 this._mask.setDisplayed(true);
8936 while (dom && dom.style) {
8937 if (!isNaN(parseInt(dom.style.zIndex))) {
8938 z = Math.max(z, parseInt(dom.style.zIndex));
8940 dom = dom.parentNode;
8942 // if we are masking the body - then it hides everything..
8943 if (this.dom == document.body) {
8945 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8946 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8949 if(typeof msg == 'string'){
8951 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8953 var mm = this._maskMsg;
8954 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8955 mm.dom.firstChild.innerHTML = msg;
8956 mm.setDisplayed(true);
8958 mm.setStyle('z-index', z + 102);
8960 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8961 this._mask.setHeight(this.getHeight());
8963 this._mask.setStyle('z-index', z + 100);
8969 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8970 * it is cached for reuse.
8972 unmask : function(removeEl){
8974 if(removeEl === true){
8975 this._mask.remove();
8978 this._maskMsg.remove();
8979 delete this._maskMsg;
8982 this._mask.setDisplayed(false);
8984 this._maskMsg.setDisplayed(false);
8988 this.removeClass("x-masked");
8992 * Returns true if this element is masked
8995 isMasked : function(){
8996 return this._mask && this._mask.isVisible();
9000 * Creates an iframe shim for this element to keep selects and other windowed objects from
9002 * @return {Roo.Element} The new shim element
9004 createShim : function(){
9005 var el = document.createElement('iframe');
9006 el.frameBorder = 'no';
9007 el.className = 'roo-shim';
9008 if(Roo.isIE && Roo.isSecure){
9009 el.src = Roo.SSL_SECURE_URL;
9011 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9012 shim.autoBoxAdjust = false;
9017 * Removes this element from the DOM and deletes it from the cache
9019 remove : function(){
9020 if(this.dom.parentNode){
9021 this.dom.parentNode.removeChild(this.dom);
9023 delete El.cache[this.dom.id];
9027 * Sets up event handlers to add and remove a css class when the mouse is over this element
9028 * @param {String} className
9029 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9030 * mouseout events for children elements
9031 * @return {Roo.Element} this
9033 addClassOnOver : function(className, preventFlicker){
9034 this.on("mouseover", function(){
9035 Roo.fly(this, '_internal').addClass(className);
9037 var removeFn = function(e){
9038 if(preventFlicker !== true || !e.within(this, true)){
9039 Roo.fly(this, '_internal').removeClass(className);
9042 this.on("mouseout", removeFn, this.dom);
9047 * Sets up event handlers to add and remove a css class when this element has the focus
9048 * @param {String} className
9049 * @return {Roo.Element} this
9051 addClassOnFocus : function(className){
9052 this.on("focus", function(){
9053 Roo.fly(this, '_internal').addClass(className);
9055 this.on("blur", function(){
9056 Roo.fly(this, '_internal').removeClass(className);
9061 * 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)
9062 * @param {String} className
9063 * @return {Roo.Element} this
9065 addClassOnClick : function(className){
9067 this.on("mousedown", function(){
9068 Roo.fly(dom, '_internal').addClass(className);
9069 var d = Roo.get(document);
9070 var fn = function(){
9071 Roo.fly(dom, '_internal').removeClass(className);
9072 d.removeListener("mouseup", fn);
9074 d.on("mouseup", fn);
9080 * Stops the specified event from bubbling and optionally prevents the default action
9081 * @param {String} eventName
9082 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9083 * @return {Roo.Element} this
9085 swallowEvent : function(eventName, preventDefault){
9086 var fn = function(e){
9087 e.stopPropagation();
9092 if(eventName instanceof Array){
9093 for(var i = 0, len = eventName.length; i < len; i++){
9094 this.on(eventName[i], fn);
9098 this.on(eventName, fn);
9105 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9108 * Sizes this element to its parent element's dimensions performing
9109 * neccessary box adjustments.
9110 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9111 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9112 * @return {Roo.Element} this
9114 fitToParent : function(monitorResize, targetParent) {
9115 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9116 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9117 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9120 var p = Roo.get(targetParent || this.dom.parentNode);
9121 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9122 if (monitorResize === true) {
9123 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9124 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9130 * Gets the next sibling, skipping text nodes
9131 * @return {HTMLElement} The next sibling or null
9133 getNextSibling : function(){
9134 var n = this.dom.nextSibling;
9135 while(n && n.nodeType != 1){
9142 * Gets the previous sibling, skipping text nodes
9143 * @return {HTMLElement} The previous sibling or null
9145 getPrevSibling : function(){
9146 var n = this.dom.previousSibling;
9147 while(n && n.nodeType != 1){
9148 n = n.previousSibling;
9155 * Appends the passed element(s) to this element
9156 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9157 * @return {Roo.Element} this
9159 appendChild: function(el){
9166 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9167 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9168 * automatically generated with the specified attributes.
9169 * @param {HTMLElement} insertBefore (optional) a child element of this element
9170 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9171 * @return {Roo.Element} The new child element
9173 createChild: function(config, insertBefore, returnDom){
9174 config = config || {tag:'div'};
9176 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9178 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9182 * Appends this element to the passed element
9183 * @param {String/HTMLElement/Element} el The new parent element
9184 * @return {Roo.Element} this
9186 appendTo: function(el){
9187 el = Roo.getDom(el);
9188 el.appendChild(this.dom);
9193 * Inserts this element before the passed element in the DOM
9194 * @param {String/HTMLElement/Element} el The element to insert before
9195 * @return {Roo.Element} this
9197 insertBefore: function(el){
9198 el = Roo.getDom(el);
9199 el.parentNode.insertBefore(this.dom, el);
9204 * Inserts this element after the passed element in the DOM
9205 * @param {String/HTMLElement/Element} el The element to insert after
9206 * @return {Roo.Element} this
9208 insertAfter: function(el){
9209 el = Roo.getDom(el);
9210 el.parentNode.insertBefore(this.dom, el.nextSibling);
9215 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9216 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9217 * @return {Roo.Element} The new child
9219 insertFirst: function(el, returnDom){
9221 if(typeof el == 'object' && !el.nodeType){ // dh config
9222 return this.createChild(el, this.dom.firstChild, returnDom);
9224 el = Roo.getDom(el);
9225 this.dom.insertBefore(el, this.dom.firstChild);
9226 return !returnDom ? Roo.get(el) : el;
9231 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9232 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9233 * @param {String} where (optional) 'before' or 'after' defaults to before
9234 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9235 * @return {Roo.Element} the inserted Element
9237 insertSibling: function(el, where, returnDom){
9238 where = where ? where.toLowerCase() : 'before';
9240 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9242 if(typeof el == 'object' && !el.nodeType){ // dh config
9243 if(where == 'after' && !this.dom.nextSibling){
9244 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9246 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9250 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9251 where == 'before' ? this.dom : this.dom.nextSibling);
9260 * Creates and wraps this element with another element
9261 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9262 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9263 * @return {HTMLElement/Element} The newly created wrapper element
9265 wrap: function(config, returnDom){
9267 config = {tag: "div"};
9269 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9270 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9275 * Replaces the passed element with this element
9276 * @param {String/HTMLElement/Element} el The element to replace
9277 * @return {Roo.Element} this
9279 replace: function(el){
9281 this.insertBefore(el);
9287 * Inserts an html fragment into this element
9288 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9289 * @param {String} html The HTML fragment
9290 * @param {Boolean} returnEl True to return an Roo.Element
9291 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9293 insertHtml : function(where, html, returnEl){
9294 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9295 return returnEl ? Roo.get(el) : el;
9299 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9300 * @param {Object} o The object with the attributes
9301 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9302 * @return {Roo.Element} this
9304 set : function(o, useSet){
9306 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9308 if(attr == "style" || typeof o[attr] == "function") continue;
9310 el.className = o["cls"];
9312 if(useSet) el.setAttribute(attr, o[attr]);
9313 else el[attr] = o[attr];
9317 Roo.DomHelper.applyStyles(el, o.style);
9323 * Convenience method for constructing a KeyMap
9324 * @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:
9325 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9326 * @param {Function} fn The function to call
9327 * @param {Object} scope (optional) The scope of the function
9328 * @return {Roo.KeyMap} The KeyMap created
9330 addKeyListener : function(key, fn, scope){
9332 if(typeof key != "object" || key instanceof Array){
9348 return new Roo.KeyMap(this, config);
9352 * Creates a KeyMap for this element
9353 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9354 * @return {Roo.KeyMap} The KeyMap created
9356 addKeyMap : function(config){
9357 return new Roo.KeyMap(this, config);
9361 * Returns true if this element is scrollable.
9364 isScrollable : function(){
9366 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9370 * 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().
9371 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9372 * @param {Number} value The new scroll value
9373 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9374 * @return {Element} this
9377 scrollTo : function(side, value, animate){
9378 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9380 this.dom[prop] = value;
9382 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9383 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9389 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9390 * within this element's scrollable range.
9391 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9392 * @param {Number} distance How far to scroll the element in pixels
9393 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9394 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9395 * was scrolled as far as it could go.
9397 scroll : function(direction, distance, animate){
9398 if(!this.isScrollable()){
9402 var l = el.scrollLeft, t = el.scrollTop;
9403 var w = el.scrollWidth, h = el.scrollHeight;
9404 var cw = el.clientWidth, ch = el.clientHeight;
9405 direction = direction.toLowerCase();
9406 var scrolled = false;
9407 var a = this.preanim(arguments, 2);
9412 var v = Math.min(l + distance, w-cw);
9413 this.scrollTo("left", v, a);
9420 var v = Math.max(l - distance, 0);
9421 this.scrollTo("left", v, a);
9429 var v = Math.max(t - distance, 0);
9430 this.scrollTo("top", v, a);
9438 var v = Math.min(t + distance, h-ch);
9439 this.scrollTo("top", v, a);
9448 * Translates the passed page coordinates into left/top css values for this element
9449 * @param {Number/Array} x The page x or an array containing [x, y]
9450 * @param {Number} y The page y
9451 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9453 translatePoints : function(x, y){
9454 if(typeof x == 'object' || x instanceof Array){
9457 var p = this.getStyle('position');
9458 var o = this.getXY();
9460 var l = parseInt(this.getStyle('left'), 10);
9461 var t = parseInt(this.getStyle('top'), 10);
9464 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9467 t = (p == "relative") ? 0 : this.dom.offsetTop;
9470 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9474 * Returns the current scroll position of the element.
9475 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9477 getScroll : function(){
9478 var d = this.dom, doc = document;
9479 if(d == doc || d == doc.body){
9480 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9481 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9482 return {left: l, top: t};
9484 return {left: d.scrollLeft, top: d.scrollTop};
9489 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9490 * are convert to standard 6 digit hex color.
9491 * @param {String} attr The css attribute
9492 * @param {String} defaultValue The default value to use when a valid color isn't found
9493 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9496 getColor : function(attr, defaultValue, prefix){
9497 var v = this.getStyle(attr);
9498 if(!v || v == "transparent" || v == "inherit") {
9499 return defaultValue;
9501 var color = typeof prefix == "undefined" ? "#" : prefix;
9502 if(v.substr(0, 4) == "rgb("){
9503 var rvs = v.slice(4, v.length -1).split(",");
9504 for(var i = 0; i < 3; i++){
9505 var h = parseInt(rvs[i]).toString(16);
9512 if(v.substr(0, 1) == "#"){
9514 for(var i = 1; i < 4; i++){
9515 var c = v.charAt(i);
9518 }else if(v.length == 7){
9519 color += v.substr(1);
9523 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9527 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9528 * gradient background, rounded corners and a 4-way shadow.
9529 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9530 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9531 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9532 * @return {Roo.Element} this
9534 boxWrap : function(cls){
9535 cls = cls || 'x-box';
9536 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9537 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9542 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9543 * @param {String} namespace The namespace in which to look for the attribute
9544 * @param {String} name The attribute name
9545 * @return {String} The attribute value
9547 getAttributeNS : Roo.isIE ? function(ns, name){
9549 var type = typeof d[ns+":"+name];
9550 if(type != 'undefined' && type != 'unknown'){
9551 return d[ns+":"+name];
9554 } : function(ns, name){
9556 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9561 * Sets or Returns the value the dom attribute value
9562 * @param {String} name The attribute name
9563 * @param {String} value (optional) The value to set the attribute to
9564 * @return {String} The attribute value
9566 attr : function(name){
9567 if (arguments.length > 1) {
9568 this.dom.setAttribute(name, arguments[1]);
9569 return arguments[1];
9571 if (!this.dom.hasAttribute(name)) {
9574 return this.dom.getAttribute(name);
9581 var ep = El.prototype;
9584 * Appends an event handler (Shorthand for addListener)
9585 * @param {String} eventName The type of event to append
9586 * @param {Function} fn The method the event invokes
9587 * @param {Object} scope (optional) The scope (this object) of the fn
9588 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9591 ep.on = ep.addListener;
9593 ep.mon = ep.addListener;
9596 * Removes an event handler from this element (shorthand for removeListener)
9597 * @param {String} eventName the type of event to remove
9598 * @param {Function} fn the method the event invokes
9599 * @return {Roo.Element} this
9602 ep.un = ep.removeListener;
9605 * true to automatically adjust width and height settings for box-model issues (default to true)
9607 ep.autoBoxAdjust = true;
9610 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9613 El.addUnits = function(v, defaultUnit){
9614 if(v === "" || v == "auto"){
9617 if(v === undefined){
9620 if(typeof v == "number" || !El.unitPattern.test(v)){
9621 return v + (defaultUnit || 'px');
9626 // special markup used throughout Roo when box wrapping elements
9627 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>';
9629 * Visibility mode constant - Use visibility to hide element
9635 * Visibility mode constant - Use display to hide element
9641 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9642 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9643 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9655 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9656 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9657 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9658 * @return {Element} The Element object
9661 El.get = function(el){
9663 if(!el){ return null; }
9664 if(typeof el == "string"){ // element id
9665 if(!(elm = document.getElementById(el))){
9668 if(ex = El.cache[el]){
9671 ex = El.cache[el] = new El(elm);
9674 }else if(el.tagName){ // dom element
9678 if(ex = El.cache[id]){
9681 ex = El.cache[id] = new El(el);
9684 }else if(el instanceof El){
9686 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9687 // catch case where it hasn't been appended
9688 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9691 }else if(el.isComposite){
9693 }else if(el instanceof Array){
9694 return El.select(el);
9695 }else if(el == document){
9696 // create a bogus element object representing the document object
9698 var f = function(){};
9699 f.prototype = El.prototype;
9701 docEl.dom = document;
9709 El.uncache = function(el){
9710 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9712 delete El.cache[a[i].id || a[i]];
9718 // Garbage collection - uncache elements/purge listeners on orphaned elements
9719 // so we don't hold a reference and cause the browser to retain them
9720 El.garbageCollect = function(){
9721 if(!Roo.enableGarbageCollector){
9722 clearInterval(El.collectorThread);
9725 for(var eid in El.cache){
9726 var el = El.cache[eid], d = el.dom;
9727 // -------------------------------------------------------
9728 // Determining what is garbage:
9729 // -------------------------------------------------------
9731 // dom node is null, definitely garbage
9732 // -------------------------------------------------------
9734 // no parentNode == direct orphan, definitely garbage
9735 // -------------------------------------------------------
9736 // !d.offsetParent && !document.getElementById(eid)
9737 // display none elements have no offsetParent so we will
9738 // also try to look it up by it's id. However, check
9739 // offsetParent first so we don't do unneeded lookups.
9740 // This enables collection of elements that are not orphans
9741 // directly, but somewhere up the line they have an orphan
9743 // -------------------------------------------------------
9744 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9745 delete El.cache[eid];
9746 if(d && Roo.enableListenerCollection){
9752 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9756 El.Flyweight = function(dom){
9759 El.Flyweight.prototype = El.prototype;
9761 El._flyweights = {};
9763 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9764 * the dom node can be overwritten by other code.
9765 * @param {String/HTMLElement} el The dom node or id
9766 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9767 * prevent conflicts (e.g. internally Roo uses "_internal")
9769 * @return {Element} The shared Element object
9771 El.fly = function(el, named){
9772 named = named || '_global';
9773 el = Roo.getDom(el);
9777 if(!El._flyweights[named]){
9778 El._flyweights[named] = new El.Flyweight();
9780 El._flyweights[named].dom = el;
9781 return El._flyweights[named];
9785 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9786 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9787 * Shorthand of {@link Roo.Element#get}
9788 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9789 * @return {Element} The Element object
9795 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9796 * the dom node can be overwritten by other code.
9797 * Shorthand of {@link Roo.Element#fly}
9798 * @param {String/HTMLElement} el The dom node or id
9799 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9800 * prevent conflicts (e.g. internally Roo uses "_internal")
9802 * @return {Element} The shared Element object
9808 // speedy lookup for elements never to box adjust
9809 var noBoxAdjust = Roo.isStrict ? {
9812 input:1, select:1, textarea:1
9814 if(Roo.isIE || Roo.isGecko){
9815 noBoxAdjust['button'] = 1;
9819 Roo.EventManager.on(window, 'unload', function(){
9821 delete El._flyweights;
9829 Roo.Element.selectorFunction = Roo.DomQuery.select;
9832 Roo.Element.select = function(selector, unique, root){
9834 if(typeof selector == "string"){
9835 els = Roo.Element.selectorFunction(selector, root);
9836 }else if(selector.length !== undefined){
9839 throw "Invalid selector";
9841 if(unique === true){
9842 return new Roo.CompositeElement(els);
9844 return new Roo.CompositeElementLite(els);
9848 * Selects elements based on the passed CSS selector to enable working on them as 1.
9849 * @param {String/Array} selector The CSS selector or an array of elements
9850 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9851 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9852 * @return {CompositeElementLite/CompositeElement}
9856 Roo.select = Roo.Element.select;
9873 * Ext JS Library 1.1.1
9874 * Copyright(c) 2006-2007, Ext JS, LLC.
9876 * Originally Released Under LGPL - original licence link has changed is not relivant.
9879 * <script type="text/javascript">
9884 //Notifies Element that fx methods are available
9885 Roo.enableFx = true;
9889 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9890 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9891 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9892 * Element effects to work.</p><br/>
9894 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9895 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9896 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9897 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9898 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9899 * expected results and should be done with care.</p><br/>
9901 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9902 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9905 ----- -----------------------------
9906 tl The top left corner
9907 t The center of the top edge
9908 tr The top right corner
9909 l The center of the left edge
9910 r The center of the right edge
9911 bl The bottom left corner
9912 b The center of the bottom edge
9913 br The bottom right corner
9915 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9916 * below are common options that can be passed to any Fx method.</b>
9917 * @cfg {Function} callback A function called when the effect is finished
9918 * @cfg {Object} scope The scope of the effect function
9919 * @cfg {String} easing A valid Easing value for the effect
9920 * @cfg {String} afterCls A css class to apply after the effect
9921 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9922 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9923 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9924 * effects that end with the element being visually hidden, ignored otherwise)
9925 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9926 * a function which returns such a specification that will be applied to the Element after the effect finishes
9927 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9928 * @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
9929 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9933 * Slides the element into view. An anchor point can be optionally passed to set the point of
9934 * origin for the slide effect. This function automatically handles wrapping the element with
9935 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9938 // default: slide the element in from the top
9941 // custom: slide the element in from the right with a 2-second duration
9942 el.slideIn('r', { duration: 2 });
9944 // common config options shown with default values
9950 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9951 * @param {Object} options (optional) Object literal with any of the Fx config options
9952 * @return {Roo.Element} The Element
9954 slideIn : function(anchor, o){
9955 var el = this.getFxEl();
9958 el.queueFx(o, function(){
9960 anchor = anchor || "t";
9962 // fix display to visibility
9965 // restore values after effect
9966 var r = this.getFxRestore();
9967 var b = this.getBox();
9968 // fixed size for slide
9972 var wrap = this.fxWrap(r.pos, o, "hidden");
9974 var st = this.dom.style;
9975 st.visibility = "visible";
9976 st.position = "absolute";
9978 // clear out temp styles after slide and unwrap
9979 var after = function(){
9980 el.fxUnwrap(wrap, r.pos, o);
9982 st.height = r.height;
9985 // time to calc the positions
9986 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9988 switch(anchor.toLowerCase()){
9990 wrap.setSize(b.width, 0);
9991 st.left = st.bottom = "0";
9995 wrap.setSize(0, b.height);
9996 st.right = st.top = "0";
10000 wrap.setSize(0, b.height);
10001 wrap.setX(b.right);
10002 st.left = st.top = "0";
10003 a = {width: bw, points: pt};
10006 wrap.setSize(b.width, 0);
10007 wrap.setY(b.bottom);
10008 st.left = st.top = "0";
10009 a = {height: bh, points: pt};
10012 wrap.setSize(0, 0);
10013 st.right = st.bottom = "0";
10014 a = {width: bw, height: bh};
10017 wrap.setSize(0, 0);
10018 wrap.setY(b.y+b.height);
10019 st.right = st.top = "0";
10020 a = {width: bw, height: bh, points: pt};
10023 wrap.setSize(0, 0);
10024 wrap.setXY([b.right, b.bottom]);
10025 st.left = st.top = "0";
10026 a = {width: bw, height: bh, points: pt};
10029 wrap.setSize(0, 0);
10030 wrap.setX(b.x+b.width);
10031 st.left = st.bottom = "0";
10032 a = {width: bw, height: bh, points: pt};
10035 this.dom.style.visibility = "visible";
10038 arguments.callee.anim = wrap.fxanim(a,
10048 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10049 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10050 * 'hidden') but block elements will still take up space in the document. The element must be removed
10051 * from the DOM using the 'remove' config option if desired. This function automatically handles
10052 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10055 // default: slide the element out to the top
10058 // custom: slide the element out to the right with a 2-second duration
10059 el.slideOut('r', { duration: 2 });
10061 // common config options shown with default values
10069 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10070 * @param {Object} options (optional) Object literal with any of the Fx config options
10071 * @return {Roo.Element} The Element
10073 slideOut : function(anchor, o){
10074 var el = this.getFxEl();
10077 el.queueFx(o, function(){
10079 anchor = anchor || "t";
10081 // restore values after effect
10082 var r = this.getFxRestore();
10084 var b = this.getBox();
10085 // fixed size for slide
10089 var wrap = this.fxWrap(r.pos, o, "visible");
10091 var st = this.dom.style;
10092 st.visibility = "visible";
10093 st.position = "absolute";
10097 var after = function(){
10099 el.setDisplayed(false);
10104 el.fxUnwrap(wrap, r.pos, o);
10106 st.width = r.width;
10107 st.height = r.height;
10112 var a, zero = {to: 0};
10113 switch(anchor.toLowerCase()){
10115 st.left = st.bottom = "0";
10116 a = {height: zero};
10119 st.right = st.top = "0";
10123 st.left = st.top = "0";
10124 a = {width: zero, points: {to:[b.right, b.y]}};
10127 st.left = st.top = "0";
10128 a = {height: zero, points: {to:[b.x, b.bottom]}};
10131 st.right = st.bottom = "0";
10132 a = {width: zero, height: zero};
10135 st.right = st.top = "0";
10136 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10139 st.left = st.top = "0";
10140 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10143 st.left = st.bottom = "0";
10144 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10148 arguments.callee.anim = wrap.fxanim(a,
10158 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10159 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10160 * The element must be removed from the DOM using the 'remove' config option if desired.
10166 // common config options shown with default values
10174 * @param {Object} options (optional) Object literal with any of the Fx config options
10175 * @return {Roo.Element} The Element
10177 puff : function(o){
10178 var el = this.getFxEl();
10181 el.queueFx(o, function(){
10182 this.clearOpacity();
10185 // restore values after effect
10186 var r = this.getFxRestore();
10187 var st = this.dom.style;
10189 var after = function(){
10191 el.setDisplayed(false);
10198 el.setPositioning(r.pos);
10199 st.width = r.width;
10200 st.height = r.height;
10205 var width = this.getWidth();
10206 var height = this.getHeight();
10208 arguments.callee.anim = this.fxanim({
10209 width : {to: this.adjustWidth(width * 2)},
10210 height : {to: this.adjustHeight(height * 2)},
10211 points : {by: [-(width * .5), -(height * .5)]},
10213 fontSize: {to:200, unit: "%"}
10224 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10225 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10226 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10232 // all config options shown with default values
10240 * @param {Object} options (optional) Object literal with any of the Fx config options
10241 * @return {Roo.Element} The Element
10243 switchOff : function(o){
10244 var el = this.getFxEl();
10247 el.queueFx(o, function(){
10248 this.clearOpacity();
10251 // restore values after effect
10252 var r = this.getFxRestore();
10253 var st = this.dom.style;
10255 var after = function(){
10257 el.setDisplayed(false);
10263 el.setPositioning(r.pos);
10264 st.width = r.width;
10265 st.height = r.height;
10270 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10271 this.clearOpacity();
10275 points:{by:[0, this.getHeight() * .5]}
10276 }, o, 'motion', 0.3, 'easeIn', after);
10277 }).defer(100, this);
10284 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10285 * changed using the "attr" config option) and then fading back to the original color. If no original
10286 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10289 // default: highlight background to yellow
10292 // custom: highlight foreground text to blue for 2 seconds
10293 el.highlight("0000ff", { attr: 'color', duration: 2 });
10295 // common config options shown with default values
10296 el.highlight("ffff9c", {
10297 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10298 endColor: (current color) or "ffffff",
10303 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10304 * @param {Object} options (optional) Object literal with any of the Fx config options
10305 * @return {Roo.Element} The Element
10307 highlight : function(color, o){
10308 var el = this.getFxEl();
10311 el.queueFx(o, function(){
10312 color = color || "ffff9c";
10313 attr = o.attr || "backgroundColor";
10315 this.clearOpacity();
10318 var origColor = this.getColor(attr);
10319 var restoreColor = this.dom.style[attr];
10320 endColor = (o.endColor || origColor) || "ffffff";
10322 var after = function(){
10323 el.dom.style[attr] = restoreColor;
10328 a[attr] = {from: color, to: endColor};
10329 arguments.callee.anim = this.fxanim(a,
10339 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10342 // default: a single light blue ripple
10345 // custom: 3 red ripples lasting 3 seconds total
10346 el.frame("ff0000", 3, { duration: 3 });
10348 // common config options shown with default values
10349 el.frame("C3DAF9", 1, {
10350 duration: 1 //duration of entire animation (not each individual ripple)
10351 // Note: Easing is not configurable and will be ignored if included
10354 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10355 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10356 * @param {Object} options (optional) Object literal with any of the Fx config options
10357 * @return {Roo.Element} The Element
10359 frame : function(color, count, o){
10360 var el = this.getFxEl();
10363 el.queueFx(o, function(){
10364 color = color || "#C3DAF9";
10365 if(color.length == 6){
10366 color = "#" + color;
10368 count = count || 1;
10369 duration = o.duration || 1;
10372 var b = this.getBox();
10373 var animFn = function(){
10374 var proxy = this.createProxy({
10377 visbility:"hidden",
10378 position:"absolute",
10379 "z-index":"35000", // yee haw
10380 border:"0px solid " + color
10383 var scale = Roo.isBorderBox ? 2 : 1;
10385 top:{from:b.y, to:b.y - 20},
10386 left:{from:b.x, to:b.x - 20},
10387 borderWidth:{from:0, to:10},
10388 opacity:{from:1, to:0},
10389 height:{from:b.height, to:(b.height + (20*scale))},
10390 width:{from:b.width, to:(b.width + (20*scale))}
10391 }, duration, function(){
10395 animFn.defer((duration/2)*1000, this);
10406 * Creates a pause before any subsequent queued effects begin. If there are
10407 * no effects queued after the pause it will have no effect.
10412 * @param {Number} seconds The length of time to pause (in seconds)
10413 * @return {Roo.Element} The Element
10415 pause : function(seconds){
10416 var el = this.getFxEl();
10419 el.queueFx(o, function(){
10420 setTimeout(function(){
10422 }, seconds * 1000);
10428 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10429 * using the "endOpacity" config option.
10432 // default: fade in from opacity 0 to 100%
10435 // custom: fade in from opacity 0 to 75% over 2 seconds
10436 el.fadeIn({ endOpacity: .75, duration: 2});
10438 // common config options shown with default values
10440 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10445 * @param {Object} options (optional) Object literal with any of the Fx config options
10446 * @return {Roo.Element} The Element
10448 fadeIn : function(o){
10449 var el = this.getFxEl();
10451 el.queueFx(o, function(){
10452 this.setOpacity(0);
10454 this.dom.style.visibility = 'visible';
10455 var to = o.endOpacity || 1;
10456 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10457 o, null, .5, "easeOut", function(){
10459 this.clearOpacity();
10468 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10469 * using the "endOpacity" config option.
10472 // default: fade out from the element's current opacity to 0
10475 // custom: fade out from the element's current opacity to 25% over 2 seconds
10476 el.fadeOut({ endOpacity: .25, duration: 2});
10478 // common config options shown with default values
10480 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10487 * @param {Object} options (optional) Object literal with any of the Fx config options
10488 * @return {Roo.Element} The Element
10490 fadeOut : function(o){
10491 var el = this.getFxEl();
10493 el.queueFx(o, function(){
10494 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10495 o, null, .5, "easeOut", function(){
10496 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10497 this.dom.style.display = "none";
10499 this.dom.style.visibility = "hidden";
10501 this.clearOpacity();
10509 * Animates the transition of an element's dimensions from a starting height/width
10510 * to an ending height/width.
10513 // change height and width to 100x100 pixels
10514 el.scale(100, 100);
10516 // common config options shown with default values. The height and width will default to
10517 // the element's existing values if passed as null.
10520 [element's height], {
10525 * @param {Number} width The new width (pass undefined to keep the original width)
10526 * @param {Number} height The new height (pass undefined to keep the original height)
10527 * @param {Object} options (optional) Object literal with any of the Fx config options
10528 * @return {Roo.Element} The Element
10530 scale : function(w, h, o){
10531 this.shift(Roo.apply({}, o, {
10539 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10540 * Any of these properties not specified in the config object will not be changed. This effect
10541 * requires that at least one new dimension, position or opacity setting must be passed in on
10542 * the config object in order for the function to have any effect.
10545 // slide the element horizontally to x position 200 while changing the height and opacity
10546 el.shift({ x: 200, height: 50, opacity: .8 });
10548 // common config options shown with default values.
10550 width: [element's width],
10551 height: [element's height],
10552 x: [element's x position],
10553 y: [element's y position],
10554 opacity: [element's opacity],
10559 * @param {Object} options Object literal with any of the Fx config options
10560 * @return {Roo.Element} The Element
10562 shift : function(o){
10563 var el = this.getFxEl();
10565 el.queueFx(o, function(){
10566 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10567 if(w !== undefined){
10568 a.width = {to: this.adjustWidth(w)};
10570 if(h !== undefined){
10571 a.height = {to: this.adjustHeight(h)};
10573 if(x !== undefined || y !== undefined){
10575 x !== undefined ? x : this.getX(),
10576 y !== undefined ? y : this.getY()
10579 if(op !== undefined){
10580 a.opacity = {to: op};
10582 if(o.xy !== undefined){
10583 a.points = {to: o.xy};
10585 arguments.callee.anim = this.fxanim(a,
10586 o, 'motion', .35, "easeOut", function(){
10594 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10595 * ending point of the effect.
10598 // default: slide the element downward while fading out
10601 // custom: slide the element out to the right with a 2-second duration
10602 el.ghost('r', { duration: 2 });
10604 // common config options shown with default values
10612 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10613 * @param {Object} options (optional) Object literal with any of the Fx config options
10614 * @return {Roo.Element} The Element
10616 ghost : function(anchor, o){
10617 var el = this.getFxEl();
10620 el.queueFx(o, function(){
10621 anchor = anchor || "b";
10623 // restore values after effect
10624 var r = this.getFxRestore();
10625 var w = this.getWidth(),
10626 h = this.getHeight();
10628 var st = this.dom.style;
10630 var after = function(){
10632 el.setDisplayed(false);
10638 el.setPositioning(r.pos);
10639 st.width = r.width;
10640 st.height = r.height;
10645 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10646 switch(anchor.toLowerCase()){
10673 arguments.callee.anim = this.fxanim(a,
10683 * Ensures that all effects queued after syncFx is called on the element are
10684 * run concurrently. This is the opposite of {@link #sequenceFx}.
10685 * @return {Roo.Element} The Element
10687 syncFx : function(){
10688 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10697 * Ensures that all effects queued after sequenceFx is called on the element are
10698 * run in sequence. This is the opposite of {@link #syncFx}.
10699 * @return {Roo.Element} The Element
10701 sequenceFx : function(){
10702 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10704 concurrent : false,
10711 nextFx : function(){
10712 var ef = this.fxQueue[0];
10719 * Returns true if the element has any effects actively running or queued, else returns false.
10720 * @return {Boolean} True if element has active effects, else false
10722 hasActiveFx : function(){
10723 return this.fxQueue && this.fxQueue[0];
10727 * Stops any running effects and clears the element's internal effects queue if it contains
10728 * any additional effects that haven't started yet.
10729 * @return {Roo.Element} The Element
10731 stopFx : function(){
10732 if(this.hasActiveFx()){
10733 var cur = this.fxQueue[0];
10734 if(cur && cur.anim && cur.anim.isAnimated()){
10735 this.fxQueue = [cur]; // clear out others
10736 cur.anim.stop(true);
10743 beforeFx : function(o){
10744 if(this.hasActiveFx() && !o.concurrent){
10755 * Returns true if the element is currently blocking so that no other effect can be queued
10756 * until this effect is finished, else returns false if blocking is not set. This is commonly
10757 * used to ensure that an effect initiated by a user action runs to completion prior to the
10758 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10759 * @return {Boolean} True if blocking, else false
10761 hasFxBlock : function(){
10762 var q = this.fxQueue;
10763 return q && q[0] && q[0].block;
10767 queueFx : function(o, fn){
10771 if(!this.hasFxBlock()){
10772 Roo.applyIf(o, this.fxDefaults);
10774 var run = this.beforeFx(o);
10775 fn.block = o.block;
10776 this.fxQueue.push(fn);
10788 fxWrap : function(pos, o, vis){
10790 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10793 wrapXY = this.getXY();
10795 var div = document.createElement("div");
10796 div.style.visibility = vis;
10797 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10798 wrap.setPositioning(pos);
10799 if(wrap.getStyle("position") == "static"){
10800 wrap.position("relative");
10802 this.clearPositioning('auto');
10804 wrap.dom.appendChild(this.dom);
10806 wrap.setXY(wrapXY);
10813 fxUnwrap : function(wrap, pos, o){
10814 this.clearPositioning();
10815 this.setPositioning(pos);
10817 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10823 getFxRestore : function(){
10824 var st = this.dom.style;
10825 return {pos: this.getPositioning(), width: st.width, height : st.height};
10829 afterFx : function(o){
10831 this.applyStyles(o.afterStyle);
10834 this.addClass(o.afterCls);
10836 if(o.remove === true){
10839 Roo.callback(o.callback, o.scope, [this]);
10841 this.fxQueue.shift();
10847 getFxEl : function(){ // support for composite element fx
10848 return Roo.get(this.dom);
10852 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10853 animType = animType || 'run';
10855 var anim = Roo.lib.Anim[animType](
10857 (opt.duration || defaultDur) || .35,
10858 (opt.easing || defaultEase) || 'easeOut',
10860 Roo.callback(cb, this);
10869 // backwords compat
10870 Roo.Fx.resize = Roo.Fx.scale;
10872 //When included, Roo.Fx is automatically applied to Element so that all basic
10873 //effects are available directly via the Element API
10874 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10876 * Ext JS Library 1.1.1
10877 * Copyright(c) 2006-2007, Ext JS, LLC.
10879 * Originally Released Under LGPL - original licence link has changed is not relivant.
10882 * <script type="text/javascript">
10887 * @class Roo.CompositeElement
10888 * Standard composite class. Creates a Roo.Element for every element in the collection.
10890 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10891 * actions will be performed on all the elements in this collection.</b>
10893 * All methods return <i>this</i> and can be chained.
10895 var els = Roo.select("#some-el div.some-class", true);
10896 // or select directly from an existing element
10897 var el = Roo.get('some-el');
10898 el.select('div.some-class', true);
10900 els.setWidth(100); // all elements become 100 width
10901 els.hide(true); // all elements fade out and hide
10903 els.setWidth(100).hide(true);
10906 Roo.CompositeElement = function(els){
10907 this.elements = [];
10908 this.addElements(els);
10910 Roo.CompositeElement.prototype = {
10912 addElements : function(els){
10913 if(!els) return this;
10914 if(typeof els == "string"){
10915 els = Roo.Element.selectorFunction(els);
10917 var yels = this.elements;
10918 var index = yels.length-1;
10919 for(var i = 0, len = els.length; i < len; i++) {
10920 yels[++index] = Roo.get(els[i]);
10926 * Clears this composite and adds the elements returned by the passed selector.
10927 * @param {String/Array} els A string CSS selector, an array of elements or an element
10928 * @return {CompositeElement} this
10930 fill : function(els){
10931 this.elements = [];
10937 * Filters this composite to only elements that match the passed selector.
10938 * @param {String} selector A string CSS selector
10939 * @return {CompositeElement} this
10941 filter : function(selector){
10943 this.each(function(el){
10944 if(el.is(selector)){
10945 els[els.length] = el.dom;
10952 invoke : function(fn, args){
10953 var els = this.elements;
10954 for(var i = 0, len = els.length; i < len; i++) {
10955 Roo.Element.prototype[fn].apply(els[i], args);
10960 * Adds elements to this composite.
10961 * @param {String/Array} els A string CSS selector, an array of elements or an element
10962 * @return {CompositeElement} this
10964 add : function(els){
10965 if(typeof els == "string"){
10966 this.addElements(Roo.Element.selectorFunction(els));
10967 }else if(els.length !== undefined){
10968 this.addElements(els);
10970 this.addElements([els]);
10975 * Calls the passed function passing (el, this, index) for each element in this composite.
10976 * @param {Function} fn The function to call
10977 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10978 * @return {CompositeElement} this
10980 each : function(fn, scope){
10981 var els = this.elements;
10982 for(var i = 0, len = els.length; i < len; i++){
10983 if(fn.call(scope || els[i], els[i], this, i) === false) {
10991 * Returns the Element object at the specified index
10992 * @param {Number} index
10993 * @return {Roo.Element}
10995 item : function(index){
10996 return this.elements[index] || null;
11000 * Returns the first Element
11001 * @return {Roo.Element}
11003 first : function(){
11004 return this.item(0);
11008 * Returns the last Element
11009 * @return {Roo.Element}
11012 return this.item(this.elements.length-1);
11016 * Returns the number of elements in this composite
11019 getCount : function(){
11020 return this.elements.length;
11024 * Returns true if this composite contains the passed element
11027 contains : function(el){
11028 return this.indexOf(el) !== -1;
11032 * Returns true if this composite contains the passed element
11035 indexOf : function(el){
11036 return this.elements.indexOf(Roo.get(el));
11041 * Removes the specified element(s).
11042 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11043 * or an array of any of those.
11044 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11045 * @return {CompositeElement} this
11047 removeElement : function(el, removeDom){
11048 if(el instanceof Array){
11049 for(var i = 0, len = el.length; i < len; i++){
11050 this.removeElement(el[i]);
11054 var index = typeof el == 'number' ? el : this.indexOf(el);
11057 var d = this.elements[index];
11061 d.parentNode.removeChild(d);
11064 this.elements.splice(index, 1);
11070 * Replaces the specified element with the passed element.
11071 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11073 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11074 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11075 * @return {CompositeElement} this
11077 replaceElement : function(el, replacement, domReplace){
11078 var index = typeof el == 'number' ? el : this.indexOf(el);
11081 this.elements[index].replaceWith(replacement);
11083 this.elements.splice(index, 1, Roo.get(replacement))
11090 * Removes all elements.
11092 clear : function(){
11093 this.elements = [];
11097 Roo.CompositeElement.createCall = function(proto, fnName){
11098 if(!proto[fnName]){
11099 proto[fnName] = function(){
11100 return this.invoke(fnName, arguments);
11104 for(var fnName in Roo.Element.prototype){
11105 if(typeof Roo.Element.prototype[fnName] == "function"){
11106 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11112 * Ext JS Library 1.1.1
11113 * Copyright(c) 2006-2007, Ext JS, LLC.
11115 * Originally Released Under LGPL - original licence link has changed is not relivant.
11118 * <script type="text/javascript">
11122 * @class Roo.CompositeElementLite
11123 * @extends Roo.CompositeElement
11124 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11126 var els = Roo.select("#some-el div.some-class");
11127 // or select directly from an existing element
11128 var el = Roo.get('some-el');
11129 el.select('div.some-class');
11131 els.setWidth(100); // all elements become 100 width
11132 els.hide(true); // all elements fade out and hide
11134 els.setWidth(100).hide(true);
11135 </code></pre><br><br>
11136 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11137 * actions will be performed on all the elements in this collection.</b>
11139 Roo.CompositeElementLite = function(els){
11140 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11141 this.el = new Roo.Element.Flyweight();
11143 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11144 addElements : function(els){
11146 if(els instanceof Array){
11147 this.elements = this.elements.concat(els);
11149 var yels = this.elements;
11150 var index = yels.length-1;
11151 for(var i = 0, len = els.length; i < len; i++) {
11152 yels[++index] = els[i];
11158 invoke : function(fn, args){
11159 var els = this.elements;
11161 for(var i = 0, len = els.length; i < len; i++) {
11163 Roo.Element.prototype[fn].apply(el, args);
11168 * Returns a flyweight Element of the dom element object at the specified index
11169 * @param {Number} index
11170 * @return {Roo.Element}
11172 item : function(index){
11173 if(!this.elements[index]){
11176 this.el.dom = this.elements[index];
11180 // fixes scope with flyweight
11181 addListener : function(eventName, handler, scope, opt){
11182 var els = this.elements;
11183 for(var i = 0, len = els.length; i < len; i++) {
11184 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11190 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11191 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11192 * a reference to the dom node, use el.dom.</b>
11193 * @param {Function} fn The function to call
11194 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11195 * @return {CompositeElement} this
11197 each : function(fn, scope){
11198 var els = this.elements;
11200 for(var i = 0, len = els.length; i < len; i++){
11202 if(fn.call(scope || el, el, this, i) === false){
11209 indexOf : function(el){
11210 return this.elements.indexOf(Roo.getDom(el));
11213 replaceElement : function(el, replacement, domReplace){
11214 var index = typeof el == 'number' ? el : this.indexOf(el);
11216 replacement = Roo.getDom(replacement);
11218 var d = this.elements[index];
11219 d.parentNode.insertBefore(replacement, d);
11220 d.parentNode.removeChild(d);
11222 this.elements.splice(index, 1, replacement);
11227 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11231 * Ext JS Library 1.1.1
11232 * Copyright(c) 2006-2007, Ext JS, LLC.
11234 * Originally Released Under LGPL - original licence link has changed is not relivant.
11237 * <script type="text/javascript">
11243 * @class Roo.data.Connection
11244 * @extends Roo.util.Observable
11245 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11246 * either to a configured URL, or to a URL specified at request time.<br><br>
11248 * Requests made by this class are asynchronous, and will return immediately. No data from
11249 * the server will be available to the statement immediately following the {@link #request} call.
11250 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11252 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11253 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11254 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11255 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11256 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11257 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11258 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11259 * standard DOM methods.
11261 * @param {Object} config a configuration object.
11263 Roo.data.Connection = function(config){
11264 Roo.apply(this, config);
11267 * @event beforerequest
11268 * Fires before a network request is made to retrieve a data object.
11269 * @param {Connection} conn This Connection object.
11270 * @param {Object} options The options config object passed to the {@link #request} method.
11272 "beforerequest" : true,
11274 * @event requestcomplete
11275 * Fires if the request was successfully completed.
11276 * @param {Connection} conn This Connection object.
11277 * @param {Object} response The XHR object containing the response data.
11278 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11279 * @param {Object} options The options config object passed to the {@link #request} method.
11281 "requestcomplete" : true,
11283 * @event requestexception
11284 * Fires if an error HTTP status was returned from the server.
11285 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11286 * @param {Connection} conn This Connection object.
11287 * @param {Object} response The XHR object containing the response data.
11288 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11289 * @param {Object} options The options config object passed to the {@link #request} method.
11291 "requestexception" : true
11293 Roo.data.Connection.superclass.constructor.call(this);
11296 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11298 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11301 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11302 * extra parameters to each request made by this object. (defaults to undefined)
11305 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11306 * to each request made by this object. (defaults to undefined)
11309 * @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)
11312 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11316 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11322 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11325 disableCaching: true,
11328 * Sends an HTTP request to a remote server.
11329 * @param {Object} options An object which may contain the following properties:<ul>
11330 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11331 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11332 * request, a url encoded string or a function to call to get either.</li>
11333 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11334 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11335 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11336 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11337 * <li>options {Object} The parameter to the request call.</li>
11338 * <li>success {Boolean} True if the request succeeded.</li>
11339 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11341 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11342 * The callback is passed the following parameters:<ul>
11343 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11344 * <li>options {Object} The parameter to the request call.</li>
11346 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11347 * The callback is passed the following parameters:<ul>
11348 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11349 * <li>options {Object} The parameter to the request call.</li>
11351 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11352 * for the callback function. Defaults to the browser window.</li>
11353 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11354 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11355 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11356 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11357 * params for the post data. Any params will be appended to the URL.</li>
11358 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11360 * @return {Number} transactionId
11362 request : function(o){
11363 if(this.fireEvent("beforerequest", this, o) !== false){
11366 if(typeof p == "function"){
11367 p = p.call(o.scope||window, o);
11369 if(typeof p == "object"){
11370 p = Roo.urlEncode(o.params);
11372 if(this.extraParams){
11373 var extras = Roo.urlEncode(this.extraParams);
11374 p = p ? (p + '&' + extras) : extras;
11377 var url = o.url || this.url;
11378 if(typeof url == 'function'){
11379 url = url.call(o.scope||window, o);
11383 var form = Roo.getDom(o.form);
11384 url = url || form.action;
11386 var enctype = form.getAttribute("enctype");
11387 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11388 return this.doFormUpload(o, p, url);
11390 var f = Roo.lib.Ajax.serializeForm(form);
11391 p = p ? (p + '&' + f) : f;
11394 var hs = o.headers;
11395 if(this.defaultHeaders){
11396 hs = Roo.apply(hs || {}, this.defaultHeaders);
11403 success: this.handleResponse,
11404 failure: this.handleFailure,
11406 argument: {options: o},
11407 timeout : o.timeout || this.timeout
11410 var method = o.method||this.method||(p ? "POST" : "GET");
11412 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11413 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11416 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11420 }else if(this.autoAbort !== false){
11424 if((method == 'GET' && p) || o.xmlData){
11425 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11428 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11429 return this.transId;
11431 Roo.callback(o.callback, o.scope, [o, null, null]);
11437 * Determine whether this object has a request outstanding.
11438 * @param {Number} transactionId (Optional) defaults to the last transaction
11439 * @return {Boolean} True if there is an outstanding request.
11441 isLoading : function(transId){
11443 return Roo.lib.Ajax.isCallInProgress(transId);
11445 return this.transId ? true : false;
11450 * Aborts any outstanding request.
11451 * @param {Number} transactionId (Optional) defaults to the last transaction
11453 abort : function(transId){
11454 if(transId || this.isLoading()){
11455 Roo.lib.Ajax.abort(transId || this.transId);
11460 handleResponse : function(response){
11461 this.transId = false;
11462 var options = response.argument.options;
11463 response.argument = options ? options.argument : null;
11464 this.fireEvent("requestcomplete", this, response, options);
11465 Roo.callback(options.success, options.scope, [response, options]);
11466 Roo.callback(options.callback, options.scope, [options, true, response]);
11470 handleFailure : function(response, e){
11471 this.transId = false;
11472 var options = response.argument.options;
11473 response.argument = options ? options.argument : null;
11474 this.fireEvent("requestexception", this, response, options, e);
11475 Roo.callback(options.failure, options.scope, [response, options]);
11476 Roo.callback(options.callback, options.scope, [options, false, response]);
11480 doFormUpload : function(o, ps, url){
11482 var frame = document.createElement('iframe');
11485 frame.className = 'x-hidden';
11487 frame.src = Roo.SSL_SECURE_URL;
11489 document.body.appendChild(frame);
11492 document.frames[id].name = id;
11495 var form = Roo.getDom(o.form);
11497 form.method = 'POST';
11498 form.enctype = form.encoding = 'multipart/form-data';
11504 if(ps){ // add dynamic params
11506 ps = Roo.urlDecode(ps, false);
11508 if(ps.hasOwnProperty(k)){
11509 hd = document.createElement('input');
11510 hd.type = 'hidden';
11513 form.appendChild(hd);
11520 var r = { // bogus response object
11525 r.argument = o ? o.argument : null;
11530 doc = frame.contentWindow.document;
11532 doc = (frame.contentDocument || window.frames[id].document);
11534 if(doc && doc.body){
11535 r.responseText = doc.body.innerHTML;
11537 if(doc && doc.XMLDocument){
11538 r.responseXML = doc.XMLDocument;
11540 r.responseXML = doc;
11547 Roo.EventManager.removeListener(frame, 'load', cb, this);
11549 this.fireEvent("requestcomplete", this, r, o);
11550 Roo.callback(o.success, o.scope, [r, o]);
11551 Roo.callback(o.callback, o.scope, [o, true, r]);
11553 setTimeout(function(){document.body.removeChild(frame);}, 100);
11556 Roo.EventManager.on(frame, 'load', cb, this);
11559 if(hiddens){ // remove dynamic params
11560 for(var i = 0, len = hiddens.length; i < len; i++){
11561 form.removeChild(hiddens[i]);
11568 * Ext JS Library 1.1.1
11569 * Copyright(c) 2006-2007, Ext JS, LLC.
11571 * Originally Released Under LGPL - original licence link has changed is not relivant.
11574 * <script type="text/javascript">
11578 * Global Ajax request class.
11581 * @extends Roo.data.Connection
11584 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11585 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11586 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11587 * @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)
11588 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11589 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11590 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11592 Roo.Ajax = new Roo.data.Connection({
11601 * Serialize the passed form into a url encoded string
11603 * @param {String/HTMLElement} form
11606 serializeForm : function(form){
11607 return Roo.lib.Ajax.serializeForm(form);
11611 * Ext JS Library 1.1.1
11612 * Copyright(c) 2006-2007, Ext JS, LLC.
11614 * Originally Released Under LGPL - original licence link has changed is not relivant.
11617 * <script type="text/javascript">
11622 * @class Roo.UpdateManager
11623 * @extends Roo.util.Observable
11624 * Provides AJAX-style update for Element object.<br><br>
11627 * // Get it from a Roo.Element object
11628 * var el = Roo.get("foo");
11629 * var mgr = el.getUpdateManager();
11630 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11632 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11634 * // or directly (returns the same UpdateManager instance)
11635 * var mgr = new Roo.UpdateManager("myElementId");
11636 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11637 * mgr.on("update", myFcnNeedsToKnow);
11639 // short handed call directly from the element object
11640 Roo.get("foo").load({
11644 text: "Loading Foo..."
11648 * Create new UpdateManager directly.
11649 * @param {String/HTMLElement/Roo.Element} el The element to update
11650 * @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).
11652 Roo.UpdateManager = function(el, forceNew){
11654 if(!forceNew && el.updateManager){
11655 return el.updateManager;
11658 * The Element object
11659 * @type Roo.Element
11663 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11666 this.defaultUrl = null;
11670 * @event beforeupdate
11671 * Fired before an update is made, return false from your handler and the update is cancelled.
11672 * @param {Roo.Element} el
11673 * @param {String/Object/Function} url
11674 * @param {String/Object} params
11676 "beforeupdate": true,
11679 * Fired after successful update is made.
11680 * @param {Roo.Element} el
11681 * @param {Object} oResponseObject The response Object
11686 * Fired on update failure.
11687 * @param {Roo.Element} el
11688 * @param {Object} oResponseObject The response Object
11692 var d = Roo.UpdateManager.defaults;
11694 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11697 this.sslBlankUrl = d.sslBlankUrl;
11699 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11702 this.disableCaching = d.disableCaching;
11704 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11707 this.indicatorText = d.indicatorText;
11709 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11712 this.showLoadIndicator = d.showLoadIndicator;
11714 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11717 this.timeout = d.timeout;
11720 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11723 this.loadScripts = d.loadScripts;
11726 * Transaction object of current executing transaction
11728 this.transaction = null;
11733 this.autoRefreshProcId = null;
11735 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11738 this.refreshDelegate = this.refresh.createDelegate(this);
11740 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11743 this.updateDelegate = this.update.createDelegate(this);
11745 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11748 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11752 this.successDelegate = this.processSuccess.createDelegate(this);
11756 this.failureDelegate = this.processFailure.createDelegate(this);
11758 if(!this.renderer){
11760 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11762 this.renderer = new Roo.UpdateManager.BasicRenderer();
11765 Roo.UpdateManager.superclass.constructor.call(this);
11768 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11770 * Get the Element this UpdateManager is bound to
11771 * @return {Roo.Element} The element
11773 getEl : function(){
11777 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11778 * @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:
11781 url: "your-url.php",<br/>
11782 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11783 callback: yourFunction,<br/>
11784 scope: yourObject, //(optional scope) <br/>
11785 discardUrl: false, <br/>
11786 nocache: false,<br/>
11787 text: "Loading...",<br/>
11789 scripts: false<br/>
11792 * The only required property is url. The optional properties nocache, text and scripts
11793 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11794 * @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}
11795 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11796 * @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.
11798 update : function(url, params, callback, discardUrl){
11799 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11800 var method = this.method,
11802 if(typeof url == "object"){ // must be config object
11805 params = params || cfg.params;
11806 callback = callback || cfg.callback;
11807 discardUrl = discardUrl || cfg.discardUrl;
11808 if(callback && cfg.scope){
11809 callback = callback.createDelegate(cfg.scope);
11811 if(typeof cfg.method != "undefined"){method = cfg.method;};
11812 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11813 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11814 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11815 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11817 this.showLoading();
11819 this.defaultUrl = url;
11821 if(typeof url == "function"){
11822 url = url.call(this);
11825 method = method || (params ? "POST" : "GET");
11826 if(method == "GET"){
11827 url = this.prepareUrl(url);
11830 var o = Roo.apply(cfg ||{}, {
11833 success: this.successDelegate,
11834 failure: this.failureDelegate,
11835 callback: undefined,
11836 timeout: (this.timeout*1000),
11837 argument: {"url": url, "form": null, "callback": callback, "params": params}
11839 Roo.log("updated manager called with timeout of " + o.timeout);
11840 this.transaction = Roo.Ajax.request(o);
11845 * 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.
11846 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11847 * @param {String/HTMLElement} form The form Id or form element
11848 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11849 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11850 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11852 formUpdate : function(form, url, reset, callback){
11853 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11854 if(typeof url == "function"){
11855 url = url.call(this);
11857 form = Roo.getDom(form);
11858 this.transaction = Roo.Ajax.request({
11861 success: this.successDelegate,
11862 failure: this.failureDelegate,
11863 timeout: (this.timeout*1000),
11864 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11866 this.showLoading.defer(1, this);
11871 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11872 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11874 refresh : function(callback){
11875 if(this.defaultUrl == null){
11878 this.update(this.defaultUrl, null, callback, true);
11882 * Set this element to auto refresh.
11883 * @param {Number} interval How often to update (in seconds).
11884 * @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)
11885 * @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}
11886 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11887 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11889 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11891 this.update(url || this.defaultUrl, params, callback, true);
11893 if(this.autoRefreshProcId){
11894 clearInterval(this.autoRefreshProcId);
11896 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11900 * Stop auto refresh on this element.
11902 stopAutoRefresh : function(){
11903 if(this.autoRefreshProcId){
11904 clearInterval(this.autoRefreshProcId);
11905 delete this.autoRefreshProcId;
11909 isAutoRefreshing : function(){
11910 return this.autoRefreshProcId ? true : false;
11913 * Called to update the element to "Loading" state. Override to perform custom action.
11915 showLoading : function(){
11916 if(this.showLoadIndicator){
11917 this.el.update(this.indicatorText);
11922 * Adds unique parameter to query string if disableCaching = true
11925 prepareUrl : function(url){
11926 if(this.disableCaching){
11927 var append = "_dc=" + (new Date().getTime());
11928 if(url.indexOf("?") !== -1){
11929 url += "&" + append;
11931 url += "?" + append;
11940 processSuccess : function(response){
11941 this.transaction = null;
11942 if(response.argument.form && response.argument.reset){
11943 try{ // put in try/catch since some older FF releases had problems with this
11944 response.argument.form.reset();
11947 if(this.loadScripts){
11948 this.renderer.render(this.el, response, this,
11949 this.updateComplete.createDelegate(this, [response]));
11951 this.renderer.render(this.el, response, this);
11952 this.updateComplete(response);
11956 updateComplete : function(response){
11957 this.fireEvent("update", this.el, response);
11958 if(typeof response.argument.callback == "function"){
11959 response.argument.callback(this.el, true, response);
11966 processFailure : function(response){
11967 this.transaction = null;
11968 this.fireEvent("failure", this.el, response);
11969 if(typeof response.argument.callback == "function"){
11970 response.argument.callback(this.el, false, response);
11975 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11976 * @param {Object} renderer The object implementing the render() method
11978 setRenderer : function(renderer){
11979 this.renderer = renderer;
11982 getRenderer : function(){
11983 return this.renderer;
11987 * Set the defaultUrl used for updates
11988 * @param {String/Function} defaultUrl The url or a function to call to get the url
11990 setDefaultUrl : function(defaultUrl){
11991 this.defaultUrl = defaultUrl;
11995 * Aborts the executing transaction
11997 abort : function(){
11998 if(this.transaction){
11999 Roo.Ajax.abort(this.transaction);
12004 * Returns true if an update is in progress
12005 * @return {Boolean}
12007 isUpdating : function(){
12008 if(this.transaction){
12009 return Roo.Ajax.isLoading(this.transaction);
12016 * @class Roo.UpdateManager.defaults
12017 * @static (not really - but it helps the doc tool)
12018 * The defaults collection enables customizing the default properties of UpdateManager
12020 Roo.UpdateManager.defaults = {
12022 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12028 * True to process scripts by default (Defaults to false).
12031 loadScripts : false,
12034 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12037 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12039 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12042 disableCaching : false,
12044 * Whether to show indicatorText when loading (Defaults to true).
12047 showLoadIndicator : true,
12049 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12052 indicatorText : '<div class="loading-indicator">Loading...</div>'
12056 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12058 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12059 * @param {String/HTMLElement/Roo.Element} el The element to update
12060 * @param {String} url The url
12061 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12062 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12065 * @member Roo.UpdateManager
12067 Roo.UpdateManager.updateElement = function(el, url, params, options){
12068 var um = Roo.get(el, true).getUpdateManager();
12069 Roo.apply(um, options);
12070 um.update(url, params, options ? options.callback : null);
12072 // alias for backwards compat
12073 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12075 * @class Roo.UpdateManager.BasicRenderer
12076 * Default Content renderer. Updates the elements innerHTML with the responseText.
12078 Roo.UpdateManager.BasicRenderer = function(){};
12080 Roo.UpdateManager.BasicRenderer.prototype = {
12082 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12083 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12084 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12085 * @param {Roo.Element} el The element being rendered
12086 * @param {Object} response The YUI Connect response object
12087 * @param {UpdateManager} updateManager The calling update manager
12088 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12090 render : function(el, response, updateManager, callback){
12091 el.update(response.responseText, updateManager.loadScripts, callback);
12097 * (c)) Alan Knowles
12103 * @class Roo.DomTemplate
12104 * @extends Roo.Template
12105 * An effort at a dom based template engine..
12107 * Similar to XTemplate, except it uses dom parsing to create the template..
12109 * Supported features:
12114 {a_variable} - output encoded.
12115 {a_variable.format:("Y-m-d")} - call a method on the variable
12116 {a_variable:raw} - unencoded output
12117 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12118 {a_variable:this.method_on_template(...)} - call a method on the template object.
12123 <div roo-for="a_variable or condition.."></div>
12124 <div roo-if="a_variable or condition"></div>
12125 <div roo-exec="some javascript"></div>
12126 <div roo-name="named_template"></div>
12131 Roo.DomTemplate = function()
12133 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12140 Roo.extend(Roo.DomTemplate, Roo.Template, {
12142 * id counter for sub templates.
12146 * flag to indicate if dom parser is inside a pre,
12147 * it will strip whitespace if not.
12152 * The various sub templates
12160 * basic tag replacing syntax
12163 * // you can fake an object call by doing this
12167 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12168 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12170 iterChild : function (node, method) {
12172 var oldPre = this.inPre;
12173 if (node.tagName == 'PRE') {
12176 for( var i = 0; i < node.childNodes.length; i++) {
12177 method.call(this, node.childNodes[i]);
12179 this.inPre = oldPre;
12185 * compile the template
12187 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12190 compile: function()
12194 // covert the html into DOM...
12198 doc = document.implementation.createHTMLDocument("");
12199 doc.documentElement.innerHTML = this.html ;
12200 div = doc.documentElement;
12202 // old IE... - nasty -- it causes all sorts of issues.. with
12203 // images getting pulled from server..
12204 div = document.createElement('div');
12205 div.innerHTML = this.html;
12207 //doc.documentElement.innerHTML = htmlBody
12213 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12215 var tpls = this.tpls;
12217 // create a top level template from the snippet..
12219 //Roo.log(div.innerHTML);
12226 body : div.innerHTML,
12239 Roo.each(tpls, function(tp){
12240 this.compileTpl(tp);
12241 this.tpls[tp.id] = tp;
12244 this.master = tpls[0];
12250 compileNode : function(node, istop) {
12255 // skip anything not a tag..
12256 if (node.nodeType != 1) {
12257 if (node.nodeType == 3 && !this.inPre) {
12258 // reduce white space..
12259 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12282 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12283 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12284 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12285 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12291 // just itterate children..
12292 this.iterChild(node,this.compileNode);
12295 tpl.uid = this.id++;
12296 tpl.value = node.getAttribute('roo-' + tpl.attr);
12297 node.removeAttribute('roo-'+ tpl.attr);
12298 if (tpl.attr != 'name') {
12299 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12300 node.parentNode.replaceChild(placeholder, node);
12303 var placeholder = document.createElement('span');
12304 placeholder.className = 'roo-tpl-' + tpl.value;
12305 node.parentNode.replaceChild(placeholder, node);
12308 // parent now sees '{domtplXXXX}
12309 this.iterChild(node,this.compileNode);
12311 // we should now have node body...
12312 var div = document.createElement('div');
12313 div.appendChild(node);
12315 // this has the unfortunate side effect of converting tagged attributes
12316 // eg. href="{...}" into %7C...%7D
12317 // this has been fixed by searching for those combo's although it's a bit hacky..
12320 tpl.body = div.innerHTML;
12327 switch (tpl.value) {
12328 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12329 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12330 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12335 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12339 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12343 tpl.id = tpl.value; // replace non characters???
12349 this.tpls.push(tpl);
12359 * Compile a segment of the template into a 'sub-template'
12365 compileTpl : function(tpl)
12367 var fm = Roo.util.Format;
12368 var useF = this.disableFormats !== true;
12370 var sep = Roo.isGecko ? "+\n" : ",\n";
12372 var undef = function(str) {
12373 Roo.debug && Roo.log("Property not found :" + str);
12377 //Roo.log(tpl.body);
12381 var fn = function(m, lbrace, name, format, args)
12384 //Roo.log(arguments);
12385 args = args ? args.replace(/\\'/g,"'") : args;
12386 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12387 if (typeof(format) == 'undefined') {
12388 format = 'htmlEncode';
12390 if (format == 'raw' ) {
12394 if(name.substr(0, 6) == 'domtpl'){
12395 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12398 // build an array of options to determine if value is undefined..
12400 // basically get 'xxxx.yyyy' then do
12401 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12402 // (function () { Roo.log("Property not found"); return ''; })() :
12407 Roo.each(name.split('.'), function(st) {
12408 lookfor += (lookfor.length ? '.': '') + st;
12409 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12412 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12415 if(format && useF){
12417 args = args ? ',' + args : "";
12419 if(format.substr(0, 5) != "this."){
12420 format = "fm." + format + '(';
12422 format = 'this.call("'+ format.substr(5) + '", ';
12426 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12429 if (args && args.length) {
12430 // called with xxyx.yuu:(test,test)
12432 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12434 // raw.. - :raw modifier..
12435 return "'"+ sep + udef_st + name + ")"+sep+"'";
12439 // branched to use + in gecko and [].join() in others
12441 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12442 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12445 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12446 body.push(tpl.body.replace(/(\r\n|\n)/g,
12447 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12448 body.push("'].join('');};};");
12449 body = body.join('');
12452 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12454 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12461 * same as applyTemplate, except it's done to one of the subTemplates
12462 * when using named templates, you can do:
12464 * var str = pl.applySubTemplate('your-name', values);
12467 * @param {Number} id of the template
12468 * @param {Object} values to apply to template
12469 * @param {Object} parent (normaly the instance of this object)
12471 applySubTemplate : function(id, values, parent)
12475 var t = this.tpls[id];
12479 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12480 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12484 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12491 if(t.execCall && t.execCall.call(this, values, parent)){
12495 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12501 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12502 parent = t.target ? values : parent;
12503 if(t.forCall && vs instanceof Array){
12505 for(var i = 0, len = vs.length; i < len; i++){
12507 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12509 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12511 //Roo.log(t.compiled);
12515 return buf.join('');
12518 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12523 return t.compiled.call(this, vs, parent);
12525 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12527 //Roo.log(t.compiled);
12535 applyTemplate : function(values){
12536 return this.master.compiled.call(this, values, {});
12537 //var s = this.subs;
12540 apply : function(){
12541 return this.applyTemplate.apply(this, arguments);
12546 Roo.DomTemplate.from = function(el){
12547 el = Roo.getDom(el);
12548 return new Roo.Domtemplate(el.value || el.innerHTML);
12551 * Ext JS Library 1.1.1
12552 * Copyright(c) 2006-2007, Ext JS, LLC.
12554 * Originally Released Under LGPL - original licence link has changed is not relivant.
12557 * <script type="text/javascript">
12561 * @class Roo.util.DelayedTask
12562 * Provides a convenient method of performing setTimeout where a new
12563 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12564 * You can use this class to buffer
12565 * the keypress events for a certain number of milliseconds, and perform only if they stop
12566 * for that amount of time.
12567 * @constructor The parameters to this constructor serve as defaults and are not required.
12568 * @param {Function} fn (optional) The default function to timeout
12569 * @param {Object} scope (optional) The default scope of that timeout
12570 * @param {Array} args (optional) The default Array of arguments
12572 Roo.util.DelayedTask = function(fn, scope, args){
12573 var id = null, d, t;
12575 var call = function(){
12576 var now = new Date().getTime();
12580 fn.apply(scope, args || []);
12584 * Cancels any pending timeout and queues a new one
12585 * @param {Number} delay The milliseconds to delay
12586 * @param {Function} newFn (optional) Overrides function passed to constructor
12587 * @param {Object} newScope (optional) Overrides scope passed to constructor
12588 * @param {Array} newArgs (optional) Overrides args passed to constructor
12590 this.delay = function(delay, newFn, newScope, newArgs){
12591 if(id && delay != d){
12595 t = new Date().getTime();
12597 scope = newScope || scope;
12598 args = newArgs || args;
12600 id = setInterval(call, d);
12605 * Cancel the last queued timeout
12607 this.cancel = function(){
12615 * Ext JS Library 1.1.1
12616 * Copyright(c) 2006-2007, Ext JS, LLC.
12618 * Originally Released Under LGPL - original licence link has changed is not relivant.
12621 * <script type="text/javascript">
12625 Roo.util.TaskRunner = function(interval){
12626 interval = interval || 10;
12627 var tasks = [], removeQueue = [];
12629 var running = false;
12631 var stopThread = function(){
12637 var startThread = function(){
12640 id = setInterval(runTasks, interval);
12644 var removeTask = function(task){
12645 removeQueue.push(task);
12651 var runTasks = function(){
12652 if(removeQueue.length > 0){
12653 for(var i = 0, len = removeQueue.length; i < len; i++){
12654 tasks.remove(removeQueue[i]);
12657 if(tasks.length < 1){
12662 var now = new Date().getTime();
12663 for(var i = 0, len = tasks.length; i < len; ++i){
12665 var itime = now - t.taskRunTime;
12666 if(t.interval <= itime){
12667 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12668 t.taskRunTime = now;
12669 if(rt === false || t.taskRunCount === t.repeat){
12674 if(t.duration && t.duration <= (now - t.taskStartTime)){
12681 * Queues a new task.
12682 * @param {Object} task
12684 this.start = function(task){
12686 task.taskStartTime = new Date().getTime();
12687 task.taskRunTime = 0;
12688 task.taskRunCount = 0;
12693 this.stop = function(task){
12698 this.stopAll = function(){
12700 for(var i = 0, len = tasks.length; i < len; i++){
12701 if(tasks[i].onStop){
12710 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12712 * Ext JS Library 1.1.1
12713 * Copyright(c) 2006-2007, Ext JS, LLC.
12715 * Originally Released Under LGPL - original licence link has changed is not relivant.
12718 * <script type="text/javascript">
12723 * @class Roo.util.MixedCollection
12724 * @extends Roo.util.Observable
12725 * A Collection class that maintains both numeric indexes and keys and exposes events.
12727 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12728 * collection (defaults to false)
12729 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12730 * and return the key value for that item. This is used when available to look up the key on items that
12731 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12732 * equivalent to providing an implementation for the {@link #getKey} method.
12734 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12742 * Fires when the collection is cleared.
12747 * Fires when an item is added to the collection.
12748 * @param {Number} index The index at which the item was added.
12749 * @param {Object} o The item added.
12750 * @param {String} key The key associated with the added item.
12755 * Fires when an item is replaced in the collection.
12756 * @param {String} key he key associated with the new added.
12757 * @param {Object} old The item being replaced.
12758 * @param {Object} new The new item.
12763 * Fires when an item is removed from the collection.
12764 * @param {Object} o The item being removed.
12765 * @param {String} key (optional) The key associated with the removed item.
12770 this.allowFunctions = allowFunctions === true;
12772 this.getKey = keyFn;
12774 Roo.util.MixedCollection.superclass.constructor.call(this);
12777 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12778 allowFunctions : false,
12781 * Adds an item to the collection.
12782 * @param {String} key The key to associate with the item
12783 * @param {Object} o The item to add.
12784 * @return {Object} The item added.
12786 add : function(key, o){
12787 if(arguments.length == 1){
12789 key = this.getKey(o);
12791 if(typeof key == "undefined" || key === null){
12793 this.items.push(o);
12794 this.keys.push(null);
12796 var old = this.map[key];
12798 return this.replace(key, o);
12801 this.items.push(o);
12803 this.keys.push(key);
12805 this.fireEvent("add", this.length-1, o, key);
12810 * MixedCollection has a generic way to fetch keys if you implement getKey.
12813 var mc = new Roo.util.MixedCollection();
12814 mc.add(someEl.dom.id, someEl);
12815 mc.add(otherEl.dom.id, otherEl);
12819 var mc = new Roo.util.MixedCollection();
12820 mc.getKey = function(el){
12826 // or via the constructor
12827 var mc = new Roo.util.MixedCollection(false, function(el){
12833 * @param o {Object} The item for which to find the key.
12834 * @return {Object} The key for the passed item.
12836 getKey : function(o){
12841 * Replaces an item in the collection.
12842 * @param {String} key The key associated with the item to replace, or the item to replace.
12843 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12844 * @return {Object} The new item.
12846 replace : function(key, o){
12847 if(arguments.length == 1){
12849 key = this.getKey(o);
12851 var old = this.item(key);
12852 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12853 return this.add(key, o);
12855 var index = this.indexOfKey(key);
12856 this.items[index] = o;
12858 this.fireEvent("replace", key, old, o);
12863 * Adds all elements of an Array or an Object to the collection.
12864 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12865 * an Array of values, each of which are added to the collection.
12867 addAll : function(objs){
12868 if(arguments.length > 1 || objs instanceof Array){
12869 var args = arguments.length > 1 ? arguments : objs;
12870 for(var i = 0, len = args.length; i < len; i++){
12874 for(var key in objs){
12875 if(this.allowFunctions || typeof objs[key] != "function"){
12876 this.add(key, objs[key]);
12883 * Executes the specified function once for every item in the collection, passing each
12884 * item as the first and only parameter. returning false from the function will stop the iteration.
12885 * @param {Function} fn The function to execute for each item.
12886 * @param {Object} scope (optional) The scope in which to execute the function.
12888 each : function(fn, scope){
12889 var items = [].concat(this.items); // each safe for removal
12890 for(var i = 0, len = items.length; i < len; i++){
12891 if(fn.call(scope || items[i], items[i], i, len) === false){
12898 * Executes the specified function once for every key in the collection, passing each
12899 * key, and its associated item as the first two parameters.
12900 * @param {Function} fn The function to execute for each item.
12901 * @param {Object} scope (optional) The scope in which to execute the function.
12903 eachKey : function(fn, scope){
12904 for(var i = 0, len = this.keys.length; i < len; i++){
12905 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12910 * Returns the first item in the collection which elicits a true return value from the
12911 * passed selection function.
12912 * @param {Function} fn The selection function to execute for each item.
12913 * @param {Object} scope (optional) The scope in which to execute the function.
12914 * @return {Object} The first item in the collection which returned true from the selection function.
12916 find : function(fn, scope){
12917 for(var i = 0, len = this.items.length; i < len; i++){
12918 if(fn.call(scope || window, this.items[i], this.keys[i])){
12919 return this.items[i];
12926 * Inserts an item at the specified index in the collection.
12927 * @param {Number} index The index to insert the item at.
12928 * @param {String} key The key to associate with the new item, or the item itself.
12929 * @param {Object} o (optional) If the second parameter was a key, the new item.
12930 * @return {Object} The item inserted.
12932 insert : function(index, key, o){
12933 if(arguments.length == 2){
12935 key = this.getKey(o);
12937 if(index >= this.length){
12938 return this.add(key, o);
12941 this.items.splice(index, 0, o);
12942 if(typeof key != "undefined" && key != null){
12945 this.keys.splice(index, 0, key);
12946 this.fireEvent("add", index, o, key);
12951 * Removed an item from the collection.
12952 * @param {Object} o The item to remove.
12953 * @return {Object} The item removed.
12955 remove : function(o){
12956 return this.removeAt(this.indexOf(o));
12960 * Remove an item from a specified index in the collection.
12961 * @param {Number} index The index within the collection of the item to remove.
12963 removeAt : function(index){
12964 if(index < this.length && index >= 0){
12966 var o = this.items[index];
12967 this.items.splice(index, 1);
12968 var key = this.keys[index];
12969 if(typeof key != "undefined"){
12970 delete this.map[key];
12972 this.keys.splice(index, 1);
12973 this.fireEvent("remove", o, key);
12978 * Removed an item associated with the passed key fom the collection.
12979 * @param {String} key The key of the item to remove.
12981 removeKey : function(key){
12982 return this.removeAt(this.indexOfKey(key));
12986 * Returns the number of items in the collection.
12987 * @return {Number} the number of items in the collection.
12989 getCount : function(){
12990 return this.length;
12994 * Returns index within the collection of the passed Object.
12995 * @param {Object} o The item to find the index of.
12996 * @return {Number} index of the item.
12998 indexOf : function(o){
12999 if(!this.items.indexOf){
13000 for(var i = 0, len = this.items.length; i < len; i++){
13001 if(this.items[i] == o) return i;
13005 return this.items.indexOf(o);
13010 * Returns index within the collection of the passed key.
13011 * @param {String} key The key to find the index of.
13012 * @return {Number} index of the key.
13014 indexOfKey : function(key){
13015 if(!this.keys.indexOf){
13016 for(var i = 0, len = this.keys.length; i < len; i++){
13017 if(this.keys[i] == key) return i;
13021 return this.keys.indexOf(key);
13026 * Returns the item associated with the passed key OR index. Key has priority over index.
13027 * @param {String/Number} key The key or index of the item.
13028 * @return {Object} The item associated with the passed key.
13030 item : function(key){
13031 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13032 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13036 * Returns the item at the specified index.
13037 * @param {Number} index The index of the item.
13040 itemAt : function(index){
13041 return this.items[index];
13045 * Returns the item associated with the passed key.
13046 * @param {String/Number} key The key of the item.
13047 * @return {Object} The item associated with the passed key.
13049 key : function(key){
13050 return this.map[key];
13054 * Returns true if the collection contains the passed Object as an item.
13055 * @param {Object} o The Object to look for in the collection.
13056 * @return {Boolean} True if the collection contains the Object as an item.
13058 contains : function(o){
13059 return this.indexOf(o) != -1;
13063 * Returns true if the collection contains the passed Object as a key.
13064 * @param {String} key The key to look for in the collection.
13065 * @return {Boolean} True if the collection contains the Object as a key.
13067 containsKey : function(key){
13068 return typeof this.map[key] != "undefined";
13072 * Removes all items from the collection.
13074 clear : function(){
13079 this.fireEvent("clear");
13083 * Returns the first item in the collection.
13084 * @return {Object} the first item in the collection..
13086 first : function(){
13087 return this.items[0];
13091 * Returns the last item in the collection.
13092 * @return {Object} the last item in the collection..
13095 return this.items[this.length-1];
13098 _sort : function(property, dir, fn){
13099 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13100 fn = fn || function(a, b){
13103 var c = [], k = this.keys, items = this.items;
13104 for(var i = 0, len = items.length; i < len; i++){
13105 c[c.length] = {key: k[i], value: items[i], index: i};
13107 c.sort(function(a, b){
13108 var v = fn(a[property], b[property]) * dsc;
13110 v = (a.index < b.index ? -1 : 1);
13114 for(var i = 0, len = c.length; i < len; i++){
13115 items[i] = c[i].value;
13118 this.fireEvent("sort", this);
13122 * Sorts this collection with the passed comparison function
13123 * @param {String} direction (optional) "ASC" or "DESC"
13124 * @param {Function} fn (optional) comparison function
13126 sort : function(dir, fn){
13127 this._sort("value", dir, fn);
13131 * Sorts this collection by keys
13132 * @param {String} direction (optional) "ASC" or "DESC"
13133 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13135 keySort : function(dir, fn){
13136 this._sort("key", dir, fn || function(a, b){
13137 return String(a).toUpperCase()-String(b).toUpperCase();
13142 * Returns a range of items in this collection
13143 * @param {Number} startIndex (optional) defaults to 0
13144 * @param {Number} endIndex (optional) default to the last item
13145 * @return {Array} An array of items
13147 getRange : function(start, end){
13148 var items = this.items;
13149 if(items.length < 1){
13152 start = start || 0;
13153 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13156 for(var i = start; i <= end; i++) {
13157 r[r.length] = items[i];
13160 for(var i = start; i >= end; i--) {
13161 r[r.length] = items[i];
13168 * Filter the <i>objects</i> in this collection by a specific property.
13169 * Returns a new collection that has been filtered.
13170 * @param {String} property A property on your objects
13171 * @param {String/RegExp} value Either string that the property values
13172 * should start with or a RegExp to test against the property
13173 * @return {MixedCollection} The new filtered collection
13175 filter : function(property, value){
13176 if(!value.exec){ // not a regex
13177 value = String(value);
13178 if(value.length == 0){
13179 return this.clone();
13181 value = new RegExp("^" + Roo.escapeRe(value), "i");
13183 return this.filterBy(function(o){
13184 return o && value.test(o[property]);
13189 * Filter by a function. * Returns a new collection that has been filtered.
13190 * The passed function will be called with each
13191 * object in the collection. If the function returns true, the value is included
13192 * otherwise it is filtered.
13193 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13194 * @param {Object} scope (optional) The scope of the function (defaults to this)
13195 * @return {MixedCollection} The new filtered collection
13197 filterBy : function(fn, scope){
13198 var r = new Roo.util.MixedCollection();
13199 r.getKey = this.getKey;
13200 var k = this.keys, it = this.items;
13201 for(var i = 0, len = it.length; i < len; i++){
13202 if(fn.call(scope||this, it[i], k[i])){
13203 r.add(k[i], it[i]);
13210 * Creates a duplicate of this collection
13211 * @return {MixedCollection}
13213 clone : function(){
13214 var r = new Roo.util.MixedCollection();
13215 var k = this.keys, it = this.items;
13216 for(var i = 0, len = it.length; i < len; i++){
13217 r.add(k[i], it[i]);
13219 r.getKey = this.getKey;
13224 * Returns the item associated with the passed key or index.
13226 * @param {String/Number} key The key or index of the item.
13227 * @return {Object} The item associated with the passed key.
13229 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13231 * Ext JS Library 1.1.1
13232 * Copyright(c) 2006-2007, Ext JS, LLC.
13234 * Originally Released Under LGPL - original licence link has changed is not relivant.
13237 * <script type="text/javascript">
13240 * @class Roo.util.JSON
13241 * Modified version of Douglas Crockford"s json.js that doesn"t
13242 * mess with the Object prototype
13243 * http://www.json.org/js.html
13246 Roo.util.JSON = new (function(){
13247 var useHasOwn = {}.hasOwnProperty ? true : false;
13249 // crashes Safari in some instances
13250 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13252 var pad = function(n) {
13253 return n < 10 ? "0" + n : n;
13266 var encodeString = function(s){
13267 if (/["\\\x00-\x1f]/.test(s)) {
13268 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13273 c = b.charCodeAt();
13275 Math.floor(c / 16).toString(16) +
13276 (c % 16).toString(16);
13279 return '"' + s + '"';
13282 var encodeArray = function(o){
13283 var a = ["["], b, i, l = o.length, v;
13284 for (i = 0; i < l; i += 1) {
13286 switch (typeof v) {
13295 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13303 var encodeDate = function(o){
13304 return '"' + o.getFullYear() + "-" +
13305 pad(o.getMonth() + 1) + "-" +
13306 pad(o.getDate()) + "T" +
13307 pad(o.getHours()) + ":" +
13308 pad(o.getMinutes()) + ":" +
13309 pad(o.getSeconds()) + '"';
13313 * Encodes an Object, Array or other value
13314 * @param {Mixed} o The variable to encode
13315 * @return {String} The JSON string
13317 this.encode = function(o)
13319 // should this be extended to fully wrap stringify..
13321 if(typeof o == "undefined" || o === null){
13323 }else if(o instanceof Array){
13324 return encodeArray(o);
13325 }else if(o instanceof Date){
13326 return encodeDate(o);
13327 }else if(typeof o == "string"){
13328 return encodeString(o);
13329 }else if(typeof o == "number"){
13330 return isFinite(o) ? String(o) : "null";
13331 }else if(typeof o == "boolean"){
13334 var a = ["{"], b, i, v;
13336 if(!useHasOwn || o.hasOwnProperty(i)) {
13338 switch (typeof v) {
13347 a.push(this.encode(i), ":",
13348 v === null ? "null" : this.encode(v));
13359 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13360 * @param {String} json The JSON string
13361 * @return {Object} The resulting object
13363 this.decode = function(json){
13365 return /** eval:var:json */ eval("(" + json + ')');
13369 * Shorthand for {@link Roo.util.JSON#encode}
13370 * @member Roo encode
13372 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13374 * Shorthand for {@link Roo.util.JSON#decode}
13375 * @member Roo decode
13377 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13380 * Ext JS Library 1.1.1
13381 * Copyright(c) 2006-2007, Ext JS, LLC.
13383 * Originally Released Under LGPL - original licence link has changed is not relivant.
13386 * <script type="text/javascript">
13390 * @class Roo.util.Format
13391 * Reusable data formatting functions
13394 Roo.util.Format = function(){
13395 var trimRe = /^\s+|\s+$/g;
13398 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13399 * @param {String} value The string to truncate
13400 * @param {Number} length The maximum length to allow before truncating
13401 * @return {String} The converted text
13403 ellipsis : function(value, len){
13404 if(value && value.length > len){
13405 return value.substr(0, len-3)+"...";
13411 * Checks a reference and converts it to empty string if it is undefined
13412 * @param {Mixed} value Reference to check
13413 * @return {Mixed} Empty string if converted, otherwise the original value
13415 undef : function(value){
13416 return typeof value != "undefined" ? value : "";
13420 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13421 * @param {String} value The string to encode
13422 * @return {String} The encoded text
13424 htmlEncode : function(value){
13425 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13429 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13430 * @param {String} value The string to decode
13431 * @return {String} The decoded text
13433 htmlDecode : function(value){
13434 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13438 * Trims any whitespace from either side of a string
13439 * @param {String} value The text to trim
13440 * @return {String} The trimmed text
13442 trim : function(value){
13443 return String(value).replace(trimRe, "");
13447 * Returns a substring from within an original string
13448 * @param {String} value The original text
13449 * @param {Number} start The start index of the substring
13450 * @param {Number} length The length of the substring
13451 * @return {String} The substring
13453 substr : function(value, start, length){
13454 return String(value).substr(start, length);
13458 * Converts a string to all lower case letters
13459 * @param {String} value The text to convert
13460 * @return {String} The converted text
13462 lowercase : function(value){
13463 return String(value).toLowerCase();
13467 * Converts a string to all upper case letters
13468 * @param {String} value The text to convert
13469 * @return {String} The converted text
13471 uppercase : function(value){
13472 return String(value).toUpperCase();
13476 * Converts the first character only of a string to upper case
13477 * @param {String} value The text to convert
13478 * @return {String} The converted text
13480 capitalize : function(value){
13481 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13485 call : function(value, fn){
13486 if(arguments.length > 2){
13487 var args = Array.prototype.slice.call(arguments, 2);
13488 args.unshift(value);
13490 return /** eval:var:value */ eval(fn).apply(window, args);
13492 /** eval:var:value */
13493 return /** eval:var:value */ eval(fn).call(window, value);
13499 * safer version of Math.toFixed..??/
13500 * @param {Number/String} value The numeric value to format
13501 * @param {Number/String} value Decimal places
13502 * @return {String} The formatted currency string
13504 toFixed : function(v, n)
13506 // why not use to fixed - precision is buggered???
13508 return Math.round(v-0);
13510 var fact = Math.pow(10,n+1);
13511 v = (Math.round((v-0)*fact))/fact;
13512 var z = (''+fact).substring(2);
13513 if (v == Math.floor(v)) {
13514 return Math.floor(v) + '.' + z;
13517 // now just padd decimals..
13518 var ps = String(v).split('.');
13519 var fd = (ps[1] + z);
13520 var r = fd.substring(0,n);
13521 var rm = fd.substring(n);
13523 return ps[0] + '.' + r;
13525 r*=1; // turn it into a number;
13527 if (String(r).length != n) {
13530 r = String(r).substring(1); // chop the end off.
13533 return ps[0] + '.' + r;
13538 * Format a number as US currency
13539 * @param {Number/String} value The numeric value to format
13540 * @return {String} The formatted currency string
13542 usMoney : function(v){
13543 return '$' + Roo.util.Format.number(v);
13548 * eventually this should probably emulate php's number_format
13549 * @param {Number/String} value The numeric value to format
13550 * @param {Number} decimals number of decimal places
13551 * @return {String} The formatted currency string
13553 number : function(v,decimals)
13555 // multiply and round.
13556 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13557 var mul = Math.pow(10, decimals);
13558 var zero = String(mul).substring(1);
13559 v = (Math.round((v-0)*mul))/mul;
13561 // if it's '0' number.. then
13563 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13565 var ps = v.split('.');
13569 var r = /(\d+)(\d{3})/;
13571 while (r.test(whole)) {
13572 whole = whole.replace(r, '$1' + ',' + '$2');
13578 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13579 // does not have decimals
13580 (decimals ? ('.' + zero) : '');
13583 return whole + sub ;
13587 * Parse a value into a formatted date using the specified format pattern.
13588 * @param {Mixed} value The value to format
13589 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13590 * @return {String} The formatted date string
13592 date : function(v, format){
13596 if(!(v instanceof Date)){
13597 v = new Date(Date.parse(v));
13599 return v.dateFormat(format || "m/d/Y");
13603 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13604 * @param {String} format Any valid date format string
13605 * @return {Function} The date formatting function
13607 dateRenderer : function(format){
13608 return function(v){
13609 return Roo.util.Format.date(v, format);
13614 stripTagsRE : /<\/?[^>]+>/gi,
13617 * Strips all HTML tags
13618 * @param {Mixed} value The text from which to strip tags
13619 * @return {String} The stripped text
13621 stripTags : function(v){
13622 return !v ? v : String(v).replace(this.stripTagsRE, "");
13627 * Ext JS Library 1.1.1
13628 * Copyright(c) 2006-2007, Ext JS, LLC.
13630 * Originally Released Under LGPL - original licence link has changed is not relivant.
13633 * <script type="text/javascript">
13640 * @class Roo.MasterTemplate
13641 * @extends Roo.Template
13642 * Provides a template that can have child templates. The syntax is:
13644 var t = new Roo.MasterTemplate(
13645 '<select name="{name}">',
13646 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13649 t.add('options', {value: 'foo', text: 'bar'});
13650 // or you can add multiple child elements in one shot
13651 t.addAll('options', [
13652 {value: 'foo', text: 'bar'},
13653 {value: 'foo2', text: 'bar2'},
13654 {value: 'foo3', text: 'bar3'}
13656 // then append, applying the master template values
13657 t.append('my-form', {name: 'my-select'});
13659 * A name attribute for the child template is not required if you have only one child
13660 * template or you want to refer to them by index.
13662 Roo.MasterTemplate = function(){
13663 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13664 this.originalHtml = this.html;
13666 var m, re = this.subTemplateRe;
13669 while(m = re.exec(this.html)){
13670 var name = m[1], content = m[2];
13675 tpl : new Roo.Template(content)
13678 st[name] = st[subIndex];
13680 st[subIndex].tpl.compile();
13681 st[subIndex].tpl.call = this.call.createDelegate(this);
13684 this.subCount = subIndex;
13687 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13689 * The regular expression used to match sub templates
13693 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13696 * Applies the passed values to a child template.
13697 * @param {String/Number} name (optional) The name or index of the child template
13698 * @param {Array/Object} values The values to be applied to the template
13699 * @return {MasterTemplate} this
13701 add : function(name, values){
13702 if(arguments.length == 1){
13703 values = arguments[0];
13706 var s = this.subs[name];
13707 s.buffer[s.buffer.length] = s.tpl.apply(values);
13712 * Applies all the passed values to a child template.
13713 * @param {String/Number} name (optional) The name or index of the child template
13714 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13715 * @param {Boolean} reset (optional) True to reset the template first
13716 * @return {MasterTemplate} this
13718 fill : function(name, values, reset){
13720 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13728 for(var i = 0, len = values.length; i < len; i++){
13729 this.add(name, values[i]);
13735 * Resets the template for reuse
13736 * @return {MasterTemplate} this
13738 reset : function(){
13740 for(var i = 0; i < this.subCount; i++){
13746 applyTemplate : function(values){
13748 var replaceIndex = -1;
13749 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13750 return s[++replaceIndex].buffer.join("");
13752 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13755 apply : function(){
13756 return this.applyTemplate.apply(this, arguments);
13759 compile : function(){return this;}
13763 * Alias for fill().
13766 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13768 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13769 * var tpl = Roo.MasterTemplate.from('element-id');
13770 * @param {String/HTMLElement} el
13771 * @param {Object} config
13774 Roo.MasterTemplate.from = function(el, config){
13775 el = Roo.getDom(el);
13776 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13779 * Ext JS Library 1.1.1
13780 * Copyright(c) 2006-2007, Ext JS, LLC.
13782 * Originally Released Under LGPL - original licence link has changed is not relivant.
13785 * <script type="text/javascript">
13790 * @class Roo.util.CSS
13791 * Utility class for manipulating CSS rules
13794 Roo.util.CSS = function(){
13796 var doc = document;
13798 var camelRe = /(-[a-z])/gi;
13799 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13803 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13804 * tag and appended to the HEAD of the document.
13805 * @param {String|Object} cssText The text containing the css rules
13806 * @param {String} id An id to add to the stylesheet for later removal
13807 * @return {StyleSheet}
13809 createStyleSheet : function(cssText, id){
13811 var head = doc.getElementsByTagName("head")[0];
13812 var nrules = doc.createElement("style");
13813 nrules.setAttribute("type", "text/css");
13815 nrules.setAttribute("id", id);
13817 if (typeof(cssText) != 'string') {
13818 // support object maps..
13819 // not sure if this a good idea..
13820 // perhaps it should be merged with the general css handling
13821 // and handle js style props.
13822 var cssTextNew = [];
13823 for(var n in cssText) {
13825 for(var k in cssText[n]) {
13826 citems.push( k + ' : ' +cssText[n][k] + ';' );
13828 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13831 cssText = cssTextNew.join("\n");
13837 head.appendChild(nrules);
13838 ss = nrules.styleSheet;
13839 ss.cssText = cssText;
13842 nrules.appendChild(doc.createTextNode(cssText));
13844 nrules.cssText = cssText;
13846 head.appendChild(nrules);
13847 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13849 this.cacheStyleSheet(ss);
13854 * Removes a style or link tag by id
13855 * @param {String} id The id of the tag
13857 removeStyleSheet : function(id){
13858 var existing = doc.getElementById(id);
13860 existing.parentNode.removeChild(existing);
13865 * Dynamically swaps an existing stylesheet reference for a new one
13866 * @param {String} id The id of an existing link tag to remove
13867 * @param {String} url The href of the new stylesheet to include
13869 swapStyleSheet : function(id, url){
13870 this.removeStyleSheet(id);
13871 var ss = doc.createElement("link");
13872 ss.setAttribute("rel", "stylesheet");
13873 ss.setAttribute("type", "text/css");
13874 ss.setAttribute("id", id);
13875 ss.setAttribute("href", url);
13876 doc.getElementsByTagName("head")[0].appendChild(ss);
13880 * Refresh the rule cache if you have dynamically added stylesheets
13881 * @return {Object} An object (hash) of rules indexed by selector
13883 refreshCache : function(){
13884 return this.getRules(true);
13888 cacheStyleSheet : function(stylesheet){
13892 try{// try catch for cross domain access issue
13893 var ssRules = stylesheet.cssRules || stylesheet.rules;
13894 for(var j = ssRules.length-1; j >= 0; --j){
13895 rules[ssRules[j].selectorText] = ssRules[j];
13901 * Gets all css rules for the document
13902 * @param {Boolean} refreshCache true to refresh the internal cache
13903 * @return {Object} An object (hash) of rules indexed by selector
13905 getRules : function(refreshCache){
13906 if(rules == null || refreshCache){
13908 var ds = doc.styleSheets;
13909 for(var i =0, len = ds.length; i < len; i++){
13911 this.cacheStyleSheet(ds[i]);
13919 * Gets an an individual CSS rule by selector(s)
13920 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13921 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13922 * @return {CSSRule} The CSS rule or null if one is not found
13924 getRule : function(selector, refreshCache){
13925 var rs = this.getRules(refreshCache);
13926 if(!(selector instanceof Array)){
13927 return rs[selector];
13929 for(var i = 0; i < selector.length; i++){
13930 if(rs[selector[i]]){
13931 return rs[selector[i]];
13939 * Updates a rule property
13940 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13941 * @param {String} property The css property
13942 * @param {String} value The new value for the property
13943 * @return {Boolean} true If a rule was found and updated
13945 updateRule : function(selector, property, value){
13946 if(!(selector instanceof Array)){
13947 var rule = this.getRule(selector);
13949 rule.style[property.replace(camelRe, camelFn)] = value;
13953 for(var i = 0; i < selector.length; i++){
13954 if(this.updateRule(selector[i], property, value)){
13964 * Ext JS Library 1.1.1
13965 * Copyright(c) 2006-2007, Ext JS, LLC.
13967 * Originally Released Under LGPL - original licence link has changed is not relivant.
13970 * <script type="text/javascript">
13976 * @class Roo.util.ClickRepeater
13977 * @extends Roo.util.Observable
13979 * A wrapper class which can be applied to any element. Fires a "click" event while the
13980 * mouse is pressed. The interval between firings may be specified in the config but
13981 * defaults to 10 milliseconds.
13983 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13985 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13986 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13987 * Similar to an autorepeat key delay.
13988 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13989 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13990 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13991 * "interval" and "delay" are ignored. "immediate" is honored.
13992 * @cfg {Boolean} preventDefault True to prevent the default click event
13993 * @cfg {Boolean} stopDefault True to stop the default click event
13996 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13997 * 2007-02-02 jvs Renamed to ClickRepeater
13998 * 2007-02-03 jvs Modifications for FF Mac and Safari
14001 * @param {String/HTMLElement/Element} el The element to listen on
14002 * @param {Object} config
14004 Roo.util.ClickRepeater = function(el, config)
14006 this.el = Roo.get(el);
14007 this.el.unselectable();
14009 Roo.apply(this, config);
14014 * Fires when the mouse button is depressed.
14015 * @param {Roo.util.ClickRepeater} this
14017 "mousedown" : true,
14020 * Fires on a specified interval during the time the element is pressed.
14021 * @param {Roo.util.ClickRepeater} this
14026 * Fires when the mouse key is released.
14027 * @param {Roo.util.ClickRepeater} this
14032 this.el.on("mousedown", this.handleMouseDown, this);
14033 if(this.preventDefault || this.stopDefault){
14034 this.el.on("click", function(e){
14035 if(this.preventDefault){
14036 e.preventDefault();
14038 if(this.stopDefault){
14044 // allow inline handler
14046 this.on("click", this.handler, this.scope || this);
14049 Roo.util.ClickRepeater.superclass.constructor.call(this);
14052 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14055 preventDefault : true,
14056 stopDefault : false,
14060 handleMouseDown : function(){
14061 clearTimeout(this.timer);
14063 if(this.pressClass){
14064 this.el.addClass(this.pressClass);
14066 this.mousedownTime = new Date();
14068 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14069 this.el.on("mouseout", this.handleMouseOut, this);
14071 this.fireEvent("mousedown", this);
14072 this.fireEvent("click", this);
14074 this.timer = this.click.defer(this.delay || this.interval, this);
14078 click : function(){
14079 this.fireEvent("click", this);
14080 this.timer = this.click.defer(this.getInterval(), this);
14084 getInterval: function(){
14085 if(!this.accelerate){
14086 return this.interval;
14088 var pressTime = this.mousedownTime.getElapsed();
14089 if(pressTime < 500){
14091 }else if(pressTime < 1700){
14093 }else if(pressTime < 2600){
14095 }else if(pressTime < 3500){
14097 }else if(pressTime < 4400){
14099 }else if(pressTime < 5300){
14101 }else if(pressTime < 6200){
14109 handleMouseOut : function(){
14110 clearTimeout(this.timer);
14111 if(this.pressClass){
14112 this.el.removeClass(this.pressClass);
14114 this.el.on("mouseover", this.handleMouseReturn, this);
14118 handleMouseReturn : function(){
14119 this.el.un("mouseover", this.handleMouseReturn);
14120 if(this.pressClass){
14121 this.el.addClass(this.pressClass);
14127 handleMouseUp : function(){
14128 clearTimeout(this.timer);
14129 this.el.un("mouseover", this.handleMouseReturn);
14130 this.el.un("mouseout", this.handleMouseOut);
14131 Roo.get(document).un("mouseup", this.handleMouseUp);
14132 this.el.removeClass(this.pressClass);
14133 this.fireEvent("mouseup", this);
14137 * Ext JS Library 1.1.1
14138 * Copyright(c) 2006-2007, Ext JS, LLC.
14140 * Originally Released Under LGPL - original licence link has changed is not relivant.
14143 * <script type="text/javascript">
14148 * @class Roo.KeyNav
14149 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14150 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14151 * way to implement custom navigation schemes for any UI component.</p>
14152 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14153 * pageUp, pageDown, del, home, end. Usage:</p>
14155 var nav = new Roo.KeyNav("my-element", {
14156 "left" : function(e){
14157 this.moveLeft(e.ctrlKey);
14159 "right" : function(e){
14160 this.moveRight(e.ctrlKey);
14162 "enter" : function(e){
14169 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14170 * @param {Object} config The config
14172 Roo.KeyNav = function(el, config){
14173 this.el = Roo.get(el);
14174 Roo.apply(this, config);
14175 if(!this.disabled){
14176 this.disabled = true;
14181 Roo.KeyNav.prototype = {
14183 * @cfg {Boolean} disabled
14184 * True to disable this KeyNav instance (defaults to false)
14188 * @cfg {String} defaultEventAction
14189 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14190 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14191 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14193 defaultEventAction: "stopEvent",
14195 * @cfg {Boolean} forceKeyDown
14196 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14197 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14198 * handle keydown instead of keypress.
14200 forceKeyDown : false,
14203 prepareEvent : function(e){
14204 var k = e.getKey();
14205 var h = this.keyToHandler[k];
14206 //if(h && this[h]){
14207 // e.stopPropagation();
14209 if(Roo.isSafari && h && k >= 37 && k <= 40){
14215 relay : function(e){
14216 var k = e.getKey();
14217 var h = this.keyToHandler[k];
14219 if(this.doRelay(e, this[h], h) !== true){
14220 e[this.defaultEventAction]();
14226 doRelay : function(e, h, hname){
14227 return h.call(this.scope || this, e);
14230 // possible handlers
14244 // quick lookup hash
14261 * Enable this KeyNav
14263 enable: function(){
14265 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14266 // the EventObject will normalize Safari automatically
14267 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14268 this.el.on("keydown", this.relay, this);
14270 this.el.on("keydown", this.prepareEvent, this);
14271 this.el.on("keypress", this.relay, this);
14273 this.disabled = false;
14278 * Disable this KeyNav
14280 disable: function(){
14281 if(!this.disabled){
14282 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14283 this.el.un("keydown", this.relay);
14285 this.el.un("keydown", this.prepareEvent);
14286 this.el.un("keypress", this.relay);
14288 this.disabled = true;
14293 * Ext JS Library 1.1.1
14294 * Copyright(c) 2006-2007, Ext JS, LLC.
14296 * Originally Released Under LGPL - original licence link has changed is not relivant.
14299 * <script type="text/javascript">
14304 * @class Roo.KeyMap
14305 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14306 * The constructor accepts the same config object as defined by {@link #addBinding}.
14307 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14308 * combination it will call the function with this signature (if the match is a multi-key
14309 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14310 * A KeyMap can also handle a string representation of keys.<br />
14313 // map one key by key code
14314 var map = new Roo.KeyMap("my-element", {
14315 key: 13, // or Roo.EventObject.ENTER
14320 // map multiple keys to one action by string
14321 var map = new Roo.KeyMap("my-element", {
14327 // map multiple keys to multiple actions by strings and array of codes
14328 var map = new Roo.KeyMap("my-element", [
14331 fn: function(){ alert("Return was pressed"); }
14334 fn: function(){ alert('a, b or c was pressed'); }
14339 fn: function(){ alert('Control + shift + tab was pressed.'); }
14343 * <b>Note: A KeyMap starts enabled</b>
14345 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14346 * @param {Object} config The config (see {@link #addBinding})
14347 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14349 Roo.KeyMap = function(el, config, eventName){
14350 this.el = Roo.get(el);
14351 this.eventName = eventName || "keydown";
14352 this.bindings = [];
14354 this.addBinding(config);
14359 Roo.KeyMap.prototype = {
14361 * True to stop the event from bubbling and prevent the default browser action if the
14362 * key was handled by the KeyMap (defaults to false)
14368 * Add a new binding to this KeyMap. The following config object properties are supported:
14370 Property Type Description
14371 ---------- --------------- ----------------------------------------------------------------------
14372 key String/Array A single keycode or an array of keycodes to handle
14373 shift Boolean True to handle key only when shift is pressed (defaults to false)
14374 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14375 alt Boolean True to handle key only when alt is pressed (defaults to false)
14376 fn Function The function to call when KeyMap finds the expected key combination
14377 scope Object The scope of the callback function
14383 var map = new Roo.KeyMap(document, {
14384 key: Roo.EventObject.ENTER,
14389 //Add a new binding to the existing KeyMap later
14397 * @param {Object/Array} config A single KeyMap config or an array of configs
14399 addBinding : function(config){
14400 if(config instanceof Array){
14401 for(var i = 0, len = config.length; i < len; i++){
14402 this.addBinding(config[i]);
14406 var keyCode = config.key,
14407 shift = config.shift,
14408 ctrl = config.ctrl,
14411 scope = config.scope;
14412 if(typeof keyCode == "string"){
14414 var keyString = keyCode.toUpperCase();
14415 for(var j = 0, len = keyString.length; j < len; j++){
14416 ks.push(keyString.charCodeAt(j));
14420 var keyArray = keyCode instanceof Array;
14421 var handler = function(e){
14422 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14423 var k = e.getKey();
14425 for(var i = 0, len = keyCode.length; i < len; i++){
14426 if(keyCode[i] == k){
14427 if(this.stopEvent){
14430 fn.call(scope || window, k, e);
14436 if(this.stopEvent){
14439 fn.call(scope || window, k, e);
14444 this.bindings.push(handler);
14448 * Shorthand for adding a single key listener
14449 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14450 * following options:
14451 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14452 * @param {Function} fn The function to call
14453 * @param {Object} scope (optional) The scope of the function
14455 on : function(key, fn, scope){
14456 var keyCode, shift, ctrl, alt;
14457 if(typeof key == "object" && !(key instanceof Array)){
14476 handleKeyDown : function(e){
14477 if(this.enabled){ //just in case
14478 var b = this.bindings;
14479 for(var i = 0, len = b.length; i < len; i++){
14480 b[i].call(this, e);
14486 * Returns true if this KeyMap is enabled
14487 * @return {Boolean}
14489 isEnabled : function(){
14490 return this.enabled;
14494 * Enables this KeyMap
14496 enable: function(){
14498 this.el.on(this.eventName, this.handleKeyDown, this);
14499 this.enabled = true;
14504 * Disable this KeyMap
14506 disable: function(){
14508 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14509 this.enabled = false;
14514 * Ext JS Library 1.1.1
14515 * Copyright(c) 2006-2007, Ext JS, LLC.
14517 * Originally Released Under LGPL - original licence link has changed is not relivant.
14520 * <script type="text/javascript">
14525 * @class Roo.util.TextMetrics
14526 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14527 * wide, in pixels, a given block of text will be.
14530 Roo.util.TextMetrics = function(){
14534 * Measures the size of the specified text
14535 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14536 * that can affect the size of the rendered text
14537 * @param {String} text The text to measure
14538 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14539 * in order to accurately measure the text height
14540 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14542 measure : function(el, text, fixedWidth){
14544 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14547 shared.setFixedWidth(fixedWidth || 'auto');
14548 return shared.getSize(text);
14552 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14553 * the overhead of multiple calls to initialize the style properties on each measurement.
14554 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14555 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14556 * in order to accurately measure the text height
14557 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14559 createInstance : function(el, fixedWidth){
14560 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14567 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14568 var ml = new Roo.Element(document.createElement('div'));
14569 document.body.appendChild(ml.dom);
14570 ml.position('absolute');
14571 ml.setLeftTop(-1000, -1000);
14575 ml.setWidth(fixedWidth);
14580 * Returns the size of the specified text based on the internal element's style and width properties
14581 * @memberOf Roo.util.TextMetrics.Instance#
14582 * @param {String} text The text to measure
14583 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14585 getSize : function(text){
14587 var s = ml.getSize();
14593 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14594 * that can affect the size of the rendered text
14595 * @memberOf Roo.util.TextMetrics.Instance#
14596 * @param {String/HTMLElement} el The element, dom node or id
14598 bind : function(el){
14600 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14605 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14606 * to set a fixed width in order to accurately measure the text height.
14607 * @memberOf Roo.util.TextMetrics.Instance#
14608 * @param {Number} width The width to set on the element
14610 setFixedWidth : function(width){
14611 ml.setWidth(width);
14615 * Returns the measured width of the specified text
14616 * @memberOf Roo.util.TextMetrics.Instance#
14617 * @param {String} text The text to measure
14618 * @return {Number} width The width in pixels
14620 getWidth : function(text){
14621 ml.dom.style.width = 'auto';
14622 return this.getSize(text).width;
14626 * Returns the measured height of the specified text. For multiline text, be sure to call
14627 * {@link #setFixedWidth} if necessary.
14628 * @memberOf Roo.util.TextMetrics.Instance#
14629 * @param {String} text The text to measure
14630 * @return {Number} height The height in pixels
14632 getHeight : function(text){
14633 return this.getSize(text).height;
14637 instance.bind(bindTo);
14642 // backwards compat
14643 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14645 * Ext JS Library 1.1.1
14646 * Copyright(c) 2006-2007, Ext JS, LLC.
14648 * Originally Released Under LGPL - original licence link has changed is not relivant.
14651 * <script type="text/javascript">
14655 * @class Roo.state.Provider
14656 * Abstract base class for state provider implementations. This class provides methods
14657 * for encoding and decoding <b>typed</b> variables including dates and defines the
14658 * Provider interface.
14660 Roo.state.Provider = function(){
14662 * @event statechange
14663 * Fires when a state change occurs.
14664 * @param {Provider} this This state provider
14665 * @param {String} key The state key which was changed
14666 * @param {String} value The encoded value for the state
14669 "statechange": true
14672 Roo.state.Provider.superclass.constructor.call(this);
14674 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14676 * Returns the current value for a key
14677 * @param {String} name The key name
14678 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14679 * @return {Mixed} The state data
14681 get : function(name, defaultValue){
14682 return typeof this.state[name] == "undefined" ?
14683 defaultValue : this.state[name];
14687 * Clears a value from the state
14688 * @param {String} name The key name
14690 clear : function(name){
14691 delete this.state[name];
14692 this.fireEvent("statechange", this, name, null);
14696 * Sets the value for a key
14697 * @param {String} name The key name
14698 * @param {Mixed} value The value to set
14700 set : function(name, value){
14701 this.state[name] = value;
14702 this.fireEvent("statechange", this, name, value);
14706 * Decodes a string previously encoded with {@link #encodeValue}.
14707 * @param {String} value The value to decode
14708 * @return {Mixed} The decoded value
14710 decodeValue : function(cookie){
14711 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14712 var matches = re.exec(unescape(cookie));
14713 if(!matches || !matches[1]) return; // non state cookie
14714 var type = matches[1];
14715 var v = matches[2];
14718 return parseFloat(v);
14720 return new Date(Date.parse(v));
14725 var values = v.split("^");
14726 for(var i = 0, len = values.length; i < len; i++){
14727 all.push(this.decodeValue(values[i]));
14732 var values = v.split("^");
14733 for(var i = 0, len = values.length; i < len; i++){
14734 var kv = values[i].split("=");
14735 all[kv[0]] = this.decodeValue(kv[1]);
14744 * Encodes a value including type information. Decode with {@link #decodeValue}.
14745 * @param {Mixed} value The value to encode
14746 * @return {String} The encoded value
14748 encodeValue : function(v){
14750 if(typeof v == "number"){
14752 }else if(typeof v == "boolean"){
14753 enc = "b:" + (v ? "1" : "0");
14754 }else if(v instanceof Date){
14755 enc = "d:" + v.toGMTString();
14756 }else if(v instanceof Array){
14758 for(var i = 0, len = v.length; i < len; i++){
14759 flat += this.encodeValue(v[i]);
14760 if(i != len-1) flat += "^";
14763 }else if(typeof v == "object"){
14766 if(typeof v[key] != "function"){
14767 flat += key + "=" + this.encodeValue(v[key]) + "^";
14770 enc = "o:" + flat.substring(0, flat.length-1);
14774 return escape(enc);
14780 * Ext JS Library 1.1.1
14781 * Copyright(c) 2006-2007, Ext JS, LLC.
14783 * Originally Released Under LGPL - original licence link has changed is not relivant.
14786 * <script type="text/javascript">
14789 * @class Roo.state.Manager
14790 * This is the global state manager. By default all components that are "state aware" check this class
14791 * for state information if you don't pass them a custom state provider. In order for this class
14792 * to be useful, it must be initialized with a provider when your application initializes.
14794 // in your initialization function
14796 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14798 // supposed you have a {@link Roo.BorderLayout}
14799 var layout = new Roo.BorderLayout(...);
14800 layout.restoreState();
14801 // or a {Roo.BasicDialog}
14802 var dialog = new Roo.BasicDialog(...);
14803 dialog.restoreState();
14807 Roo.state.Manager = function(){
14808 var provider = new Roo.state.Provider();
14812 * Configures the default state provider for your application
14813 * @param {Provider} stateProvider The state provider to set
14815 setProvider : function(stateProvider){
14816 provider = stateProvider;
14820 * Returns the current value for a key
14821 * @param {String} name The key name
14822 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14823 * @return {Mixed} The state data
14825 get : function(key, defaultValue){
14826 return provider.get(key, defaultValue);
14830 * Sets the value for a key
14831 * @param {String} name The key name
14832 * @param {Mixed} value The state data
14834 set : function(key, value){
14835 provider.set(key, value);
14839 * Clears a value from the state
14840 * @param {String} name The key name
14842 clear : function(key){
14843 provider.clear(key);
14847 * Gets the currently configured state provider
14848 * @return {Provider} The state provider
14850 getProvider : function(){
14857 * Ext JS Library 1.1.1
14858 * Copyright(c) 2006-2007, Ext JS, LLC.
14860 * Originally Released Under LGPL - original licence link has changed is not relivant.
14863 * <script type="text/javascript">
14866 * @class Roo.state.CookieProvider
14867 * @extends Roo.state.Provider
14868 * The default Provider implementation which saves state via cookies.
14871 var cp = new Roo.state.CookieProvider({
14873 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14874 domain: "roojs.com"
14876 Roo.state.Manager.setProvider(cp);
14878 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14879 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14880 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14881 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14882 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14883 * domain the page is running on including the 'www' like 'www.roojs.com')
14884 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14886 * Create a new CookieProvider
14887 * @param {Object} config The configuration object
14889 Roo.state.CookieProvider = function(config){
14890 Roo.state.CookieProvider.superclass.constructor.call(this);
14892 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14893 this.domain = null;
14894 this.secure = false;
14895 Roo.apply(this, config);
14896 this.state = this.readCookies();
14899 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14901 set : function(name, value){
14902 if(typeof value == "undefined" || value === null){
14906 this.setCookie(name, value);
14907 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14911 clear : function(name){
14912 this.clearCookie(name);
14913 Roo.state.CookieProvider.superclass.clear.call(this, name);
14917 readCookies : function(){
14919 var c = document.cookie + ";";
14920 var re = /\s?(.*?)=(.*?);/g;
14922 while((matches = re.exec(c)) != null){
14923 var name = matches[1];
14924 var value = matches[2];
14925 if(name && name.substring(0,3) == "ys-"){
14926 cookies[name.substr(3)] = this.decodeValue(value);
14933 setCookie : function(name, value){
14934 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14935 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14936 ((this.path == null) ? "" : ("; path=" + this.path)) +
14937 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14938 ((this.secure == true) ? "; secure" : "");
14942 clearCookie : function(name){
14943 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14944 ((this.path == null) ? "" : ("; path=" + this.path)) +
14945 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14946 ((this.secure == true) ? "; secure" : "");
14950 * Ext JS Library 1.1.1
14951 * Copyright(c) 2006-2007, Ext JS, LLC.
14953 * Originally Released Under LGPL - original licence link has changed is not relivant.
14956 * <script type="text/javascript">
14962 * These classes are derivatives of the similarly named classes in the YUI Library.
14963 * The original license:
14964 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14965 * Code licensed under the BSD License:
14966 * http://developer.yahoo.net/yui/license.txt
14971 var Event=Roo.EventManager;
14972 var Dom=Roo.lib.Dom;
14975 * @class Roo.dd.DragDrop
14976 * @extends Roo.util.Observable
14977 * Defines the interface and base operation of items that that can be
14978 * dragged or can be drop targets. It was designed to be extended, overriding
14979 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14980 * Up to three html elements can be associated with a DragDrop instance:
14982 * <li>linked element: the element that is passed into the constructor.
14983 * This is the element which defines the boundaries for interaction with
14984 * other DragDrop objects.</li>
14985 * <li>handle element(s): The drag operation only occurs if the element that
14986 * was clicked matches a handle element. By default this is the linked
14987 * element, but there are times that you will want only a portion of the
14988 * linked element to initiate the drag operation, and the setHandleElId()
14989 * method provides a way to define this.</li>
14990 * <li>drag element: this represents the element that would be moved along
14991 * with the cursor during a drag operation. By default, this is the linked
14992 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14993 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14996 * This class should not be instantiated until the onload event to ensure that
14997 * the associated elements are available.
14998 * The following would define a DragDrop obj that would interact with any
14999 * other DragDrop obj in the "group1" group:
15001 * dd = new Roo.dd.DragDrop("div1", "group1");
15003 * Since none of the event handlers have been implemented, nothing would
15004 * actually happen if you were to run the code above. Normally you would
15005 * override this class or one of the default implementations, but you can
15006 * also override the methods you want on an instance of the class...
15008 * dd.onDragDrop = function(e, id) {
15009 * alert("dd was dropped on " + id);
15013 * @param {String} id of the element that is linked to this instance
15014 * @param {String} sGroup the group of related DragDrop objects
15015 * @param {object} config an object containing configurable attributes
15016 * Valid properties for DragDrop:
15017 * padding, isTarget, maintainOffset, primaryButtonOnly
15019 Roo.dd.DragDrop = function(id, sGroup, config) {
15021 this.init(id, sGroup, config);
15026 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15029 * The id of the element associated with this object. This is what we
15030 * refer to as the "linked element" because the size and position of
15031 * this element is used to determine when the drag and drop objects have
15039 * Configuration attributes passed into the constructor
15046 * The id of the element that will be dragged. By default this is same
15047 * as the linked element , but could be changed to another element. Ex:
15049 * @property dragElId
15056 * the id of the element that initiates the drag operation. By default
15057 * this is the linked element, but could be changed to be a child of this
15058 * element. This lets us do things like only starting the drag when the
15059 * header element within the linked html element is clicked.
15060 * @property handleElId
15067 * An associative array of HTML tags that will be ignored if clicked.
15068 * @property invalidHandleTypes
15069 * @type {string: string}
15071 invalidHandleTypes: null,
15074 * An associative array of ids for elements that will be ignored if clicked
15075 * @property invalidHandleIds
15076 * @type {string: string}
15078 invalidHandleIds: null,
15081 * An indexted array of css class names for elements that will be ignored
15083 * @property invalidHandleClasses
15086 invalidHandleClasses: null,
15089 * The linked element's absolute X position at the time the drag was
15091 * @property startPageX
15098 * The linked element's absolute X position at the time the drag was
15100 * @property startPageY
15107 * The group defines a logical collection of DragDrop objects that are
15108 * related. Instances only get events when interacting with other
15109 * DragDrop object in the same group. This lets us define multiple
15110 * groups using a single DragDrop subclass if we want.
15112 * @type {string: string}
15117 * Individual drag/drop instances can be locked. This will prevent
15118 * onmousedown start drag.
15126 * Lock this instance
15129 lock: function() { this.locked = true; },
15132 * Unlock this instace
15135 unlock: function() { this.locked = false; },
15138 * By default, all insances can be a drop target. This can be disabled by
15139 * setting isTarget to false.
15146 * The padding configured for this drag and drop object for calculating
15147 * the drop zone intersection with this object.
15154 * Cached reference to the linked element
15155 * @property _domRef
15161 * Internal typeof flag
15162 * @property __ygDragDrop
15165 __ygDragDrop: true,
15168 * Set to true when horizontal contraints are applied
15169 * @property constrainX
15176 * Set to true when vertical contraints are applied
15177 * @property constrainY
15184 * The left constraint
15192 * The right constraint
15200 * The up constraint
15209 * The down constraint
15217 * Maintain offsets when we resetconstraints. Set to true when you want
15218 * the position of the element relative to its parent to stay the same
15219 * when the page changes
15221 * @property maintainOffset
15224 maintainOffset: false,
15227 * Array of pixel locations the element will snap to if we specified a
15228 * horizontal graduation/interval. This array is generated automatically
15229 * when you define a tick interval.
15236 * Array of pixel locations the element will snap to if we specified a
15237 * vertical graduation/interval. This array is generated automatically
15238 * when you define a tick interval.
15245 * By default the drag and drop instance will only respond to the primary
15246 * button click (left button for a right-handed mouse). Set to true to
15247 * allow drag and drop to start with any mouse click that is propogated
15249 * @property primaryButtonOnly
15252 primaryButtonOnly: true,
15255 * The availabe property is false until the linked dom element is accessible.
15256 * @property available
15262 * By default, drags can only be initiated if the mousedown occurs in the
15263 * region the linked element is. This is done in part to work around a
15264 * bug in some browsers that mis-report the mousedown if the previous
15265 * mouseup happened outside of the window. This property is set to true
15266 * if outer handles are defined.
15268 * @property hasOuterHandles
15272 hasOuterHandles: false,
15275 * Code that executes immediately before the startDrag event
15276 * @method b4StartDrag
15279 b4StartDrag: function(x, y) { },
15282 * Abstract method called after a drag/drop object is clicked
15283 * and the drag or mousedown time thresholds have beeen met.
15284 * @method startDrag
15285 * @param {int} X click location
15286 * @param {int} Y click location
15288 startDrag: function(x, y) { /* override this */ },
15291 * Code that executes immediately before the onDrag event
15295 b4Drag: function(e) { },
15298 * Abstract method called during the onMouseMove event while dragging an
15301 * @param {Event} e the mousemove event
15303 onDrag: function(e) { /* override this */ },
15306 * Abstract method called when this element fist begins hovering over
15307 * another DragDrop obj
15308 * @method onDragEnter
15309 * @param {Event} e the mousemove event
15310 * @param {String|DragDrop[]} id In POINT mode, the element
15311 * id this is hovering over. In INTERSECT mode, an array of one or more
15312 * dragdrop items being hovered over.
15314 onDragEnter: function(e, id) { /* override this */ },
15317 * Code that executes immediately before the onDragOver event
15318 * @method b4DragOver
15321 b4DragOver: function(e) { },
15324 * Abstract method called when this element is hovering over another
15326 * @method onDragOver
15327 * @param {Event} e the mousemove event
15328 * @param {String|DragDrop[]} id In POINT mode, the element
15329 * id this is hovering over. In INTERSECT mode, an array of dd items
15330 * being hovered over.
15332 onDragOver: function(e, id) { /* override this */ },
15335 * Code that executes immediately before the onDragOut event
15336 * @method b4DragOut
15339 b4DragOut: function(e) { },
15342 * Abstract method called when we are no longer hovering over an element
15343 * @method onDragOut
15344 * @param {Event} e the mousemove event
15345 * @param {String|DragDrop[]} id In POINT mode, the element
15346 * id this was hovering over. In INTERSECT mode, an array of dd items
15347 * that the mouse is no longer over.
15349 onDragOut: function(e, id) { /* override this */ },
15352 * Code that executes immediately before the onDragDrop event
15353 * @method b4DragDrop
15356 b4DragDrop: function(e) { },
15359 * Abstract method called when this item is dropped on another DragDrop
15361 * @method onDragDrop
15362 * @param {Event} e the mouseup event
15363 * @param {String|DragDrop[]} id In POINT mode, the element
15364 * id this was dropped on. In INTERSECT mode, an array of dd items this
15367 onDragDrop: function(e, id) { /* override this */ },
15370 * Abstract method called when this item is dropped on an area with no
15372 * @method onInvalidDrop
15373 * @param {Event} e the mouseup event
15375 onInvalidDrop: function(e) { /* override this */ },
15378 * Code that executes immediately before the endDrag event
15379 * @method b4EndDrag
15382 b4EndDrag: function(e) { },
15385 * Fired when we are done dragging the object
15387 * @param {Event} e the mouseup event
15389 endDrag: function(e) { /* override this */ },
15392 * Code executed immediately before the onMouseDown event
15393 * @method b4MouseDown
15394 * @param {Event} e the mousedown event
15397 b4MouseDown: function(e) { },
15400 * Event handler that fires when a drag/drop obj gets a mousedown
15401 * @method onMouseDown
15402 * @param {Event} e the mousedown event
15404 onMouseDown: function(e) { /* override this */ },
15407 * Event handler that fires when a drag/drop obj gets a mouseup
15408 * @method onMouseUp
15409 * @param {Event} e the mouseup event
15411 onMouseUp: function(e) { /* override this */ },
15414 * Override the onAvailable method to do what is needed after the initial
15415 * position was determined.
15416 * @method onAvailable
15418 onAvailable: function () {
15422 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15425 defaultPadding : {left:0, right:0, top:0, bottom:0},
15428 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15432 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15433 { dragElId: "existingProxyDiv" });
15434 dd.startDrag = function(){
15435 this.constrainTo("parent-id");
15438 * Or you can initalize it using the {@link Roo.Element} object:
15440 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15441 startDrag : function(){
15442 this.constrainTo("parent-id");
15446 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15447 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15448 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15449 * an object containing the sides to pad. For example: {right:10, bottom:10}
15450 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15452 constrainTo : function(constrainTo, pad, inContent){
15453 if(typeof pad == "number"){
15454 pad = {left: pad, right:pad, top:pad, bottom:pad};
15456 pad = pad || this.defaultPadding;
15457 var b = Roo.get(this.getEl()).getBox();
15458 var ce = Roo.get(constrainTo);
15459 var s = ce.getScroll();
15460 var c, cd = ce.dom;
15461 if(cd == document.body){
15462 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15465 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15469 var topSpace = b.y - c.y;
15470 var leftSpace = b.x - c.x;
15472 this.resetConstraints();
15473 this.setXConstraint(leftSpace - (pad.left||0), // left
15474 c.width - leftSpace - b.width - (pad.right||0) //right
15476 this.setYConstraint(topSpace - (pad.top||0), //top
15477 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15482 * Returns a reference to the linked element
15484 * @return {HTMLElement} the html element
15486 getEl: function() {
15487 if (!this._domRef) {
15488 this._domRef = Roo.getDom(this.id);
15491 return this._domRef;
15495 * Returns a reference to the actual element to drag. By default this is
15496 * the same as the html element, but it can be assigned to another
15497 * element. An example of this can be found in Roo.dd.DDProxy
15498 * @method getDragEl
15499 * @return {HTMLElement} the html element
15501 getDragEl: function() {
15502 return Roo.getDom(this.dragElId);
15506 * Sets up the DragDrop object. Must be called in the constructor of any
15507 * Roo.dd.DragDrop subclass
15509 * @param id the id of the linked element
15510 * @param {String} sGroup the group of related items
15511 * @param {object} config configuration attributes
15513 init: function(id, sGroup, config) {
15514 this.initTarget(id, sGroup, config);
15515 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15516 // Event.on(this.id, "selectstart", Event.preventDefault);
15520 * Initializes Targeting functionality only... the object does not
15521 * get a mousedown handler.
15522 * @method initTarget
15523 * @param id the id of the linked element
15524 * @param {String} sGroup the group of related items
15525 * @param {object} config configuration attributes
15527 initTarget: function(id, sGroup, config) {
15529 // configuration attributes
15530 this.config = config || {};
15532 // create a local reference to the drag and drop manager
15533 this.DDM = Roo.dd.DDM;
15534 // initialize the groups array
15537 // assume that we have an element reference instead of an id if the
15538 // parameter is not a string
15539 if (typeof id !== "string") {
15546 // add to an interaction group
15547 this.addToGroup((sGroup) ? sGroup : "default");
15549 // We don't want to register this as the handle with the manager
15550 // so we just set the id rather than calling the setter.
15551 this.handleElId = id;
15553 // the linked element is the element that gets dragged by default
15554 this.setDragElId(id);
15556 // by default, clicked anchors will not start drag operations.
15557 this.invalidHandleTypes = { A: "A" };
15558 this.invalidHandleIds = {};
15559 this.invalidHandleClasses = [];
15561 this.applyConfig();
15563 this.handleOnAvailable();
15567 * Applies the configuration parameters that were passed into the constructor.
15568 * This is supposed to happen at each level through the inheritance chain. So
15569 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15570 * DragDrop in order to get all of the parameters that are available in
15572 * @method applyConfig
15574 applyConfig: function() {
15576 // configurable properties:
15577 // padding, isTarget, maintainOffset, primaryButtonOnly
15578 this.padding = this.config.padding || [0, 0, 0, 0];
15579 this.isTarget = (this.config.isTarget !== false);
15580 this.maintainOffset = (this.config.maintainOffset);
15581 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15586 * Executed when the linked element is available
15587 * @method handleOnAvailable
15590 handleOnAvailable: function() {
15591 this.available = true;
15592 this.resetConstraints();
15593 this.onAvailable();
15597 * Configures the padding for the target zone in px. Effectively expands
15598 * (or reduces) the virtual object size for targeting calculations.
15599 * Supports css-style shorthand; if only one parameter is passed, all sides
15600 * will have that padding, and if only two are passed, the top and bottom
15601 * will have the first param, the left and right the second.
15602 * @method setPadding
15603 * @param {int} iTop Top pad
15604 * @param {int} iRight Right pad
15605 * @param {int} iBot Bot pad
15606 * @param {int} iLeft Left pad
15608 setPadding: function(iTop, iRight, iBot, iLeft) {
15609 // this.padding = [iLeft, iRight, iTop, iBot];
15610 if (!iRight && 0 !== iRight) {
15611 this.padding = [iTop, iTop, iTop, iTop];
15612 } else if (!iBot && 0 !== iBot) {
15613 this.padding = [iTop, iRight, iTop, iRight];
15615 this.padding = [iTop, iRight, iBot, iLeft];
15620 * Stores the initial placement of the linked element.
15621 * @method setInitialPosition
15622 * @param {int} diffX the X offset, default 0
15623 * @param {int} diffY the Y offset, default 0
15625 setInitPosition: function(diffX, diffY) {
15626 var el = this.getEl();
15628 if (!this.DDM.verifyEl(el)) {
15632 var dx = diffX || 0;
15633 var dy = diffY || 0;
15635 var p = Dom.getXY( el );
15637 this.initPageX = p[0] - dx;
15638 this.initPageY = p[1] - dy;
15640 this.lastPageX = p[0];
15641 this.lastPageY = p[1];
15644 this.setStartPosition(p);
15648 * Sets the start position of the element. This is set when the obj
15649 * is initialized, the reset when a drag is started.
15650 * @method setStartPosition
15651 * @param pos current position (from previous lookup)
15654 setStartPosition: function(pos) {
15655 var p = pos || Dom.getXY( this.getEl() );
15656 this.deltaSetXY = null;
15658 this.startPageX = p[0];
15659 this.startPageY = p[1];
15663 * Add this instance to a group of related drag/drop objects. All
15664 * instances belong to at least one group, and can belong to as many
15665 * groups as needed.
15666 * @method addToGroup
15667 * @param sGroup {string} the name of the group
15669 addToGroup: function(sGroup) {
15670 this.groups[sGroup] = true;
15671 this.DDM.regDragDrop(this, sGroup);
15675 * Remove's this instance from the supplied interaction group
15676 * @method removeFromGroup
15677 * @param {string} sGroup The group to drop
15679 removeFromGroup: function(sGroup) {
15680 if (this.groups[sGroup]) {
15681 delete this.groups[sGroup];
15684 this.DDM.removeDDFromGroup(this, sGroup);
15688 * Allows you to specify that an element other than the linked element
15689 * will be moved with the cursor during a drag
15690 * @method setDragElId
15691 * @param id {string} the id of the element that will be used to initiate the drag
15693 setDragElId: function(id) {
15694 this.dragElId = id;
15698 * Allows you to specify a child of the linked element that should be
15699 * used to initiate the drag operation. An example of this would be if
15700 * you have a content div with text and links. Clicking anywhere in the
15701 * content area would normally start the drag operation. Use this method
15702 * to specify that an element inside of the content div is the element
15703 * that starts the drag operation.
15704 * @method setHandleElId
15705 * @param id {string} the id of the element that will be used to
15706 * initiate the drag.
15708 setHandleElId: function(id) {
15709 if (typeof id !== "string") {
15712 this.handleElId = id;
15713 this.DDM.regHandle(this.id, id);
15717 * Allows you to set an element outside of the linked element as a drag
15719 * @method setOuterHandleElId
15720 * @param id the id of the element that will be used to initiate the drag
15722 setOuterHandleElId: function(id) {
15723 if (typeof id !== "string") {
15726 Event.on(id, "mousedown",
15727 this.handleMouseDown, this);
15728 this.setHandleElId(id);
15730 this.hasOuterHandles = true;
15734 * Remove all drag and drop hooks for this element
15737 unreg: function() {
15738 Event.un(this.id, "mousedown",
15739 this.handleMouseDown);
15740 this._domRef = null;
15741 this.DDM._remove(this);
15744 destroy : function(){
15749 * Returns true if this instance is locked, or the drag drop mgr is locked
15750 * (meaning that all drag/drop is disabled on the page.)
15752 * @return {boolean} true if this obj or all drag/drop is locked, else
15755 isLocked: function() {
15756 return (this.DDM.isLocked() || this.locked);
15760 * Fired when this object is clicked
15761 * @method handleMouseDown
15763 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15766 handleMouseDown: function(e, oDD){
15767 if (this.primaryButtonOnly && e.button != 0) {
15771 if (this.isLocked()) {
15775 this.DDM.refreshCache(this.groups);
15777 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15778 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15780 if (this.clickValidator(e)) {
15782 // set the initial element position
15783 this.setStartPosition();
15786 this.b4MouseDown(e);
15787 this.onMouseDown(e);
15789 this.DDM.handleMouseDown(e, this);
15791 this.DDM.stopEvent(e);
15799 clickValidator: function(e) {
15800 var target = e.getTarget();
15801 return ( this.isValidHandleChild(target) &&
15802 (this.id == this.handleElId ||
15803 this.DDM.handleWasClicked(target, this.id)) );
15807 * Allows you to specify a tag name that should not start a drag operation
15808 * when clicked. This is designed to facilitate embedding links within a
15809 * drag handle that do something other than start the drag.
15810 * @method addInvalidHandleType
15811 * @param {string} tagName the type of element to exclude
15813 addInvalidHandleType: function(tagName) {
15814 var type = tagName.toUpperCase();
15815 this.invalidHandleTypes[type] = type;
15819 * Lets you to specify an element id for a child of a drag handle
15820 * that should not initiate a drag
15821 * @method addInvalidHandleId
15822 * @param {string} id the element id of the element you wish to ignore
15824 addInvalidHandleId: function(id) {
15825 if (typeof id !== "string") {
15828 this.invalidHandleIds[id] = id;
15832 * Lets you specify a css class of elements that will not initiate a drag
15833 * @method addInvalidHandleClass
15834 * @param {string} cssClass the class of the elements you wish to ignore
15836 addInvalidHandleClass: function(cssClass) {
15837 this.invalidHandleClasses.push(cssClass);
15841 * Unsets an excluded tag name set by addInvalidHandleType
15842 * @method removeInvalidHandleType
15843 * @param {string} tagName the type of element to unexclude
15845 removeInvalidHandleType: function(tagName) {
15846 var type = tagName.toUpperCase();
15847 // this.invalidHandleTypes[type] = null;
15848 delete this.invalidHandleTypes[type];
15852 * Unsets an invalid handle id
15853 * @method removeInvalidHandleId
15854 * @param {string} id the id of the element to re-enable
15856 removeInvalidHandleId: function(id) {
15857 if (typeof id !== "string") {
15860 delete this.invalidHandleIds[id];
15864 * Unsets an invalid css class
15865 * @method removeInvalidHandleClass
15866 * @param {string} cssClass the class of the element(s) you wish to
15869 removeInvalidHandleClass: function(cssClass) {
15870 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15871 if (this.invalidHandleClasses[i] == cssClass) {
15872 delete this.invalidHandleClasses[i];
15878 * Checks the tag exclusion list to see if this click should be ignored
15879 * @method isValidHandleChild
15880 * @param {HTMLElement} node the HTMLElement to evaluate
15881 * @return {boolean} true if this is a valid tag type, false if not
15883 isValidHandleChild: function(node) {
15886 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15889 nodeName = node.nodeName.toUpperCase();
15891 nodeName = node.nodeName;
15893 valid = valid && !this.invalidHandleTypes[nodeName];
15894 valid = valid && !this.invalidHandleIds[node.id];
15896 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15897 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15906 * Create the array of horizontal tick marks if an interval was specified
15907 * in setXConstraint().
15908 * @method setXTicks
15911 setXTicks: function(iStartX, iTickSize) {
15913 this.xTickSize = iTickSize;
15917 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15919 this.xTicks[this.xTicks.length] = i;
15924 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15926 this.xTicks[this.xTicks.length] = i;
15931 this.xTicks.sort(this.DDM.numericSort) ;
15935 * Create the array of vertical tick marks if an interval was specified in
15936 * setYConstraint().
15937 * @method setYTicks
15940 setYTicks: function(iStartY, iTickSize) {
15942 this.yTickSize = iTickSize;
15946 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15948 this.yTicks[this.yTicks.length] = i;
15953 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15955 this.yTicks[this.yTicks.length] = i;
15960 this.yTicks.sort(this.DDM.numericSort) ;
15964 * By default, the element can be dragged any place on the screen. Use
15965 * this method to limit the horizontal travel of the element. Pass in
15966 * 0,0 for the parameters if you want to lock the drag to the y axis.
15967 * @method setXConstraint
15968 * @param {int} iLeft the number of pixels the element can move to the left
15969 * @param {int} iRight the number of pixels the element can move to the
15971 * @param {int} iTickSize optional parameter for specifying that the
15973 * should move iTickSize pixels at a time.
15975 setXConstraint: function(iLeft, iRight, iTickSize) {
15976 this.leftConstraint = iLeft;
15977 this.rightConstraint = iRight;
15979 this.minX = this.initPageX - iLeft;
15980 this.maxX = this.initPageX + iRight;
15981 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15983 this.constrainX = true;
15987 * Clears any constraints applied to this instance. Also clears ticks
15988 * since they can't exist independent of a constraint at this time.
15989 * @method clearConstraints
15991 clearConstraints: function() {
15992 this.constrainX = false;
15993 this.constrainY = false;
15998 * Clears any tick interval defined for this instance
15999 * @method clearTicks
16001 clearTicks: function() {
16002 this.xTicks = null;
16003 this.yTicks = null;
16004 this.xTickSize = 0;
16005 this.yTickSize = 0;
16009 * By default, the element can be dragged any place on the screen. Set
16010 * this to limit the vertical travel of the element. Pass in 0,0 for the
16011 * parameters if you want to lock the drag to the x axis.
16012 * @method setYConstraint
16013 * @param {int} iUp the number of pixels the element can move up
16014 * @param {int} iDown the number of pixels the element can move down
16015 * @param {int} iTickSize optional parameter for specifying that the
16016 * element should move iTickSize pixels at a time.
16018 setYConstraint: function(iUp, iDown, iTickSize) {
16019 this.topConstraint = iUp;
16020 this.bottomConstraint = iDown;
16022 this.minY = this.initPageY - iUp;
16023 this.maxY = this.initPageY + iDown;
16024 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16026 this.constrainY = true;
16031 * resetConstraints must be called if you manually reposition a dd element.
16032 * @method resetConstraints
16033 * @param {boolean} maintainOffset
16035 resetConstraints: function() {
16038 // Maintain offsets if necessary
16039 if (this.initPageX || this.initPageX === 0) {
16040 // figure out how much this thing has moved
16041 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16042 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16044 this.setInitPosition(dx, dy);
16046 // This is the first time we have detected the element's position
16048 this.setInitPosition();
16051 if (this.constrainX) {
16052 this.setXConstraint( this.leftConstraint,
16053 this.rightConstraint,
16057 if (this.constrainY) {
16058 this.setYConstraint( this.topConstraint,
16059 this.bottomConstraint,
16065 * Normally the drag element is moved pixel by pixel, but we can specify
16066 * that it move a number of pixels at a time. This method resolves the
16067 * location when we have it set up like this.
16069 * @param {int} val where we want to place the object
16070 * @param {int[]} tickArray sorted array of valid points
16071 * @return {int} the closest tick
16074 getTick: function(val, tickArray) {
16077 // If tick interval is not defined, it is effectively 1 pixel,
16078 // so we return the value passed to us.
16080 } else if (tickArray[0] >= val) {
16081 // The value is lower than the first tick, so we return the first
16083 return tickArray[0];
16085 for (var i=0, len=tickArray.length; i<len; ++i) {
16087 if (tickArray[next] && tickArray[next] >= val) {
16088 var diff1 = val - tickArray[i];
16089 var diff2 = tickArray[next] - val;
16090 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16094 // The value is larger than the last tick, so we return the last
16096 return tickArray[tickArray.length - 1];
16103 * @return {string} string representation of the dd obj
16105 toString: function() {
16106 return ("DragDrop " + this.id);
16114 * Ext JS Library 1.1.1
16115 * Copyright(c) 2006-2007, Ext JS, LLC.
16117 * Originally Released Under LGPL - original licence link has changed is not relivant.
16120 * <script type="text/javascript">
16125 * The drag and drop utility provides a framework for building drag and drop
16126 * applications. In addition to enabling drag and drop for specific elements,
16127 * the drag and drop elements are tracked by the manager class, and the
16128 * interactions between the various elements are tracked during the drag and
16129 * the implementing code is notified about these important moments.
16132 // Only load the library once. Rewriting the manager class would orphan
16133 // existing drag and drop instances.
16134 if (!Roo.dd.DragDropMgr) {
16137 * @class Roo.dd.DragDropMgr
16138 * DragDropMgr is a singleton that tracks the element interaction for
16139 * all DragDrop items in the window. Generally, you will not call
16140 * this class directly, but it does have helper methods that could
16141 * be useful in your DragDrop implementations.
16144 Roo.dd.DragDropMgr = function() {
16146 var Event = Roo.EventManager;
16151 * Two dimensional Array of registered DragDrop objects. The first
16152 * dimension is the DragDrop item group, the second the DragDrop
16155 * @type {string: string}
16162 * Array of element ids defined as drag handles. Used to determine
16163 * if the element that generated the mousedown event is actually the
16164 * handle and not the html element itself.
16165 * @property handleIds
16166 * @type {string: string}
16173 * the DragDrop object that is currently being dragged
16174 * @property dragCurrent
16182 * the DragDrop object(s) that are being hovered over
16183 * @property dragOvers
16191 * the X distance between the cursor and the object being dragged
16200 * the Y distance between the cursor and the object being dragged
16209 * Flag to determine if we should prevent the default behavior of the
16210 * events we define. By default this is true, but this can be set to
16211 * false if you need the default behavior (not recommended)
16212 * @property preventDefault
16216 preventDefault: true,
16219 * Flag to determine if we should stop the propagation of the events
16220 * we generate. This is true by default but you may want to set it to
16221 * false if the html element contains other features that require the
16223 * @property stopPropagation
16227 stopPropagation: true,
16230 * Internal flag that is set to true when drag and drop has been
16232 * @property initialized
16239 * All drag and drop can be disabled.
16247 * Called the first time an element is registered.
16253 this.initialized = true;
16257 * In point mode, drag and drop interaction is defined by the
16258 * location of the cursor during the drag/drop
16266 * In intersect mode, drag and drop interactio nis defined by the
16267 * overlap of two or more drag and drop objects.
16268 * @property INTERSECT
16275 * The current drag and drop mode. Default: POINT
16283 * Runs method on all drag and drop objects
16284 * @method _execOnAll
16288 _execOnAll: function(sMethod, args) {
16289 for (var i in this.ids) {
16290 for (var j in this.ids[i]) {
16291 var oDD = this.ids[i][j];
16292 if (! this.isTypeOfDD(oDD)) {
16295 oDD[sMethod].apply(oDD, args);
16301 * Drag and drop initialization. Sets up the global event handlers
16306 _onLoad: function() {
16311 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16312 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16313 Event.on(window, "unload", this._onUnload, this, true);
16314 Event.on(window, "resize", this._onResize, this, true);
16315 // Event.on(window, "mouseout", this._test);
16320 * Reset constraints on all drag and drop objs
16321 * @method _onResize
16325 _onResize: function(e) {
16326 this._execOnAll("resetConstraints", []);
16330 * Lock all drag and drop functionality
16334 lock: function() { this.locked = true; },
16337 * Unlock all drag and drop functionality
16341 unlock: function() { this.locked = false; },
16344 * Is drag and drop locked?
16346 * @return {boolean} True if drag and drop is locked, false otherwise.
16349 isLocked: function() { return this.locked; },
16352 * Location cache that is set for all drag drop objects when a drag is
16353 * initiated, cleared when the drag is finished.
16354 * @property locationCache
16361 * Set useCache to false if you want to force object the lookup of each
16362 * drag and drop linked element constantly during a drag.
16363 * @property useCache
16370 * The number of pixels that the mouse needs to move after the
16371 * mousedown before the drag is initiated. Default=3;
16372 * @property clickPixelThresh
16376 clickPixelThresh: 3,
16379 * The number of milliseconds after the mousedown event to initiate the
16380 * drag if we don't get a mouseup event. Default=1000
16381 * @property clickTimeThresh
16385 clickTimeThresh: 350,
16388 * Flag that indicates that either the drag pixel threshold or the
16389 * mousdown time threshold has been met
16390 * @property dragThreshMet
16395 dragThreshMet: false,
16398 * Timeout used for the click time threshold
16399 * @property clickTimeout
16404 clickTimeout: null,
16407 * The X position of the mousedown event stored for later use when a
16408 * drag threshold is met.
16417 * The Y position of the mousedown event stored for later use when a
16418 * drag threshold is met.
16427 * Each DragDrop instance must be registered with the DragDropMgr.
16428 * This is executed in DragDrop.init()
16429 * @method regDragDrop
16430 * @param {DragDrop} oDD the DragDrop object to register
16431 * @param {String} sGroup the name of the group this element belongs to
16434 regDragDrop: function(oDD, sGroup) {
16435 if (!this.initialized) { this.init(); }
16437 if (!this.ids[sGroup]) {
16438 this.ids[sGroup] = {};
16440 this.ids[sGroup][oDD.id] = oDD;
16444 * Removes the supplied dd instance from the supplied group. Executed
16445 * by DragDrop.removeFromGroup, so don't call this function directly.
16446 * @method removeDDFromGroup
16450 removeDDFromGroup: function(oDD, sGroup) {
16451 if (!this.ids[sGroup]) {
16452 this.ids[sGroup] = {};
16455 var obj = this.ids[sGroup];
16456 if (obj && obj[oDD.id]) {
16457 delete obj[oDD.id];
16462 * Unregisters a drag and drop item. This is executed in
16463 * DragDrop.unreg, use that method instead of calling this directly.
16468 _remove: function(oDD) {
16469 for (var g in oDD.groups) {
16470 if (g && this.ids[g][oDD.id]) {
16471 delete this.ids[g][oDD.id];
16474 delete this.handleIds[oDD.id];
16478 * Each DragDrop handle element must be registered. This is done
16479 * automatically when executing DragDrop.setHandleElId()
16480 * @method regHandle
16481 * @param {String} sDDId the DragDrop id this element is a handle for
16482 * @param {String} sHandleId the id of the element that is the drag
16486 regHandle: function(sDDId, sHandleId) {
16487 if (!this.handleIds[sDDId]) {
16488 this.handleIds[sDDId] = {};
16490 this.handleIds[sDDId][sHandleId] = sHandleId;
16494 * Utility function to determine if a given element has been
16495 * registered as a drag drop item.
16496 * @method isDragDrop
16497 * @param {String} id the element id to check
16498 * @return {boolean} true if this element is a DragDrop item,
16502 isDragDrop: function(id) {
16503 return ( this.getDDById(id) ) ? true : false;
16507 * Returns the drag and drop instances that are in all groups the
16508 * passed in instance belongs to.
16509 * @method getRelated
16510 * @param {DragDrop} p_oDD the obj to get related data for
16511 * @param {boolean} bTargetsOnly if true, only return targetable objs
16512 * @return {DragDrop[]} the related instances
16515 getRelated: function(p_oDD, bTargetsOnly) {
16517 for (var i in p_oDD.groups) {
16518 for (j in this.ids[i]) {
16519 var dd = this.ids[i][j];
16520 if (! this.isTypeOfDD(dd)) {
16523 if (!bTargetsOnly || dd.isTarget) {
16524 oDDs[oDDs.length] = dd;
16533 * Returns true if the specified dd target is a legal target for
16534 * the specifice drag obj
16535 * @method isLegalTarget
16536 * @param {DragDrop} the drag obj
16537 * @param {DragDrop} the target
16538 * @return {boolean} true if the target is a legal target for the
16542 isLegalTarget: function (oDD, oTargetDD) {
16543 var targets = this.getRelated(oDD, true);
16544 for (var i=0, len=targets.length;i<len;++i) {
16545 if (targets[i].id == oTargetDD.id) {
16554 * My goal is to be able to transparently determine if an object is
16555 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16556 * returns "object", oDD.constructor.toString() always returns
16557 * "DragDrop" and not the name of the subclass. So for now it just
16558 * evaluates a well-known variable in DragDrop.
16559 * @method isTypeOfDD
16560 * @param {Object} the object to evaluate
16561 * @return {boolean} true if typeof oDD = DragDrop
16564 isTypeOfDD: function (oDD) {
16565 return (oDD && oDD.__ygDragDrop);
16569 * Utility function to determine if a given element has been
16570 * registered as a drag drop handle for the given Drag Drop object.
16572 * @param {String} id the element id to check
16573 * @return {boolean} true if this element is a DragDrop handle, false
16577 isHandle: function(sDDId, sHandleId) {
16578 return ( this.handleIds[sDDId] &&
16579 this.handleIds[sDDId][sHandleId] );
16583 * Returns the DragDrop instance for a given id
16584 * @method getDDById
16585 * @param {String} id the id of the DragDrop object
16586 * @return {DragDrop} the drag drop object, null if it is not found
16589 getDDById: function(id) {
16590 for (var i in this.ids) {
16591 if (this.ids[i][id]) {
16592 return this.ids[i][id];
16599 * Fired after a registered DragDrop object gets the mousedown event.
16600 * Sets up the events required to track the object being dragged
16601 * @method handleMouseDown
16602 * @param {Event} e the event
16603 * @param oDD the DragDrop object being dragged
16607 handleMouseDown: function(e, oDD) {
16609 Roo.QuickTips.disable();
16611 this.currentTarget = e.getTarget();
16613 this.dragCurrent = oDD;
16615 var el = oDD.getEl();
16617 // track start position
16618 this.startX = e.getPageX();
16619 this.startY = e.getPageY();
16621 this.deltaX = this.startX - el.offsetLeft;
16622 this.deltaY = this.startY - el.offsetTop;
16624 this.dragThreshMet = false;
16626 this.clickTimeout = setTimeout(
16628 var DDM = Roo.dd.DDM;
16629 DDM.startDrag(DDM.startX, DDM.startY);
16631 this.clickTimeThresh );
16635 * Fired when either the drag pixel threshol or the mousedown hold
16636 * time threshold has been met.
16637 * @method startDrag
16638 * @param x {int} the X position of the original mousedown
16639 * @param y {int} the Y position of the original mousedown
16642 startDrag: function(x, y) {
16643 clearTimeout(this.clickTimeout);
16644 if (this.dragCurrent) {
16645 this.dragCurrent.b4StartDrag(x, y);
16646 this.dragCurrent.startDrag(x, y);
16648 this.dragThreshMet = true;
16652 * Internal function to handle the mouseup event. Will be invoked
16653 * from the context of the document.
16654 * @method handleMouseUp
16655 * @param {Event} e the event
16659 handleMouseUp: function(e) {
16662 Roo.QuickTips.enable();
16664 if (! this.dragCurrent) {
16668 clearTimeout(this.clickTimeout);
16670 if (this.dragThreshMet) {
16671 this.fireEvents(e, true);
16681 * Utility to stop event propagation and event default, if these
16682 * features are turned on.
16683 * @method stopEvent
16684 * @param {Event} e the event as returned by this.getEvent()
16687 stopEvent: function(e){
16688 if(this.stopPropagation) {
16689 e.stopPropagation();
16692 if (this.preventDefault) {
16693 e.preventDefault();
16698 * Internal function to clean up event handlers after the drag
16699 * operation is complete
16701 * @param {Event} e the event
16705 stopDrag: function(e) {
16706 // Fire the drag end event for the item that was dragged
16707 if (this.dragCurrent) {
16708 if (this.dragThreshMet) {
16709 this.dragCurrent.b4EndDrag(e);
16710 this.dragCurrent.endDrag(e);
16713 this.dragCurrent.onMouseUp(e);
16716 this.dragCurrent = null;
16717 this.dragOvers = {};
16721 * Internal function to handle the mousemove event. Will be invoked
16722 * from the context of the html element.
16724 * @TODO figure out what we can do about mouse events lost when the
16725 * user drags objects beyond the window boundary. Currently we can
16726 * detect this in internet explorer by verifying that the mouse is
16727 * down during the mousemove event. Firefox doesn't give us the
16728 * button state on the mousemove event.
16729 * @method handleMouseMove
16730 * @param {Event} e the event
16734 handleMouseMove: function(e) {
16735 if (! this.dragCurrent) {
16739 // var button = e.which || e.button;
16741 // check for IE mouseup outside of page boundary
16742 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16744 return this.handleMouseUp(e);
16747 if (!this.dragThreshMet) {
16748 var diffX = Math.abs(this.startX - e.getPageX());
16749 var diffY = Math.abs(this.startY - e.getPageY());
16750 if (diffX > this.clickPixelThresh ||
16751 diffY > this.clickPixelThresh) {
16752 this.startDrag(this.startX, this.startY);
16756 if (this.dragThreshMet) {
16757 this.dragCurrent.b4Drag(e);
16758 this.dragCurrent.onDrag(e);
16759 if(!this.dragCurrent.moveOnly){
16760 this.fireEvents(e, false);
16770 * Iterates over all of the DragDrop elements to find ones we are
16771 * hovering over or dropping on
16772 * @method fireEvents
16773 * @param {Event} e the event
16774 * @param {boolean} isDrop is this a drop op or a mouseover op?
16778 fireEvents: function(e, isDrop) {
16779 var dc = this.dragCurrent;
16781 // If the user did the mouse up outside of the window, we could
16782 // get here even though we have ended the drag.
16783 if (!dc || dc.isLocked()) {
16787 var pt = e.getPoint();
16789 // cache the previous dragOver array
16795 var enterEvts = [];
16797 // Check to see if the object(s) we were hovering over is no longer
16798 // being hovered over so we can fire the onDragOut event
16799 for (var i in this.dragOvers) {
16801 var ddo = this.dragOvers[i];
16803 if (! this.isTypeOfDD(ddo)) {
16807 if (! this.isOverTarget(pt, ddo, this.mode)) {
16808 outEvts.push( ddo );
16811 oldOvers[i] = true;
16812 delete this.dragOvers[i];
16815 for (var sGroup in dc.groups) {
16817 if ("string" != typeof sGroup) {
16821 for (i in this.ids[sGroup]) {
16822 var oDD = this.ids[sGroup][i];
16823 if (! this.isTypeOfDD(oDD)) {
16827 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16828 if (this.isOverTarget(pt, oDD, this.mode)) {
16829 // look for drop interactions
16831 dropEvts.push( oDD );
16832 // look for drag enter and drag over interactions
16835 // initial drag over: dragEnter fires
16836 if (!oldOvers[oDD.id]) {
16837 enterEvts.push( oDD );
16838 // subsequent drag overs: dragOver fires
16840 overEvts.push( oDD );
16843 this.dragOvers[oDD.id] = oDD;
16851 if (outEvts.length) {
16852 dc.b4DragOut(e, outEvts);
16853 dc.onDragOut(e, outEvts);
16856 if (enterEvts.length) {
16857 dc.onDragEnter(e, enterEvts);
16860 if (overEvts.length) {
16861 dc.b4DragOver(e, overEvts);
16862 dc.onDragOver(e, overEvts);
16865 if (dropEvts.length) {
16866 dc.b4DragDrop(e, dropEvts);
16867 dc.onDragDrop(e, dropEvts);
16871 // fire dragout events
16873 for (i=0, len=outEvts.length; i<len; ++i) {
16874 dc.b4DragOut(e, outEvts[i].id);
16875 dc.onDragOut(e, outEvts[i].id);
16878 // fire enter events
16879 for (i=0,len=enterEvts.length; i<len; ++i) {
16880 // dc.b4DragEnter(e, oDD.id);
16881 dc.onDragEnter(e, enterEvts[i].id);
16884 // fire over events
16885 for (i=0,len=overEvts.length; i<len; ++i) {
16886 dc.b4DragOver(e, overEvts[i].id);
16887 dc.onDragOver(e, overEvts[i].id);
16890 // fire drop events
16891 for (i=0, len=dropEvts.length; i<len; ++i) {
16892 dc.b4DragDrop(e, dropEvts[i].id);
16893 dc.onDragDrop(e, dropEvts[i].id);
16898 // notify about a drop that did not find a target
16899 if (isDrop && !dropEvts.length) {
16900 dc.onInvalidDrop(e);
16906 * Helper function for getting the best match from the list of drag
16907 * and drop objects returned by the drag and drop events when we are
16908 * in INTERSECT mode. It returns either the first object that the
16909 * cursor is over, or the object that has the greatest overlap with
16910 * the dragged element.
16911 * @method getBestMatch
16912 * @param {DragDrop[]} dds The array of drag and drop objects
16914 * @return {DragDrop} The best single match
16917 getBestMatch: function(dds) {
16919 // Return null if the input is not what we expect
16920 //if (!dds || !dds.length || dds.length == 0) {
16922 // If there is only one item, it wins
16923 //} else if (dds.length == 1) {
16925 var len = dds.length;
16930 // Loop through the targeted items
16931 for (var i=0; i<len; ++i) {
16933 // If the cursor is over the object, it wins. If the
16934 // cursor is over multiple matches, the first one we come
16936 if (dd.cursorIsOver) {
16939 // Otherwise the object with the most overlap wins
16942 winner.overlap.getArea() < dd.overlap.getArea()) {
16953 * Refreshes the cache of the top-left and bottom-right points of the
16954 * drag and drop objects in the specified group(s). This is in the
16955 * format that is stored in the drag and drop instance, so typical
16958 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16962 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16964 * @TODO this really should be an indexed array. Alternatively this
16965 * method could accept both.
16966 * @method refreshCache
16967 * @param {Object} groups an associative array of groups to refresh
16970 refreshCache: function(groups) {
16971 for (var sGroup in groups) {
16972 if ("string" != typeof sGroup) {
16975 for (var i in this.ids[sGroup]) {
16976 var oDD = this.ids[sGroup][i];
16978 if (this.isTypeOfDD(oDD)) {
16979 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16980 var loc = this.getLocation(oDD);
16982 this.locationCache[oDD.id] = loc;
16984 delete this.locationCache[oDD.id];
16985 // this will unregister the drag and drop object if
16986 // the element is not in a usable state
16995 * This checks to make sure an element exists and is in the DOM. The
16996 * main purpose is to handle cases where innerHTML is used to remove
16997 * drag and drop objects from the DOM. IE provides an 'unspecified
16998 * error' when trying to access the offsetParent of such an element
17000 * @param {HTMLElement} el the element to check
17001 * @return {boolean} true if the element looks usable
17004 verifyEl: function(el) {
17009 parent = el.offsetParent;
17012 parent = el.offsetParent;
17023 * Returns a Region object containing the drag and drop element's position
17024 * and size, including the padding configured for it
17025 * @method getLocation
17026 * @param {DragDrop} oDD the drag and drop object to get the
17028 * @return {Roo.lib.Region} a Region object representing the total area
17029 * the element occupies, including any padding
17030 * the instance is configured for.
17033 getLocation: function(oDD) {
17034 if (! this.isTypeOfDD(oDD)) {
17038 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17041 pos= Roo.lib.Dom.getXY(el);
17049 x2 = x1 + el.offsetWidth;
17051 y2 = y1 + el.offsetHeight;
17053 t = y1 - oDD.padding[0];
17054 r = x2 + oDD.padding[1];
17055 b = y2 + oDD.padding[2];
17056 l = x1 - oDD.padding[3];
17058 return new Roo.lib.Region( t, r, b, l );
17062 * Checks the cursor location to see if it over the target
17063 * @method isOverTarget
17064 * @param {Roo.lib.Point} pt The point to evaluate
17065 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17066 * @return {boolean} true if the mouse is over the target
17070 isOverTarget: function(pt, oTarget, intersect) {
17071 // use cache if available
17072 var loc = this.locationCache[oTarget.id];
17073 if (!loc || !this.useCache) {
17074 loc = this.getLocation(oTarget);
17075 this.locationCache[oTarget.id] = loc;
17083 oTarget.cursorIsOver = loc.contains( pt );
17085 // DragDrop is using this as a sanity check for the initial mousedown
17086 // in this case we are done. In POINT mode, if the drag obj has no
17087 // contraints, we are also done. Otherwise we need to evaluate the
17088 // location of the target as related to the actual location of the
17089 // dragged element.
17090 var dc = this.dragCurrent;
17091 if (!dc || !dc.getTargetCoord ||
17092 (!intersect && !dc.constrainX && !dc.constrainY)) {
17093 return oTarget.cursorIsOver;
17096 oTarget.overlap = null;
17098 // Get the current location of the drag element, this is the
17099 // location of the mouse event less the delta that represents
17100 // where the original mousedown happened on the element. We
17101 // need to consider constraints and ticks as well.
17102 var pos = dc.getTargetCoord(pt.x, pt.y);
17104 var el = dc.getDragEl();
17105 var curRegion = new Roo.lib.Region( pos.y,
17106 pos.x + el.offsetWidth,
17107 pos.y + el.offsetHeight,
17110 var overlap = curRegion.intersect(loc);
17113 oTarget.overlap = overlap;
17114 return (intersect) ? true : oTarget.cursorIsOver;
17121 * unload event handler
17122 * @method _onUnload
17126 _onUnload: function(e, me) {
17127 Roo.dd.DragDropMgr.unregAll();
17131 * Cleans up the drag and drop events and objects.
17136 unregAll: function() {
17138 if (this.dragCurrent) {
17140 this.dragCurrent = null;
17143 this._execOnAll("unreg", []);
17145 for (i in this.elementCache) {
17146 delete this.elementCache[i];
17149 this.elementCache = {};
17154 * A cache of DOM elements
17155 * @property elementCache
17162 * Get the wrapper for the DOM element specified
17163 * @method getElWrapper
17164 * @param {String} id the id of the element to get
17165 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17167 * @deprecated This wrapper isn't that useful
17170 getElWrapper: function(id) {
17171 var oWrapper = this.elementCache[id];
17172 if (!oWrapper || !oWrapper.el) {
17173 oWrapper = this.elementCache[id] =
17174 new this.ElementWrapper(Roo.getDom(id));
17180 * Returns the actual DOM element
17181 * @method getElement
17182 * @param {String} id the id of the elment to get
17183 * @return {Object} The element
17184 * @deprecated use Roo.getDom instead
17187 getElement: function(id) {
17188 return Roo.getDom(id);
17192 * Returns the style property for the DOM element (i.e.,
17193 * document.getElById(id).style)
17195 * @param {String} id the id of the elment to get
17196 * @return {Object} The style property of the element
17197 * @deprecated use Roo.getDom instead
17200 getCss: function(id) {
17201 var el = Roo.getDom(id);
17202 return (el) ? el.style : null;
17206 * Inner class for cached elements
17207 * @class DragDropMgr.ElementWrapper
17212 ElementWrapper: function(el) {
17217 this.el = el || null;
17222 this.id = this.el && el.id;
17224 * A reference to the style property
17227 this.css = this.el && el.style;
17231 * Returns the X position of an html element
17233 * @param el the element for which to get the position
17234 * @return {int} the X coordinate
17236 * @deprecated use Roo.lib.Dom.getX instead
17239 getPosX: function(el) {
17240 return Roo.lib.Dom.getX(el);
17244 * Returns the Y position of an html element
17246 * @param el the element for which to get the position
17247 * @return {int} the Y coordinate
17248 * @deprecated use Roo.lib.Dom.getY instead
17251 getPosY: function(el) {
17252 return Roo.lib.Dom.getY(el);
17256 * Swap two nodes. In IE, we use the native method, for others we
17257 * emulate the IE behavior
17259 * @param n1 the first node to swap
17260 * @param n2 the other node to swap
17263 swapNode: function(n1, n2) {
17267 var p = n2.parentNode;
17268 var s = n2.nextSibling;
17271 p.insertBefore(n1, n2);
17272 } else if (n2 == n1.nextSibling) {
17273 p.insertBefore(n2, n1);
17275 n1.parentNode.replaceChild(n2, n1);
17276 p.insertBefore(n1, s);
17282 * Returns the current scroll position
17283 * @method getScroll
17287 getScroll: function () {
17288 var t, l, dde=document.documentElement, db=document.body;
17289 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17291 l = dde.scrollLeft;
17298 return { top: t, left: l };
17302 * Returns the specified element style property
17304 * @param {HTMLElement} el the element
17305 * @param {string} styleProp the style property
17306 * @return {string} The value of the style property
17307 * @deprecated use Roo.lib.Dom.getStyle
17310 getStyle: function(el, styleProp) {
17311 return Roo.fly(el).getStyle(styleProp);
17315 * Gets the scrollTop
17316 * @method getScrollTop
17317 * @return {int} the document's scrollTop
17320 getScrollTop: function () { return this.getScroll().top; },
17323 * Gets the scrollLeft
17324 * @method getScrollLeft
17325 * @return {int} the document's scrollTop
17328 getScrollLeft: function () { return this.getScroll().left; },
17331 * Sets the x/y position of an element to the location of the
17334 * @param {HTMLElement} moveEl The element to move
17335 * @param {HTMLElement} targetEl The position reference element
17338 moveToEl: function (moveEl, targetEl) {
17339 var aCoord = Roo.lib.Dom.getXY(targetEl);
17340 Roo.lib.Dom.setXY(moveEl, aCoord);
17344 * Numeric array sort function
17345 * @method numericSort
17348 numericSort: function(a, b) { return (a - b); },
17352 * @property _timeoutCount
17359 * Trying to make the load order less important. Without this we get
17360 * an error if this file is loaded before the Event Utility.
17361 * @method _addListeners
17365 _addListeners: function() {
17366 var DDM = Roo.dd.DDM;
17367 if ( Roo.lib.Event && document ) {
17370 if (DDM._timeoutCount > 2000) {
17372 setTimeout(DDM._addListeners, 10);
17373 if (document && document.body) {
17374 DDM._timeoutCount += 1;
17381 * Recursively searches the immediate parent and all child nodes for
17382 * the handle element in order to determine wheter or not it was
17384 * @method handleWasClicked
17385 * @param node the html element to inspect
17388 handleWasClicked: function(node, id) {
17389 if (this.isHandle(id, node.id)) {
17392 // check to see if this is a text node child of the one we want
17393 var p = node.parentNode;
17396 if (this.isHandle(id, p.id)) {
17411 // shorter alias, save a few bytes
17412 Roo.dd.DDM = Roo.dd.DragDropMgr;
17413 Roo.dd.DDM._addListeners();
17417 * Ext JS Library 1.1.1
17418 * Copyright(c) 2006-2007, Ext JS, LLC.
17420 * Originally Released Under LGPL - original licence link has changed is not relivant.
17423 * <script type="text/javascript">
17428 * A DragDrop implementation where the linked element follows the
17429 * mouse cursor during a drag.
17430 * @extends Roo.dd.DragDrop
17432 * @param {String} id the id of the linked element
17433 * @param {String} sGroup the group of related DragDrop items
17434 * @param {object} config an object containing configurable attributes
17435 * Valid properties for DD:
17438 Roo.dd.DD = function(id, sGroup, config) {
17440 this.init(id, sGroup, config);
17444 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17447 * When set to true, the utility automatically tries to scroll the browser
17448 * window wehn a drag and drop element is dragged near the viewport boundary.
17449 * Defaults to true.
17456 * Sets the pointer offset to the distance between the linked element's top
17457 * left corner and the location the element was clicked
17458 * @method autoOffset
17459 * @param {int} iPageX the X coordinate of the click
17460 * @param {int} iPageY the Y coordinate of the click
17462 autoOffset: function(iPageX, iPageY) {
17463 var x = iPageX - this.startPageX;
17464 var y = iPageY - this.startPageY;
17465 this.setDelta(x, y);
17469 * Sets the pointer offset. You can call this directly to force the
17470 * offset to be in a particular location (e.g., pass in 0,0 to set it
17471 * to the center of the object)
17473 * @param {int} iDeltaX the distance from the left
17474 * @param {int} iDeltaY the distance from the top
17476 setDelta: function(iDeltaX, iDeltaY) {
17477 this.deltaX = iDeltaX;
17478 this.deltaY = iDeltaY;
17482 * Sets the drag element to the location of the mousedown or click event,
17483 * maintaining the cursor location relative to the location on the element
17484 * that was clicked. Override this if you want to place the element in a
17485 * location other than where the cursor is.
17486 * @method setDragElPos
17487 * @param {int} iPageX the X coordinate of the mousedown or drag event
17488 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17490 setDragElPos: function(iPageX, iPageY) {
17491 // the first time we do this, we are going to check to make sure
17492 // the element has css positioning
17494 var el = this.getDragEl();
17495 this.alignElWithMouse(el, iPageX, iPageY);
17499 * Sets the element to the location of the mousedown or click event,
17500 * maintaining the cursor location relative to the location on the element
17501 * that was clicked. Override this if you want to place the element in a
17502 * location other than where the cursor is.
17503 * @method alignElWithMouse
17504 * @param {HTMLElement} el the element to move
17505 * @param {int} iPageX the X coordinate of the mousedown or drag event
17506 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17508 alignElWithMouse: function(el, iPageX, iPageY) {
17509 var oCoord = this.getTargetCoord(iPageX, iPageY);
17510 var fly = el.dom ? el : Roo.fly(el);
17511 if (!this.deltaSetXY) {
17512 var aCoord = [oCoord.x, oCoord.y];
17514 var newLeft = fly.getLeft(true);
17515 var newTop = fly.getTop(true);
17516 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17518 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17521 this.cachePosition(oCoord.x, oCoord.y);
17522 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17527 * Saves the most recent position so that we can reset the constraints and
17528 * tick marks on-demand. We need to know this so that we can calculate the
17529 * number of pixels the element is offset from its original position.
17530 * @method cachePosition
17531 * @param iPageX the current x position (optional, this just makes it so we
17532 * don't have to look it up again)
17533 * @param iPageY the current y position (optional, this just makes it so we
17534 * don't have to look it up again)
17536 cachePosition: function(iPageX, iPageY) {
17538 this.lastPageX = iPageX;
17539 this.lastPageY = iPageY;
17541 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17542 this.lastPageX = aCoord[0];
17543 this.lastPageY = aCoord[1];
17548 * Auto-scroll the window if the dragged object has been moved beyond the
17549 * visible window boundary.
17550 * @method autoScroll
17551 * @param {int} x the drag element's x position
17552 * @param {int} y the drag element's y position
17553 * @param {int} h the height of the drag element
17554 * @param {int} w the width of the drag element
17557 autoScroll: function(x, y, h, w) {
17560 // The client height
17561 var clientH = Roo.lib.Dom.getViewWidth();
17563 // The client width
17564 var clientW = Roo.lib.Dom.getViewHeight();
17566 // The amt scrolled down
17567 var st = this.DDM.getScrollTop();
17569 // The amt scrolled right
17570 var sl = this.DDM.getScrollLeft();
17572 // Location of the bottom of the element
17575 // Location of the right of the element
17578 // The distance from the cursor to the bottom of the visible area,
17579 // adjusted so that we don't scroll if the cursor is beyond the
17580 // element drag constraints
17581 var toBot = (clientH + st - y - this.deltaY);
17583 // The distance from the cursor to the right of the visible area
17584 var toRight = (clientW + sl - x - this.deltaX);
17587 // How close to the edge the cursor must be before we scroll
17588 // var thresh = (document.all) ? 100 : 40;
17591 // How many pixels to scroll per autoscroll op. This helps to reduce
17592 // clunky scrolling. IE is more sensitive about this ... it needs this
17593 // value to be higher.
17594 var scrAmt = (document.all) ? 80 : 30;
17596 // Scroll down if we are near the bottom of the visible page and the
17597 // obj extends below the crease
17598 if ( bot > clientH && toBot < thresh ) {
17599 window.scrollTo(sl, st + scrAmt);
17602 // Scroll up if the window is scrolled down and the top of the object
17603 // goes above the top border
17604 if ( y < st && st > 0 && y - st < thresh ) {
17605 window.scrollTo(sl, st - scrAmt);
17608 // Scroll right if the obj is beyond the right border and the cursor is
17609 // near the border.
17610 if ( right > clientW && toRight < thresh ) {
17611 window.scrollTo(sl + scrAmt, st);
17614 // Scroll left if the window has been scrolled to the right and the obj
17615 // extends past the left border
17616 if ( x < sl && sl > 0 && x - sl < thresh ) {
17617 window.scrollTo(sl - scrAmt, st);
17623 * Finds the location the element should be placed if we want to move
17624 * it to where the mouse location less the click offset would place us.
17625 * @method getTargetCoord
17626 * @param {int} iPageX the X coordinate of the click
17627 * @param {int} iPageY the Y coordinate of the click
17628 * @return an object that contains the coordinates (Object.x and Object.y)
17631 getTargetCoord: function(iPageX, iPageY) {
17634 var x = iPageX - this.deltaX;
17635 var y = iPageY - this.deltaY;
17637 if (this.constrainX) {
17638 if (x < this.minX) { x = this.minX; }
17639 if (x > this.maxX) { x = this.maxX; }
17642 if (this.constrainY) {
17643 if (y < this.minY) { y = this.minY; }
17644 if (y > this.maxY) { y = this.maxY; }
17647 x = this.getTick(x, this.xTicks);
17648 y = this.getTick(y, this.yTicks);
17655 * Sets up config options specific to this class. Overrides
17656 * Roo.dd.DragDrop, but all versions of this method through the
17657 * inheritance chain are called
17659 applyConfig: function() {
17660 Roo.dd.DD.superclass.applyConfig.call(this);
17661 this.scroll = (this.config.scroll !== false);
17665 * Event that fires prior to the onMouseDown event. Overrides
17668 b4MouseDown: function(e) {
17669 // this.resetConstraints();
17670 this.autoOffset(e.getPageX(),
17675 * Event that fires prior to the onDrag event. Overrides
17678 b4Drag: function(e) {
17679 this.setDragElPos(e.getPageX(),
17683 toString: function() {
17684 return ("DD " + this.id);
17687 //////////////////////////////////////////////////////////////////////////
17688 // Debugging ygDragDrop events that can be overridden
17689 //////////////////////////////////////////////////////////////////////////
17691 startDrag: function(x, y) {
17694 onDrag: function(e) {
17697 onDragEnter: function(e, id) {
17700 onDragOver: function(e, id) {
17703 onDragOut: function(e, id) {
17706 onDragDrop: function(e, id) {
17709 endDrag: function(e) {
17716 * Ext JS Library 1.1.1
17717 * Copyright(c) 2006-2007, Ext JS, LLC.
17719 * Originally Released Under LGPL - original licence link has changed is not relivant.
17722 * <script type="text/javascript">
17726 * @class Roo.dd.DDProxy
17727 * A DragDrop implementation that inserts an empty, bordered div into
17728 * the document that follows the cursor during drag operations. At the time of
17729 * the click, the frame div is resized to the dimensions of the linked html
17730 * element, and moved to the exact location of the linked element.
17732 * References to the "frame" element refer to the single proxy element that
17733 * was created to be dragged in place of all DDProxy elements on the
17736 * @extends Roo.dd.DD
17738 * @param {String} id the id of the linked html element
17739 * @param {String} sGroup the group of related DragDrop objects
17740 * @param {object} config an object containing configurable attributes
17741 * Valid properties for DDProxy in addition to those in DragDrop:
17742 * resizeFrame, centerFrame, dragElId
17744 Roo.dd.DDProxy = function(id, sGroup, config) {
17746 this.init(id, sGroup, config);
17752 * The default drag frame div id
17753 * @property Roo.dd.DDProxy.dragElId
17757 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17759 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17762 * By default we resize the drag frame to be the same size as the element
17763 * we want to drag (this is to get the frame effect). We can turn it off
17764 * if we want a different behavior.
17765 * @property resizeFrame
17771 * By default the frame is positioned exactly where the drag element is, so
17772 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17773 * you do not have constraints on the obj is to have the drag frame centered
17774 * around the cursor. Set centerFrame to true for this effect.
17775 * @property centerFrame
17778 centerFrame: false,
17781 * Creates the proxy element if it does not yet exist
17782 * @method createFrame
17784 createFrame: function() {
17786 var body = document.body;
17788 if (!body || !body.firstChild) {
17789 setTimeout( function() { self.createFrame(); }, 50 );
17793 var div = this.getDragEl();
17796 div = document.createElement("div");
17797 div.id = this.dragElId;
17800 s.position = "absolute";
17801 s.visibility = "hidden";
17803 s.border = "2px solid #aaa";
17806 // appendChild can blow up IE if invoked prior to the window load event
17807 // while rendering a table. It is possible there are other scenarios
17808 // that would cause this to happen as well.
17809 body.insertBefore(div, body.firstChild);
17814 * Initialization for the drag frame element. Must be called in the
17815 * constructor of all subclasses
17816 * @method initFrame
17818 initFrame: function() {
17819 this.createFrame();
17822 applyConfig: function() {
17823 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17825 this.resizeFrame = (this.config.resizeFrame !== false);
17826 this.centerFrame = (this.config.centerFrame);
17827 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17831 * Resizes the drag frame to the dimensions of the clicked object, positions
17832 * it over the object, and finally displays it
17833 * @method showFrame
17834 * @param {int} iPageX X click position
17835 * @param {int} iPageY Y click position
17838 showFrame: function(iPageX, iPageY) {
17839 var el = this.getEl();
17840 var dragEl = this.getDragEl();
17841 var s = dragEl.style;
17843 this._resizeProxy();
17845 if (this.centerFrame) {
17846 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17847 Math.round(parseInt(s.height, 10)/2) );
17850 this.setDragElPos(iPageX, iPageY);
17852 Roo.fly(dragEl).show();
17856 * The proxy is automatically resized to the dimensions of the linked
17857 * element when a drag is initiated, unless resizeFrame is set to false
17858 * @method _resizeProxy
17861 _resizeProxy: function() {
17862 if (this.resizeFrame) {
17863 var el = this.getEl();
17864 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17868 // overrides Roo.dd.DragDrop
17869 b4MouseDown: function(e) {
17870 var x = e.getPageX();
17871 var y = e.getPageY();
17872 this.autoOffset(x, y);
17873 this.setDragElPos(x, y);
17876 // overrides Roo.dd.DragDrop
17877 b4StartDrag: function(x, y) {
17878 // show the drag frame
17879 this.showFrame(x, y);
17882 // overrides Roo.dd.DragDrop
17883 b4EndDrag: function(e) {
17884 Roo.fly(this.getDragEl()).hide();
17887 // overrides Roo.dd.DragDrop
17888 // By default we try to move the element to the last location of the frame.
17889 // This is so that the default behavior mirrors that of Roo.dd.DD.
17890 endDrag: function(e) {
17892 var lel = this.getEl();
17893 var del = this.getDragEl();
17895 // Show the drag frame briefly so we can get its position
17896 del.style.visibility = "";
17899 // Hide the linked element before the move to get around a Safari
17901 lel.style.visibility = "hidden";
17902 Roo.dd.DDM.moveToEl(lel, del);
17903 del.style.visibility = "hidden";
17904 lel.style.visibility = "";
17909 beforeMove : function(){
17913 afterDrag : function(){
17917 toString: function() {
17918 return ("DDProxy " + this.id);
17924 * Ext JS Library 1.1.1
17925 * Copyright(c) 2006-2007, Ext JS, LLC.
17927 * Originally Released Under LGPL - original licence link has changed is not relivant.
17930 * <script type="text/javascript">
17934 * @class Roo.dd.DDTarget
17935 * A DragDrop implementation that does not move, but can be a drop
17936 * target. You would get the same result by simply omitting implementation
17937 * for the event callbacks, but this way we reduce the processing cost of the
17938 * event listener and the callbacks.
17939 * @extends Roo.dd.DragDrop
17941 * @param {String} id the id of the element that is a drop target
17942 * @param {String} sGroup the group of related DragDrop objects
17943 * @param {object} config an object containing configurable attributes
17944 * Valid properties for DDTarget in addition to those in
17948 Roo.dd.DDTarget = function(id, sGroup, config) {
17950 this.initTarget(id, sGroup, config);
17952 if (config.listeners || config.events) {
17953 Roo.dd.DragDrop.superclass.constructor.call(this, {
17954 listeners : config.listeners || {},
17955 events : config.events || {}
17960 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17961 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17962 toString: function() {
17963 return ("DDTarget " + this.id);
17968 * Ext JS Library 1.1.1
17969 * Copyright(c) 2006-2007, Ext JS, LLC.
17971 * Originally Released Under LGPL - original licence link has changed is not relivant.
17974 * <script type="text/javascript">
17979 * @class Roo.dd.ScrollManager
17980 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17981 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17984 Roo.dd.ScrollManager = function(){
17985 var ddm = Roo.dd.DragDropMgr;
17992 var onStop = function(e){
17997 var triggerRefresh = function(){
17998 if(ddm.dragCurrent){
17999 ddm.refreshCache(ddm.dragCurrent.groups);
18003 var doScroll = function(){
18004 if(ddm.dragCurrent){
18005 var dds = Roo.dd.ScrollManager;
18007 if(proc.el.scroll(proc.dir, dds.increment)){
18011 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18016 var clearProc = function(){
18018 clearInterval(proc.id);
18025 var startProc = function(el, dir){
18026 Roo.log('scroll startproc');
18030 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18033 var onFire = function(e, isDrop){
18035 if(isDrop || !ddm.dragCurrent){ return; }
18036 var dds = Roo.dd.ScrollManager;
18037 if(!dragEl || dragEl != ddm.dragCurrent){
18038 dragEl = ddm.dragCurrent;
18039 // refresh regions on drag start
18040 dds.refreshCache();
18043 var xy = Roo.lib.Event.getXY(e);
18044 var pt = new Roo.lib.Point(xy[0], xy[1]);
18045 for(var id in els){
18046 var el = els[id], r = el._region;
18047 if(r && r.contains(pt) && el.isScrollable()){
18048 if(r.bottom - pt.y <= dds.thresh){
18050 startProc(el, "down");
18053 }else if(r.right - pt.x <= dds.thresh){
18055 startProc(el, "left");
18058 }else if(pt.y - r.top <= dds.thresh){
18060 startProc(el, "up");
18063 }else if(pt.x - r.left <= dds.thresh){
18065 startProc(el, "right");
18074 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18075 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18079 * Registers new overflow element(s) to auto scroll
18080 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18082 register : function(el){
18083 if(el instanceof Array){
18084 for(var i = 0, len = el.length; i < len; i++) {
18085 this.register(el[i]);
18091 Roo.dd.ScrollManager.els = els;
18095 * Unregisters overflow element(s) so they are no longer scrolled
18096 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18098 unregister : function(el){
18099 if(el instanceof Array){
18100 for(var i = 0, len = el.length; i < len; i++) {
18101 this.unregister(el[i]);
18110 * The number of pixels from the edge of a container the pointer needs to be to
18111 * trigger scrolling (defaults to 25)
18117 * The number of pixels to scroll in each scroll increment (defaults to 50)
18123 * The frequency of scrolls in milliseconds (defaults to 500)
18129 * True to animate the scroll (defaults to true)
18135 * The animation duration in seconds -
18136 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18142 * Manually trigger a cache refresh.
18144 refreshCache : function(){
18145 for(var id in els){
18146 if(typeof els[id] == 'object'){ // for people extending the object prototype
18147 els[id]._region = els[id].getRegion();
18154 * Ext JS Library 1.1.1
18155 * Copyright(c) 2006-2007, Ext JS, LLC.
18157 * Originally Released Under LGPL - original licence link has changed is not relivant.
18160 * <script type="text/javascript">
18165 * @class Roo.dd.Registry
18166 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18167 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18170 Roo.dd.Registry = function(){
18173 var autoIdSeed = 0;
18175 var getId = function(el, autogen){
18176 if(typeof el == "string"){
18180 if(!id && autogen !== false){
18181 id = "roodd-" + (++autoIdSeed);
18189 * Register a drag drop element
18190 * @param {String|HTMLElement} element The id or DOM node to register
18191 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18192 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18193 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18194 * populated in the data object (if applicable):
18196 Value Description<br />
18197 --------- ------------------------------------------<br />
18198 handles Array of DOM nodes that trigger dragging<br />
18199 for the element being registered<br />
18200 isHandle True if the element passed in triggers<br />
18201 dragging itself, else false
18204 register : function(el, data){
18206 if(typeof el == "string"){
18207 el = document.getElementById(el);
18210 elements[getId(el)] = data;
18211 if(data.isHandle !== false){
18212 handles[data.ddel.id] = data;
18215 var hs = data.handles;
18216 for(var i = 0, len = hs.length; i < len; i++){
18217 handles[getId(hs[i])] = data;
18223 * Unregister a drag drop element
18224 * @param {String|HTMLElement} element The id or DOM node to unregister
18226 unregister : function(el){
18227 var id = getId(el, false);
18228 var data = elements[id];
18230 delete elements[id];
18232 var hs = data.handles;
18233 for(var i = 0, len = hs.length; i < len; i++){
18234 delete handles[getId(hs[i], false)];
18241 * Returns the handle registered for a DOM Node by id
18242 * @param {String|HTMLElement} id The DOM node or id to look up
18243 * @return {Object} handle The custom handle data
18245 getHandle : function(id){
18246 if(typeof id != "string"){ // must be element?
18249 return handles[id];
18253 * Returns the handle that is registered for the DOM node that is the target of the event
18254 * @param {Event} e The event
18255 * @return {Object} handle The custom handle data
18257 getHandleFromEvent : function(e){
18258 var t = Roo.lib.Event.getTarget(e);
18259 return t ? handles[t.id] : null;
18263 * Returns a custom data object that is registered for a DOM node by id
18264 * @param {String|HTMLElement} id The DOM node or id to look up
18265 * @return {Object} data The custom data
18267 getTarget : function(id){
18268 if(typeof id != "string"){ // must be element?
18271 return elements[id];
18275 * Returns a custom data object that is registered for the DOM node that is the target of the event
18276 * @param {Event} e The event
18277 * @return {Object} data The custom data
18279 getTargetFromEvent : function(e){
18280 var t = Roo.lib.Event.getTarget(e);
18281 return t ? elements[t.id] || handles[t.id] : null;
18286 * Ext JS Library 1.1.1
18287 * Copyright(c) 2006-2007, Ext JS, LLC.
18289 * Originally Released Under LGPL - original licence link has changed is not relivant.
18292 * <script type="text/javascript">
18297 * @class Roo.dd.StatusProxy
18298 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18299 * default drag proxy used by all Roo.dd components.
18301 * @param {Object} config
18303 Roo.dd.StatusProxy = function(config){
18304 Roo.apply(this, config);
18305 this.id = this.id || Roo.id();
18306 this.el = new Roo.Layer({
18308 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18309 {tag: "div", cls: "x-dd-drop-icon"},
18310 {tag: "div", cls: "x-dd-drag-ghost"}
18313 shadow: !config || config.shadow !== false
18315 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18316 this.dropStatus = this.dropNotAllowed;
18319 Roo.dd.StatusProxy.prototype = {
18321 * @cfg {String} dropAllowed
18322 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18324 dropAllowed : "x-dd-drop-ok",
18326 * @cfg {String} dropNotAllowed
18327 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18329 dropNotAllowed : "x-dd-drop-nodrop",
18332 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18333 * over the current target element.
18334 * @param {String} cssClass The css class for the new drop status indicator image
18336 setStatus : function(cssClass){
18337 cssClass = cssClass || this.dropNotAllowed;
18338 if(this.dropStatus != cssClass){
18339 this.el.replaceClass(this.dropStatus, cssClass);
18340 this.dropStatus = cssClass;
18345 * Resets the status indicator to the default dropNotAllowed value
18346 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18348 reset : function(clearGhost){
18349 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18350 this.dropStatus = this.dropNotAllowed;
18352 this.ghost.update("");
18357 * Updates the contents of the ghost element
18358 * @param {String} html The html that will replace the current innerHTML of the ghost element
18360 update : function(html){
18361 if(typeof html == "string"){
18362 this.ghost.update(html);
18364 this.ghost.update("");
18365 html.style.margin = "0";
18366 this.ghost.dom.appendChild(html);
18368 // ensure float = none set?? cant remember why though.
18369 var el = this.ghost.dom.firstChild;
18371 Roo.fly(el).setStyle('float', 'none');
18376 * Returns the underlying proxy {@link Roo.Layer}
18377 * @return {Roo.Layer} el
18379 getEl : function(){
18384 * Returns the ghost element
18385 * @return {Roo.Element} el
18387 getGhost : function(){
18393 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18395 hide : function(clear){
18403 * Stops the repair animation if it's currently running
18406 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18412 * Displays this proxy
18419 * Force the Layer to sync its shadow and shim positions to the element
18426 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18427 * invalid drop operation by the item being dragged.
18428 * @param {Array} xy The XY position of the element ([x, y])
18429 * @param {Function} callback The function to call after the repair is complete
18430 * @param {Object} scope The scope in which to execute the callback
18432 repair : function(xy, callback, scope){
18433 this.callback = callback;
18434 this.scope = scope;
18435 if(xy && this.animRepair !== false){
18436 this.el.addClass("x-dd-drag-repair");
18437 this.el.hideUnders(true);
18438 this.anim = this.el.shift({
18439 duration: this.repairDuration || .5,
18443 callback: this.afterRepair,
18447 this.afterRepair();
18452 afterRepair : function(){
18454 if(typeof this.callback == "function"){
18455 this.callback.call(this.scope || this);
18457 this.callback = null;
18462 * Ext JS Library 1.1.1
18463 * Copyright(c) 2006-2007, Ext JS, LLC.
18465 * Originally Released Under LGPL - original licence link has changed is not relivant.
18468 * <script type="text/javascript">
18472 * @class Roo.dd.DragSource
18473 * @extends Roo.dd.DDProxy
18474 * A simple class that provides the basic implementation needed to make any element draggable.
18476 * @param {String/HTMLElement/Element} el The container element
18477 * @param {Object} config
18479 Roo.dd.DragSource = function(el, config){
18480 this.el = Roo.get(el);
18481 this.dragData = {};
18483 Roo.apply(this, config);
18486 this.proxy = new Roo.dd.StatusProxy();
18489 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18490 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18492 this.dragging = false;
18495 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18497 * @cfg {String} dropAllowed
18498 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18500 dropAllowed : "x-dd-drop-ok",
18502 * @cfg {String} dropNotAllowed
18503 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18505 dropNotAllowed : "x-dd-drop-nodrop",
18508 * Returns the data object associated with this drag source
18509 * @return {Object} data An object containing arbitrary data
18511 getDragData : function(e){
18512 return this.dragData;
18516 onDragEnter : function(e, id){
18517 var target = Roo.dd.DragDropMgr.getDDById(id);
18518 this.cachedTarget = target;
18519 if(this.beforeDragEnter(target, e, id) !== false){
18520 if(target.isNotifyTarget){
18521 var status = target.notifyEnter(this, e, this.dragData);
18522 this.proxy.setStatus(status);
18524 this.proxy.setStatus(this.dropAllowed);
18527 if(this.afterDragEnter){
18529 * An empty function by default, but provided so that you can perform a custom action
18530 * when the dragged item enters the drop target by providing an implementation.
18531 * @param {Roo.dd.DragDrop} target The drop target
18532 * @param {Event} e The event object
18533 * @param {String} id The id of the dragged element
18534 * @method afterDragEnter
18536 this.afterDragEnter(target, e, id);
18542 * An empty function by default, but provided so that you can perform a custom action
18543 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18544 * @param {Roo.dd.DragDrop} target The drop target
18545 * @param {Event} e The event object
18546 * @param {String} id The id of the dragged element
18547 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18549 beforeDragEnter : function(target, e, id){
18554 alignElWithMouse: function() {
18555 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18560 onDragOver : function(e, id){
18561 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18562 if(this.beforeDragOver(target, e, id) !== false){
18563 if(target.isNotifyTarget){
18564 var status = target.notifyOver(this, e, this.dragData);
18565 this.proxy.setStatus(status);
18568 if(this.afterDragOver){
18570 * An empty function by default, but provided so that you can perform a custom action
18571 * while the dragged item is over the drop target by providing an implementation.
18572 * @param {Roo.dd.DragDrop} target The drop target
18573 * @param {Event} e The event object
18574 * @param {String} id The id of the dragged element
18575 * @method afterDragOver
18577 this.afterDragOver(target, e, id);
18583 * An empty function by default, but provided so that you can perform a custom action
18584 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18585 * @param {Roo.dd.DragDrop} target The drop target
18586 * @param {Event} e The event object
18587 * @param {String} id The id of the dragged element
18588 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18590 beforeDragOver : function(target, e, id){
18595 onDragOut : function(e, id){
18596 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18597 if(this.beforeDragOut(target, e, id) !== false){
18598 if(target.isNotifyTarget){
18599 target.notifyOut(this, e, this.dragData);
18601 this.proxy.reset();
18602 if(this.afterDragOut){
18604 * An empty function by default, but provided so that you can perform a custom action
18605 * after the dragged item is dragged out of the target without dropping.
18606 * @param {Roo.dd.DragDrop} target The drop target
18607 * @param {Event} e The event object
18608 * @param {String} id The id of the dragged element
18609 * @method afterDragOut
18611 this.afterDragOut(target, e, id);
18614 this.cachedTarget = null;
18618 * An empty function by default, but provided so that you can perform a custom action before the dragged
18619 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18620 * @param {Roo.dd.DragDrop} target The drop target
18621 * @param {Event} e The event object
18622 * @param {String} id The id of the dragged element
18623 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18625 beforeDragOut : function(target, e, id){
18630 onDragDrop : function(e, id){
18631 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18632 if(this.beforeDragDrop(target, e, id) !== false){
18633 if(target.isNotifyTarget){
18634 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18635 this.onValidDrop(target, e, id);
18637 this.onInvalidDrop(target, e, id);
18640 this.onValidDrop(target, e, id);
18643 if(this.afterDragDrop){
18645 * An empty function by default, but provided so that you can perform a custom action
18646 * after a valid drag drop has occurred by providing an implementation.
18647 * @param {Roo.dd.DragDrop} target The drop target
18648 * @param {Event} e The event object
18649 * @param {String} id The id of the dropped element
18650 * @method afterDragDrop
18652 this.afterDragDrop(target, e, id);
18655 delete this.cachedTarget;
18659 * An empty function by default, but provided so that you can perform a custom action before the dragged
18660 * item is dropped onto the target and optionally cancel the onDragDrop.
18661 * @param {Roo.dd.DragDrop} target The drop target
18662 * @param {Event} e The event object
18663 * @param {String} id The id of the dragged element
18664 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18666 beforeDragDrop : function(target, e, id){
18671 onValidDrop : function(target, e, id){
18673 if(this.afterValidDrop){
18675 * An empty function by default, but provided so that you can perform a custom action
18676 * after a valid drop has occurred by providing an implementation.
18677 * @param {Object} target The target DD
18678 * @param {Event} e The event object
18679 * @param {String} id The id of the dropped element
18680 * @method afterInvalidDrop
18682 this.afterValidDrop(target, e, id);
18687 getRepairXY : function(e, data){
18688 return this.el.getXY();
18692 onInvalidDrop : function(target, e, id){
18693 this.beforeInvalidDrop(target, e, id);
18694 if(this.cachedTarget){
18695 if(this.cachedTarget.isNotifyTarget){
18696 this.cachedTarget.notifyOut(this, e, this.dragData);
18698 this.cacheTarget = null;
18700 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18702 if(this.afterInvalidDrop){
18704 * An empty function by default, but provided so that you can perform a custom action
18705 * after an invalid drop has occurred by providing an implementation.
18706 * @param {Event} e The event object
18707 * @param {String} id The id of the dropped element
18708 * @method afterInvalidDrop
18710 this.afterInvalidDrop(e, id);
18715 afterRepair : function(){
18717 this.el.highlight(this.hlColor || "c3daf9");
18719 this.dragging = false;
18723 * An empty function by default, but provided so that you can perform a custom action after an invalid
18724 * drop has occurred.
18725 * @param {Roo.dd.DragDrop} target The drop target
18726 * @param {Event} e The event object
18727 * @param {String} id The id of the dragged element
18728 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18730 beforeInvalidDrop : function(target, e, id){
18735 handleMouseDown : function(e){
18736 if(this.dragging) {
18739 var data = this.getDragData(e);
18740 if(data && this.onBeforeDrag(data, e) !== false){
18741 this.dragData = data;
18743 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18748 * An empty function by default, but provided so that you can perform a custom action before the initial
18749 * drag event begins and optionally cancel it.
18750 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18751 * @param {Event} e The event object
18752 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18754 onBeforeDrag : function(data, e){
18759 * An empty function by default, but provided so that you can perform a custom action once the initial
18760 * drag event has begun. The drag cannot be canceled from this function.
18761 * @param {Number} x The x position of the click on the dragged object
18762 * @param {Number} y The y position of the click on the dragged object
18764 onStartDrag : Roo.emptyFn,
18766 // private - YUI override
18767 startDrag : function(x, y){
18768 this.proxy.reset();
18769 this.dragging = true;
18770 this.proxy.update("");
18771 this.onInitDrag(x, y);
18776 onInitDrag : function(x, y){
18777 var clone = this.el.dom.cloneNode(true);
18778 clone.id = Roo.id(); // prevent duplicate ids
18779 this.proxy.update(clone);
18780 this.onStartDrag(x, y);
18785 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18786 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18788 getProxy : function(){
18793 * Hides the drag source's {@link Roo.dd.StatusProxy}
18795 hideProxy : function(){
18797 this.proxy.reset(true);
18798 this.dragging = false;
18802 triggerCacheRefresh : function(){
18803 Roo.dd.DDM.refreshCache(this.groups);
18806 // private - override to prevent hiding
18807 b4EndDrag: function(e) {
18810 // private - override to prevent moving
18811 endDrag : function(e){
18812 this.onEndDrag(this.dragData, e);
18816 onEndDrag : function(data, e){
18819 // private - pin to cursor
18820 autoOffset : function(x, y) {
18821 this.setDelta(-12, -20);
18825 * Ext JS Library 1.1.1
18826 * Copyright(c) 2006-2007, Ext JS, LLC.
18828 * Originally Released Under LGPL - original licence link has changed is not relivant.
18831 * <script type="text/javascript">
18836 * @class Roo.dd.DropTarget
18837 * @extends Roo.dd.DDTarget
18838 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18839 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18841 * @param {String/HTMLElement/Element} el The container element
18842 * @param {Object} config
18844 Roo.dd.DropTarget = function(el, config){
18845 this.el = Roo.get(el);
18847 var listeners = false; ;
18848 if (config && config.listeners) {
18849 listeners= config.listeners;
18850 delete config.listeners;
18852 Roo.apply(this, config);
18854 if(this.containerScroll){
18855 Roo.dd.ScrollManager.register(this.el);
18859 * @scope Roo.dd.DropTarget
18864 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18865 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18866 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18868 * IMPORTANT : it should set this.overClass and this.dropAllowed
18870 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18871 * @param {Event} e The event
18872 * @param {Object} data An object containing arbitrary data supplied by the drag source
18878 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18879 * This method will be called on every mouse movement while the drag source is over the drop target.
18880 * This default implementation simply returns the dropAllowed config value.
18882 * IMPORTANT : it should set this.dropAllowed
18884 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18885 * @param {Event} e The event
18886 * @param {Object} data An object containing arbitrary data supplied by the drag source
18892 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18893 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18894 * overClass (if any) from the drop element.
18896 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18897 * @param {Event} e The event
18898 * @param {Object} data An object containing arbitrary data supplied by the drag source
18904 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18905 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18906 * implementation that does something to process the drop event and returns true so that the drag source's
18907 * repair action does not run.
18909 * IMPORTANT : it should set this.success
18911 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18912 * @param {Event} e The event
18913 * @param {Object} data An object containing arbitrary data supplied by the drag source
18919 Roo.dd.DropTarget.superclass.constructor.call( this,
18921 this.ddGroup || this.group,
18924 listeners : listeners || {}
18932 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18934 * @cfg {String} overClass
18935 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18938 * @cfg {String} ddGroup
18939 * The drag drop group to handle drop events for
18943 * @cfg {String} dropAllowed
18944 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18946 dropAllowed : "x-dd-drop-ok",
18948 * @cfg {String} dropNotAllowed
18949 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18951 dropNotAllowed : "x-dd-drop-nodrop",
18953 * @cfg {boolean} success
18954 * set this after drop listener..
18958 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18959 * if the drop point is valid for over/enter..
18966 isNotifyTarget : true,
18971 notifyEnter : function(dd, e, data)
18974 this.fireEvent('enter', dd, e, data);
18975 if(this.overClass){
18976 this.el.addClass(this.overClass);
18978 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18979 this.valid ? this.dropAllowed : this.dropNotAllowed
18986 notifyOver : function(dd, e, data)
18989 this.fireEvent('over', dd, e, data);
18990 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18991 this.valid ? this.dropAllowed : this.dropNotAllowed
18998 notifyOut : function(dd, e, data)
19000 this.fireEvent('out', dd, e, data);
19001 if(this.overClass){
19002 this.el.removeClass(this.overClass);
19009 notifyDrop : function(dd, e, data)
19011 this.success = false;
19012 this.fireEvent('drop', dd, e, data);
19013 return this.success;
19017 * Ext JS Library 1.1.1
19018 * Copyright(c) 2006-2007, Ext JS, LLC.
19020 * Originally Released Under LGPL - original licence link has changed is not relivant.
19023 * <script type="text/javascript">
19028 * @class Roo.dd.DragZone
19029 * @extends Roo.dd.DragSource
19030 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19031 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19033 * @param {String/HTMLElement/Element} el The container element
19034 * @param {Object} config
19036 Roo.dd.DragZone = function(el, config){
19037 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19038 if(this.containerScroll){
19039 Roo.dd.ScrollManager.register(this.el);
19043 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19045 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19046 * for auto scrolling during drag operations.
19049 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19050 * method after a failed drop (defaults to "c3daf9" - light blue)
19054 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19055 * for a valid target to drag based on the mouse down. Override this method
19056 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19057 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19058 * @param {EventObject} e The mouse down event
19059 * @return {Object} The dragData
19061 getDragData : function(e){
19062 return Roo.dd.Registry.getHandleFromEvent(e);
19066 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19067 * this.dragData.ddel
19068 * @param {Number} x The x position of the click on the dragged object
19069 * @param {Number} y The y position of the click on the dragged object
19070 * @return {Boolean} true to continue the drag, false to cancel
19072 onInitDrag : function(x, y){
19073 this.proxy.update(this.dragData.ddel.cloneNode(true));
19074 this.onStartDrag(x, y);
19079 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19081 afterRepair : function(){
19083 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19085 this.dragging = false;
19089 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19090 * the XY of this.dragData.ddel
19091 * @param {EventObject} e The mouse up event
19092 * @return {Array} The xy location (e.g. [100, 200])
19094 getRepairXY : function(e){
19095 return Roo.Element.fly(this.dragData.ddel).getXY();
19099 * Ext JS Library 1.1.1
19100 * Copyright(c) 2006-2007, Ext JS, LLC.
19102 * Originally Released Under LGPL - original licence link has changed is not relivant.
19105 * <script type="text/javascript">
19108 * @class Roo.dd.DropZone
19109 * @extends Roo.dd.DropTarget
19110 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19111 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19113 * @param {String/HTMLElement/Element} el The container element
19114 * @param {Object} config
19116 Roo.dd.DropZone = function(el, config){
19117 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19120 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19122 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19123 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19124 * provide your own custom lookup.
19125 * @param {Event} e The event
19126 * @return {Object} data The custom data
19128 getTargetFromEvent : function(e){
19129 return Roo.dd.Registry.getTargetFromEvent(e);
19133 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19134 * that it has registered. This method has no default implementation and should be overridden to provide
19135 * node-specific processing if necessary.
19136 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19137 * {@link #getTargetFromEvent} for this node)
19138 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19139 * @param {Event} e The event
19140 * @param {Object} data An object containing arbitrary data supplied by the drag source
19142 onNodeEnter : function(n, dd, e, data){
19147 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19148 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19149 * overridden to provide the proper feedback.
19150 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19151 * {@link #getTargetFromEvent} for this node)
19152 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19153 * @param {Event} e The event
19154 * @param {Object} data An object containing arbitrary data supplied by the drag source
19155 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19156 * underlying {@link Roo.dd.StatusProxy} can be updated
19158 onNodeOver : function(n, dd, e, data){
19159 return this.dropAllowed;
19163 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19164 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19165 * node-specific processing if necessary.
19166 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19167 * {@link #getTargetFromEvent} for this node)
19168 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19169 * @param {Event} e The event
19170 * @param {Object} data An object containing arbitrary data supplied by the drag source
19172 onNodeOut : function(n, dd, e, data){
19177 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19178 * the drop node. The default implementation returns false, so it should be overridden to provide the
19179 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19180 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19181 * {@link #getTargetFromEvent} for this node)
19182 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19183 * @param {Event} e The event
19184 * @param {Object} data An object containing arbitrary data supplied by the drag source
19185 * @return {Boolean} True if the drop was valid, else false
19187 onNodeDrop : function(n, dd, e, data){
19192 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19193 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19194 * it should be overridden to provide the proper feedback if necessary.
19195 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19196 * @param {Event} e The event
19197 * @param {Object} data An object containing arbitrary data supplied by the drag source
19198 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19199 * underlying {@link Roo.dd.StatusProxy} can be updated
19201 onContainerOver : function(dd, e, data){
19202 return this.dropNotAllowed;
19206 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19207 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19208 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19209 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19210 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19211 * @param {Event} e The event
19212 * @param {Object} data An object containing arbitrary data supplied by the drag source
19213 * @return {Boolean} True if the drop was valid, else false
19215 onContainerDrop : function(dd, e, data){
19220 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19221 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19222 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19223 * you should override this method and provide a custom implementation.
19224 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19225 * @param {Event} e The event
19226 * @param {Object} data An object containing arbitrary data supplied by the drag source
19227 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19228 * underlying {@link Roo.dd.StatusProxy} can be updated
19230 notifyEnter : function(dd, e, data){
19231 return this.dropNotAllowed;
19235 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19236 * This method will be called on every mouse movement while the drag source is over the drop zone.
19237 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19238 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19239 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19240 * registered node, it will call {@link #onContainerOver}.
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 notifyOver : function(dd, e, data){
19248 var n = this.getTargetFromEvent(e);
19249 if(!n){ // not over valid drop target
19250 if(this.lastOverNode){
19251 this.onNodeOut(this.lastOverNode, dd, e, data);
19252 this.lastOverNode = null;
19254 return this.onContainerOver(dd, e, data);
19256 if(this.lastOverNode != n){
19257 if(this.lastOverNode){
19258 this.onNodeOut(this.lastOverNode, dd, e, data);
19260 this.onNodeEnter(n, dd, e, data);
19261 this.lastOverNode = n;
19263 return this.onNodeOver(n, dd, e, data);
19267 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19268 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19269 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19270 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19271 * @param {Event} e The event
19272 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19274 notifyOut : function(dd, e, data){
19275 if(this.lastOverNode){
19276 this.onNodeOut(this.lastOverNode, dd, e, data);
19277 this.lastOverNode = null;
19282 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19283 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19284 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19285 * otherwise it will call {@link #onContainerDrop}.
19286 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19287 * @param {Event} e The event
19288 * @param {Object} data An object containing arbitrary data supplied by the drag source
19289 * @return {Boolean} True if the drop was valid, else false
19291 notifyDrop : function(dd, e, data){
19292 if(this.lastOverNode){
19293 this.onNodeOut(this.lastOverNode, dd, e, data);
19294 this.lastOverNode = null;
19296 var n = this.getTargetFromEvent(e);
19298 this.onNodeDrop(n, dd, e, data) :
19299 this.onContainerDrop(dd, e, data);
19303 triggerCacheRefresh : function(){
19304 Roo.dd.DDM.refreshCache(this.groups);
19308 * Ext JS Library 1.1.1
19309 * Copyright(c) 2006-2007, Ext JS, LLC.
19311 * Originally Released Under LGPL - original licence link has changed is not relivant.
19314 * <script type="text/javascript">
19319 * @class Roo.data.SortTypes
19321 * Defines the default sorting (casting?) comparison functions used when sorting data.
19323 Roo.data.SortTypes = {
19325 * Default sort that does nothing
19326 * @param {Mixed} s The value being converted
19327 * @return {Mixed} The comparison value
19329 none : function(s){
19334 * The regular expression used to strip tags
19338 stripTagsRE : /<\/?[^>]+>/gi,
19341 * Strips all HTML tags to sort on text only
19342 * @param {Mixed} s The value being converted
19343 * @return {String} The comparison value
19345 asText : function(s){
19346 return String(s).replace(this.stripTagsRE, "");
19350 * Strips all HTML tags to sort on text only - Case insensitive
19351 * @param {Mixed} s The value being converted
19352 * @return {String} The comparison value
19354 asUCText : function(s){
19355 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19359 * Case insensitive string
19360 * @param {Mixed} s The value being converted
19361 * @return {String} The comparison value
19363 asUCString : function(s) {
19364 return String(s).toUpperCase();
19369 * @param {Mixed} s The value being converted
19370 * @return {Number} The comparison value
19372 asDate : function(s) {
19376 if(s instanceof Date){
19377 return s.getTime();
19379 return Date.parse(String(s));
19384 * @param {Mixed} s The value being converted
19385 * @return {Float} The comparison value
19387 asFloat : function(s) {
19388 var val = parseFloat(String(s).replace(/,/g, ""));
19389 if(isNaN(val)) val = 0;
19395 * @param {Mixed} s The value being converted
19396 * @return {Number} The comparison value
19398 asInt : function(s) {
19399 var val = parseInt(String(s).replace(/,/g, ""));
19400 if(isNaN(val)) val = 0;
19405 * Ext JS Library 1.1.1
19406 * Copyright(c) 2006-2007, Ext JS, LLC.
19408 * Originally Released Under LGPL - original licence link has changed is not relivant.
19411 * <script type="text/javascript">
19415 * @class Roo.data.Record
19416 * Instances of this class encapsulate both record <em>definition</em> information, and record
19417 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19418 * to access Records cached in an {@link Roo.data.Store} object.<br>
19420 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19421 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19424 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19426 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19427 * {@link #create}. The parameters are the same.
19428 * @param {Array} data An associative Array of data values keyed by the field name.
19429 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19430 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19431 * not specified an integer id is generated.
19433 Roo.data.Record = function(data, id){
19434 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19439 * Generate a constructor for a specific record layout.
19440 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19441 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19442 * Each field definition object may contain the following properties: <ul>
19443 * <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,
19444 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19445 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19446 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19447 * is being used, then this is a string containing the javascript expression to reference the data relative to
19448 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19449 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19450 * this may be omitted.</p></li>
19451 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19452 * <ul><li>auto (Default, implies no conversion)</li>
19457 * <li>date</li></ul></p></li>
19458 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19459 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19460 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19461 * by the Reader into an object that will be stored in the Record. It is passed the
19462 * following parameters:<ul>
19463 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19465 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19467 * <br>usage:<br><pre><code>
19468 var TopicRecord = Roo.data.Record.create(
19469 {name: 'title', mapping: 'topic_title'},
19470 {name: 'author', mapping: 'username'},
19471 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19472 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19473 {name: 'lastPoster', mapping: 'user2'},
19474 {name: 'excerpt', mapping: 'post_text'}
19477 var myNewRecord = new TopicRecord({
19478 title: 'Do my job please',
19481 lastPost: new Date(),
19482 lastPoster: 'Animal',
19483 excerpt: 'No way dude!'
19485 myStore.add(myNewRecord);
19490 Roo.data.Record.create = function(o){
19491 var f = function(){
19492 f.superclass.constructor.apply(this, arguments);
19494 Roo.extend(f, Roo.data.Record);
19495 var p = f.prototype;
19496 p.fields = new Roo.util.MixedCollection(false, function(field){
19499 for(var i = 0, len = o.length; i < len; i++){
19500 p.fields.add(new Roo.data.Field(o[i]));
19502 f.getField = function(name){
19503 return p.fields.get(name);
19508 Roo.data.Record.AUTO_ID = 1000;
19509 Roo.data.Record.EDIT = 'edit';
19510 Roo.data.Record.REJECT = 'reject';
19511 Roo.data.Record.COMMIT = 'commit';
19513 Roo.data.Record.prototype = {
19515 * Readonly flag - true if this record has been modified.
19524 join : function(store){
19525 this.store = store;
19529 * Set the named field to the specified value.
19530 * @param {String} name The name of the field to set.
19531 * @param {Object} value The value to set the field to.
19533 set : function(name, value){
19534 if(this.data[name] == value){
19538 if(!this.modified){
19539 this.modified = {};
19541 if(typeof this.modified[name] == 'undefined'){
19542 this.modified[name] = this.data[name];
19544 this.data[name] = value;
19545 if(!this.editing && this.store){
19546 this.store.afterEdit(this);
19551 * Get the value of the named field.
19552 * @param {String} name The name of the field to get the value of.
19553 * @return {Object} The value of the field.
19555 get : function(name){
19556 return this.data[name];
19560 beginEdit : function(){
19561 this.editing = true;
19562 this.modified = {};
19566 cancelEdit : function(){
19567 this.editing = false;
19568 delete this.modified;
19572 endEdit : function(){
19573 this.editing = false;
19574 if(this.dirty && this.store){
19575 this.store.afterEdit(this);
19580 * Usually called by the {@link Roo.data.Store} which owns the Record.
19581 * Rejects all changes made to the Record since either creation, or the last commit operation.
19582 * Modified fields are reverted to their original values.
19584 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19585 * of reject operations.
19587 reject : function(){
19588 var m = this.modified;
19590 if(typeof m[n] != "function"){
19591 this.data[n] = m[n];
19594 this.dirty = false;
19595 delete this.modified;
19596 this.editing = false;
19598 this.store.afterReject(this);
19603 * Usually called by the {@link Roo.data.Store} which owns the Record.
19604 * Commits all changes made to the Record since either creation, or the last commit operation.
19606 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19607 * of commit operations.
19609 commit : function(){
19610 this.dirty = false;
19611 delete this.modified;
19612 this.editing = false;
19614 this.store.afterCommit(this);
19619 hasError : function(){
19620 return this.error != null;
19624 clearError : function(){
19629 * Creates a copy of this record.
19630 * @param {String} id (optional) A new record id if you don't want to use this record's id
19633 copy : function(newId) {
19634 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19638 * Ext JS Library 1.1.1
19639 * Copyright(c) 2006-2007, Ext JS, LLC.
19641 * Originally Released Under LGPL - original licence link has changed is not relivant.
19644 * <script type="text/javascript">
19650 * @class Roo.data.Store
19651 * @extends Roo.util.Observable
19652 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19653 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19655 * 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
19656 * has no knowledge of the format of the data returned by the Proxy.<br>
19658 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19659 * instances from the data object. These records are cached and made available through accessor functions.
19661 * Creates a new Store.
19662 * @param {Object} config A config object containing the objects needed for the Store to access data,
19663 * and read the data into Records.
19665 Roo.data.Store = function(config){
19666 this.data = new Roo.util.MixedCollection(false);
19667 this.data.getKey = function(o){
19670 this.baseParams = {};
19672 this.paramNames = {
19677 "multisort" : "_multisort"
19680 if(config && config.data){
19681 this.inlineData = config.data;
19682 delete config.data;
19685 Roo.apply(this, config);
19687 if(this.reader){ // reader passed
19688 this.reader = Roo.factory(this.reader, Roo.data);
19689 this.reader.xmodule = this.xmodule || false;
19690 if(!this.recordType){
19691 this.recordType = this.reader.recordType;
19693 if(this.reader.onMetaChange){
19694 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19698 if(this.recordType){
19699 this.fields = this.recordType.prototype.fields;
19701 this.modified = [];
19705 * @event datachanged
19706 * Fires when the data cache has changed, and a widget which is using this Store
19707 * as a Record cache should refresh its view.
19708 * @param {Store} this
19710 datachanged : true,
19712 * @event metachange
19713 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19714 * @param {Store} this
19715 * @param {Object} meta The JSON metadata
19720 * Fires when Records have been added to the Store
19721 * @param {Store} this
19722 * @param {Roo.data.Record[]} records The array of Records added
19723 * @param {Number} index The index at which the record(s) were added
19728 * Fires when a Record has been removed from the Store
19729 * @param {Store} this
19730 * @param {Roo.data.Record} record The Record that was removed
19731 * @param {Number} index The index at which the record was removed
19736 * Fires when a Record has been updated
19737 * @param {Store} this
19738 * @param {Roo.data.Record} record The Record that was updated
19739 * @param {String} operation The update operation being performed. Value may be one of:
19741 Roo.data.Record.EDIT
19742 Roo.data.Record.REJECT
19743 Roo.data.Record.COMMIT
19749 * Fires when the data cache has been cleared.
19750 * @param {Store} this
19754 * @event beforeload
19755 * Fires before a request is made for a new data object. If the beforeload handler returns false
19756 * the load action will be canceled.
19757 * @param {Store} this
19758 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19762 * @event beforeloadadd
19763 * Fires after a new set of Records has been loaded.
19764 * @param {Store} this
19765 * @param {Roo.data.Record[]} records The Records that were loaded
19766 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19768 beforeloadadd : true,
19771 * Fires after a new set of Records has been loaded, before they are added to the store.
19772 * @param {Store} this
19773 * @param {Roo.data.Record[]} records The Records that were loaded
19774 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19775 * @params {Object} return from reader
19779 * @event loadexception
19780 * Fires if an exception occurs in the Proxy during loading.
19781 * Called with the signature of the Proxy's "loadexception" event.
19782 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19785 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19786 * @param {Object} load options
19787 * @param {Object} jsonData from your request (normally this contains the Exception)
19789 loadexception : true
19793 this.proxy = Roo.factory(this.proxy, Roo.data);
19794 this.proxy.xmodule = this.xmodule || false;
19795 this.relayEvents(this.proxy, ["loadexception"]);
19797 this.sortToggle = {};
19798 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19800 Roo.data.Store.superclass.constructor.call(this);
19802 if(this.inlineData){
19803 this.loadData(this.inlineData);
19804 delete this.inlineData;
19808 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19810 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19811 * without a remote query - used by combo/forms at present.
19815 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19818 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19821 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19822 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19825 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19826 * on any HTTP request
19829 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19832 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19836 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19837 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19839 remoteSort : false,
19842 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19843 * loaded or when a record is removed. (defaults to false).
19845 pruneModifiedRecords : false,
19848 lastOptions : null,
19851 * Add Records to the Store and fires the add event.
19852 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19854 add : function(records){
19855 records = [].concat(records);
19856 for(var i = 0, len = records.length; i < len; i++){
19857 records[i].join(this);
19859 var index = this.data.length;
19860 this.data.addAll(records);
19861 this.fireEvent("add", this, records, index);
19865 * Remove a Record from the Store and fires the remove event.
19866 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19868 remove : function(record){
19869 var index = this.data.indexOf(record);
19870 this.data.removeAt(index);
19871 if(this.pruneModifiedRecords){
19872 this.modified.remove(record);
19874 this.fireEvent("remove", this, record, index);
19878 * Remove all Records from the Store and fires the clear event.
19880 removeAll : function(){
19882 if(this.pruneModifiedRecords){
19883 this.modified = [];
19885 this.fireEvent("clear", this);
19889 * Inserts Records to the Store at the given index and fires the add event.
19890 * @param {Number} index The start index at which to insert the passed Records.
19891 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19893 insert : function(index, records){
19894 records = [].concat(records);
19895 for(var i = 0, len = records.length; i < len; i++){
19896 this.data.insert(index, records[i]);
19897 records[i].join(this);
19899 this.fireEvent("add", this, records, index);
19903 * Get the index within the cache of the passed Record.
19904 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19905 * @return {Number} The index of the passed Record. Returns -1 if not found.
19907 indexOf : function(record){
19908 return this.data.indexOf(record);
19912 * Get the index within the cache of the Record with the passed id.
19913 * @param {String} id The id of the Record to find.
19914 * @return {Number} The index of the Record. Returns -1 if not found.
19916 indexOfId : function(id){
19917 return this.data.indexOfKey(id);
19921 * Get the Record with the specified id.
19922 * @param {String} id The id of the Record to find.
19923 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19925 getById : function(id){
19926 return this.data.key(id);
19930 * Get the Record at the specified index.
19931 * @param {Number} index The index of the Record to find.
19932 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19934 getAt : function(index){
19935 return this.data.itemAt(index);
19939 * Returns a range of Records between specified indices.
19940 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19941 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19942 * @return {Roo.data.Record[]} An array of Records
19944 getRange : function(start, end){
19945 return this.data.getRange(start, end);
19949 storeOptions : function(o){
19950 o = Roo.apply({}, o);
19953 this.lastOptions = o;
19957 * Loads the Record cache from the configured Proxy using the configured Reader.
19959 * If using remote paging, then the first load call must specify the <em>start</em>
19960 * and <em>limit</em> properties in the options.params property to establish the initial
19961 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19963 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19964 * and this call will return before the new data has been loaded. Perform any post-processing
19965 * in a callback function, or in a "load" event handler.</strong>
19967 * @param {Object} options An object containing properties which control loading options:<ul>
19968 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19969 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19970 * passed the following arguments:<ul>
19971 * <li>r : Roo.data.Record[]</li>
19972 * <li>options: Options object from the load call</li>
19973 * <li>success: Boolean success indicator</li></ul></li>
19974 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19975 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19978 load : function(options){
19979 options = options || {};
19980 if(this.fireEvent("beforeload", this, options) !== false){
19981 this.storeOptions(options);
19982 var p = Roo.apply(options.params || {}, this.baseParams);
19983 // if meta was not loaded from remote source.. try requesting it.
19984 if (!this.reader.metaFromRemote) {
19985 p._requestMeta = 1;
19987 if(this.sortInfo && this.remoteSort){
19988 var pn = this.paramNames;
19989 p[pn["sort"]] = this.sortInfo.field;
19990 p[pn["dir"]] = this.sortInfo.direction;
19992 if (this.multiSort) {
19993 var pn = this.paramNames;
19994 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19997 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20002 * Reloads the Record cache from the configured Proxy using the configured Reader and
20003 * the options from the last load operation performed.
20004 * @param {Object} options (optional) An object containing properties which may override the options
20005 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20006 * the most recently used options are reused).
20008 reload : function(options){
20009 this.load(Roo.applyIf(options||{}, this.lastOptions));
20013 // Called as a callback by the Reader during a load operation.
20014 loadRecords : function(o, options, success){
20015 if(!o || success === false){
20016 if(success !== false){
20017 this.fireEvent("load", this, [], options, o);
20019 if(options.callback){
20020 options.callback.call(options.scope || this, [], options, false);
20024 // if data returned failure - throw an exception.
20025 if (o.success === false) {
20026 // show a message if no listener is registered.
20027 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
20028 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
20030 // loadmask wil be hooked into this..
20031 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
20034 var r = o.records, t = o.totalRecords || r.length;
20036 this.fireEvent("beforeloadadd", this, r, options, o);
20038 if(!options || options.add !== true){
20039 if(this.pruneModifiedRecords){
20040 this.modified = [];
20042 for(var i = 0, len = r.length; i < len; i++){
20046 this.data = this.snapshot;
20047 delete this.snapshot;
20050 this.data.addAll(r);
20051 this.totalLength = t;
20053 this.fireEvent("datachanged", this);
20055 this.totalLength = Math.max(t, this.data.length+r.length);
20058 this.fireEvent("load", this, r, options, o);
20059 if(options.callback){
20060 options.callback.call(options.scope || this, r, options, true);
20066 * Loads data from a passed data block. A Reader which understands the format of the data
20067 * must have been configured in the constructor.
20068 * @param {Object} data The data block from which to read the Records. The format of the data expected
20069 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20070 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20072 loadData : function(o, append){
20073 var r = this.reader.readRecords(o);
20074 this.loadRecords(r, {add: append}, true);
20078 * Gets the number of cached records.
20080 * <em>If using paging, this may not be the total size of the dataset. If the data object
20081 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20082 * the data set size</em>
20084 getCount : function(){
20085 return this.data.length || 0;
20089 * Gets the total number of records in the dataset as returned by the server.
20091 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20092 * the dataset size</em>
20094 getTotalCount : function(){
20095 return this.totalLength || 0;
20099 * Returns the sort state of the Store as an object with two properties:
20101 field {String} The name of the field by which the Records are sorted
20102 direction {String} The sort order, "ASC" or "DESC"
20105 getSortState : function(){
20106 return this.sortInfo;
20110 applySort : function(){
20111 if(this.sortInfo && !this.remoteSort){
20112 var s = this.sortInfo, f = s.field;
20113 var st = this.fields.get(f).sortType;
20114 var fn = function(r1, r2){
20115 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20116 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20118 this.data.sort(s.direction, fn);
20119 if(this.snapshot && this.snapshot != this.data){
20120 this.snapshot.sort(s.direction, fn);
20126 * Sets the default sort column and order to be used by the next load operation.
20127 * @param {String} fieldName The name of the field to sort by.
20128 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20130 setDefaultSort : function(field, dir){
20131 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20135 * Sort the Records.
20136 * If remote sorting is used, the sort is performed on the server, and the cache is
20137 * reloaded. If local sorting is used, the cache is sorted internally.
20138 * @param {String} fieldName The name of the field to sort by.
20139 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20141 sort : function(fieldName, dir){
20142 var f = this.fields.get(fieldName);
20144 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20146 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20147 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20152 this.sortToggle[f.name] = dir;
20153 this.sortInfo = {field: f.name, direction: dir};
20154 if(!this.remoteSort){
20156 this.fireEvent("datachanged", this);
20158 this.load(this.lastOptions);
20163 * Calls the specified function for each of the Records in the cache.
20164 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20165 * Returning <em>false</em> aborts and exits the iteration.
20166 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20168 each : function(fn, scope){
20169 this.data.each(fn, scope);
20173 * Gets all records modified since the last commit. Modified records are persisted across load operations
20174 * (e.g., during paging).
20175 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20177 getModifiedRecords : function(){
20178 return this.modified;
20182 createFilterFn : function(property, value, anyMatch){
20183 if(!value.exec){ // not a regex
20184 value = String(value);
20185 if(value.length == 0){
20188 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20190 return function(r){
20191 return value.test(r.data[property]);
20196 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20197 * @param {String} property A field on your records
20198 * @param {Number} start The record index to start at (defaults to 0)
20199 * @param {Number} end The last record index to include (defaults to length - 1)
20200 * @return {Number} The sum
20202 sum : function(property, start, end){
20203 var rs = this.data.items, v = 0;
20204 start = start || 0;
20205 end = (end || end === 0) ? end : rs.length-1;
20207 for(var i = start; i <= end; i++){
20208 v += (rs[i].data[property] || 0);
20214 * Filter the records by a specified property.
20215 * @param {String} field A field on your records
20216 * @param {String/RegExp} value Either a string that the field
20217 * should start with or a RegExp to test against the field
20218 * @param {Boolean} anyMatch True to match any part not just the beginning
20220 filter : function(property, value, anyMatch){
20221 var fn = this.createFilterFn(property, value, anyMatch);
20222 return fn ? this.filterBy(fn) : this.clearFilter();
20226 * Filter by a function. The specified function will be called with each
20227 * record in this data source. If the function returns true the record is included,
20228 * otherwise it is filtered.
20229 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20230 * @param {Object} scope (optional) The scope of the function (defaults to this)
20232 filterBy : function(fn, scope){
20233 this.snapshot = this.snapshot || this.data;
20234 this.data = this.queryBy(fn, scope||this);
20235 this.fireEvent("datachanged", this);
20239 * Query the records by a specified property.
20240 * @param {String} field A field on your records
20241 * @param {String/RegExp} value Either a string that the field
20242 * should start with or a RegExp to test against the field
20243 * @param {Boolean} anyMatch True to match any part not just the beginning
20244 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20246 query : function(property, value, anyMatch){
20247 var fn = this.createFilterFn(property, value, anyMatch);
20248 return fn ? this.queryBy(fn) : this.data.clone();
20252 * Query by a function. The specified function will be called with each
20253 * record in this data source. If the function returns true the record is included
20255 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20256 * @param {Object} scope (optional) The scope of the function (defaults to this)
20257 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20259 queryBy : function(fn, scope){
20260 var data = this.snapshot || this.data;
20261 return data.filterBy(fn, scope||this);
20265 * Collects unique values for a particular dataIndex from this store.
20266 * @param {String} dataIndex The property to collect
20267 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20268 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20269 * @return {Array} An array of the unique values
20271 collect : function(dataIndex, allowNull, bypassFilter){
20272 var d = (bypassFilter === true && this.snapshot) ?
20273 this.snapshot.items : this.data.items;
20274 var v, sv, r = [], l = {};
20275 for(var i = 0, len = d.length; i < len; i++){
20276 v = d[i].data[dataIndex];
20278 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20287 * Revert to a view of the Record cache with no filtering applied.
20288 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20290 clearFilter : function(suppressEvent){
20291 if(this.snapshot && this.snapshot != this.data){
20292 this.data = this.snapshot;
20293 delete this.snapshot;
20294 if(suppressEvent !== true){
20295 this.fireEvent("datachanged", this);
20301 afterEdit : function(record){
20302 if(this.modified.indexOf(record) == -1){
20303 this.modified.push(record);
20305 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20309 afterReject : function(record){
20310 this.modified.remove(record);
20311 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20315 afterCommit : function(record){
20316 this.modified.remove(record);
20317 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20321 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20322 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20324 commitChanges : function(){
20325 var m = this.modified.slice(0);
20326 this.modified = [];
20327 for(var i = 0, len = m.length; i < len; i++){
20333 * Cancel outstanding changes on all changed records.
20335 rejectChanges : function(){
20336 var m = this.modified.slice(0);
20337 this.modified = [];
20338 for(var i = 0, len = m.length; i < len; i++){
20343 onMetaChange : function(meta, rtype, o){
20344 this.recordType = rtype;
20345 this.fields = rtype.prototype.fields;
20346 delete this.snapshot;
20347 this.sortInfo = meta.sortInfo || this.sortInfo;
20348 this.modified = [];
20349 this.fireEvent('metachange', this, this.reader.meta);
20353 * Ext JS Library 1.1.1
20354 * Copyright(c) 2006-2007, Ext JS, LLC.
20356 * Originally Released Under LGPL - original licence link has changed is not relivant.
20359 * <script type="text/javascript">
20363 * @class Roo.data.SimpleStore
20364 * @extends Roo.data.Store
20365 * Small helper class to make creating Stores from Array data easier.
20366 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20367 * @cfg {Array} fields An array of field definition objects, or field name strings.
20368 * @cfg {Array} data The multi-dimensional array of data
20370 * @param {Object} config
20372 Roo.data.SimpleStore = function(config){
20373 Roo.data.SimpleStore.superclass.constructor.call(this, {
20375 reader: new Roo.data.ArrayReader({
20378 Roo.data.Record.create(config.fields)
20380 proxy : new Roo.data.MemoryProxy(config.data)
20384 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
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">
20397 * @extends Roo.data.Store
20398 * @class Roo.data.JsonStore
20399 * Small helper class to make creating Stores for JSON data easier. <br/>
20401 var store = new Roo.data.JsonStore({
20402 url: 'get-images.php',
20404 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20407 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20408 * JsonReader and HttpProxy (unless inline data is provided).</b>
20409 * @cfg {Array} fields An array of field definition objects, or field name strings.
20411 * @param {Object} config
20413 Roo.data.JsonStore = function(c){
20414 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20415 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20416 reader: new Roo.data.JsonReader(c, c.fields)
20419 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20421 * Ext JS Library 1.1.1
20422 * Copyright(c) 2006-2007, Ext JS, LLC.
20424 * Originally Released Under LGPL - original licence link has changed is not relivant.
20427 * <script type="text/javascript">
20431 Roo.data.Field = function(config){
20432 if(typeof config == "string"){
20433 config = {name: config};
20435 Roo.apply(this, config);
20438 this.type = "auto";
20441 var st = Roo.data.SortTypes;
20442 // named sortTypes are supported, here we look them up
20443 if(typeof this.sortType == "string"){
20444 this.sortType = st[this.sortType];
20447 // set default sortType for strings and dates
20448 if(!this.sortType){
20451 this.sortType = st.asUCString;
20454 this.sortType = st.asDate;
20457 this.sortType = st.none;
20462 var stripRe = /[\$,%]/g;
20464 // prebuilt conversion function for this field, instead of
20465 // switching every time we're reading a value
20467 var cv, dateFormat = this.dateFormat;
20472 cv = function(v){ return v; };
20475 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20479 return v !== undefined && v !== null && v !== '' ?
20480 parseInt(String(v).replace(stripRe, ""), 10) : '';
20485 return v !== undefined && v !== null && v !== '' ?
20486 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20491 cv = function(v){ return v === true || v === "true" || v == 1; };
20498 if(v instanceof Date){
20502 if(dateFormat == "timestamp"){
20503 return new Date(v*1000);
20505 return Date.parseDate(v, dateFormat);
20507 var parsed = Date.parse(v);
20508 return parsed ? new Date(parsed) : null;
20517 Roo.data.Field.prototype = {
20525 * Ext JS Library 1.1.1
20526 * Copyright(c) 2006-2007, Ext JS, LLC.
20528 * Originally Released Under LGPL - original licence link has changed is not relivant.
20531 * <script type="text/javascript">
20534 // Base class for reading structured data from a data source. This class is intended to be
20535 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20538 * @class Roo.data.DataReader
20539 * Base class for reading structured data from a data source. This class is intended to be
20540 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20543 Roo.data.DataReader = function(meta, recordType){
20547 this.recordType = recordType instanceof Array ?
20548 Roo.data.Record.create(recordType) : recordType;
20551 Roo.data.DataReader.prototype = {
20553 * Create an empty record
20554 * @param {Object} data (optional) - overlay some values
20555 * @return {Roo.data.Record} record created.
20557 newRow : function(d) {
20559 this.recordType.prototype.fields.each(function(c) {
20561 case 'int' : da[c.name] = 0; break;
20562 case 'date' : da[c.name] = new Date(); break;
20563 case 'float' : da[c.name] = 0.0; break;
20564 case 'boolean' : da[c.name] = false; break;
20565 default : da[c.name] = ""; break;
20569 return new this.recordType(Roo.apply(da, d));
20574 * Ext JS Library 1.1.1
20575 * Copyright(c) 2006-2007, Ext JS, LLC.
20577 * Originally Released Under LGPL - original licence link has changed is not relivant.
20580 * <script type="text/javascript">
20584 * @class Roo.data.DataProxy
20585 * @extends Roo.data.Observable
20586 * This class is an abstract base class for implementations which provide retrieval of
20587 * unformatted data objects.<br>
20589 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20590 * (of the appropriate type which knows how to parse the data object) to provide a block of
20591 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20593 * Custom implementations must implement the load method as described in
20594 * {@link Roo.data.HttpProxy#load}.
20596 Roo.data.DataProxy = function(){
20599 * @event beforeload
20600 * Fires before a network request is made to retrieve a data object.
20601 * @param {Object} This DataProxy object.
20602 * @param {Object} params The params parameter to the load function.
20607 * Fires before the load method's callback is called.
20608 * @param {Object} This DataProxy object.
20609 * @param {Object} o The data object.
20610 * @param {Object} arg The callback argument object passed to the load function.
20614 * @event loadexception
20615 * Fires if an Exception occurs during data retrieval.
20616 * @param {Object} This DataProxy object.
20617 * @param {Object} o The data object.
20618 * @param {Object} arg The callback argument object passed to the load function.
20619 * @param {Object} e The Exception.
20621 loadexception : true
20623 Roo.data.DataProxy.superclass.constructor.call(this);
20626 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20629 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20633 * Ext JS Library 1.1.1
20634 * Copyright(c) 2006-2007, Ext JS, LLC.
20636 * Originally Released Under LGPL - original licence link has changed is not relivant.
20639 * <script type="text/javascript">
20642 * @class Roo.data.MemoryProxy
20643 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20644 * to the Reader when its load method is called.
20646 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20648 Roo.data.MemoryProxy = function(data){
20652 Roo.data.MemoryProxy.superclass.constructor.call(this);
20656 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20658 * Load data from the requested source (in this case an in-memory
20659 * data object passed to the constructor), read the data object into
20660 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20661 * process that block using the passed callback.
20662 * @param {Object} params This parameter is not used by the MemoryProxy class.
20663 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20664 * object into a block of Roo.data.Records.
20665 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20666 * The function must be passed <ul>
20667 * <li>The Record block object</li>
20668 * <li>The "arg" argument from the load function</li>
20669 * <li>A boolean success indicator</li>
20671 * @param {Object} scope The scope in which to call the callback
20672 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20674 load : function(params, reader, callback, scope, arg){
20675 params = params || {};
20678 result = reader.readRecords(this.data);
20680 this.fireEvent("loadexception", this, arg, null, e);
20681 callback.call(scope, null, arg, false);
20684 callback.call(scope, result, arg, true);
20688 update : function(params, records){
20693 * Ext JS Library 1.1.1
20694 * Copyright(c) 2006-2007, Ext JS, LLC.
20696 * Originally Released Under LGPL - original licence link has changed is not relivant.
20699 * <script type="text/javascript">
20702 * @class Roo.data.HttpProxy
20703 * @extends Roo.data.DataProxy
20704 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20705 * configured to reference a certain URL.<br><br>
20707 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20708 * from which the running page was served.<br><br>
20710 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20712 * Be aware that to enable the browser to parse an XML document, the server must set
20713 * the Content-Type header in the HTTP response to "text/xml".
20715 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20716 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20717 * will be used to make the request.
20719 Roo.data.HttpProxy = function(conn){
20720 Roo.data.HttpProxy.superclass.constructor.call(this);
20721 // is conn a conn config or a real conn?
20723 this.useAjax = !conn || !conn.events;
20727 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20728 // thse are take from connection...
20731 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20734 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20735 * extra parameters to each request made by this object. (defaults to undefined)
20738 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20739 * to each request made by this object. (defaults to undefined)
20742 * @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)
20745 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20748 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20754 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20758 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20759 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20760 * a finer-grained basis than the DataProxy events.
20762 getConnection : function(){
20763 return this.useAjax ? Roo.Ajax : this.conn;
20767 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20768 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20769 * process that block using the passed callback.
20770 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20771 * for the request to the remote server.
20772 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20773 * object into a block of Roo.data.Records.
20774 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20775 * The function must be passed <ul>
20776 * <li>The Record block object</li>
20777 * <li>The "arg" argument from the load function</li>
20778 * <li>A boolean success indicator</li>
20780 * @param {Object} scope The scope in which to call the callback
20781 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20783 load : function(params, reader, callback, scope, arg){
20784 if(this.fireEvent("beforeload", this, params) !== false){
20786 params : params || {},
20788 callback : callback,
20793 callback : this.loadResponse,
20797 Roo.applyIf(o, this.conn);
20798 if(this.activeRequest){
20799 Roo.Ajax.abort(this.activeRequest);
20801 this.activeRequest = Roo.Ajax.request(o);
20803 this.conn.request(o);
20806 callback.call(scope||this, null, arg, false);
20811 loadResponse : function(o, success, response){
20812 delete this.activeRequest;
20814 this.fireEvent("loadexception", this, o, response);
20815 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20820 result = o.reader.read(response);
20822 this.fireEvent("loadexception", this, o, response, e);
20823 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20827 this.fireEvent("load", this, o, o.request.arg);
20828 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20832 update : function(dataSet){
20837 updateResponse : function(dataSet){
20842 * Ext JS Library 1.1.1
20843 * Copyright(c) 2006-2007, Ext JS, LLC.
20845 * Originally Released Under LGPL - original licence link has changed is not relivant.
20848 * <script type="text/javascript">
20852 * @class Roo.data.ScriptTagProxy
20853 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20854 * other than the originating domain of the running page.<br><br>
20856 * <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
20857 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20859 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20860 * source code that is used as the source inside a <script> tag.<br><br>
20862 * In order for the browser to process the returned data, the server must wrap the data object
20863 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20864 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20865 * depending on whether the callback name was passed:
20868 boolean scriptTag = false;
20869 String cb = request.getParameter("callback");
20872 response.setContentType("text/javascript");
20874 response.setContentType("application/x-json");
20876 Writer out = response.getWriter();
20878 out.write(cb + "(");
20880 out.print(dataBlock.toJsonString());
20887 * @param {Object} config A configuration object.
20889 Roo.data.ScriptTagProxy = function(config){
20890 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20891 Roo.apply(this, config);
20892 this.head = document.getElementsByTagName("head")[0];
20895 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20897 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20899 * @cfg {String} url The URL from which to request the data object.
20902 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20906 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20907 * the server the name of the callback function set up by the load call to process the returned data object.
20908 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20909 * javascript output which calls this named function passing the data object as its only parameter.
20911 callbackParam : "callback",
20913 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20914 * name to the request.
20919 * Load data from the configured URL, read the data object into
20920 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20921 * process that block using the passed callback.
20922 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20923 * for the request to the remote server.
20924 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20925 * object into a block of Roo.data.Records.
20926 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20927 * The function must be passed <ul>
20928 * <li>The Record block object</li>
20929 * <li>The "arg" argument from the load function</li>
20930 * <li>A boolean success indicator</li>
20932 * @param {Object} scope The scope in which to call the callback
20933 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20935 load : function(params, reader, callback, scope, arg){
20936 if(this.fireEvent("beforeload", this, params) !== false){
20938 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20940 var url = this.url;
20941 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20943 url += "&_dc=" + (new Date().getTime());
20945 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20948 cb : "stcCallback"+transId,
20949 scriptId : "stcScript"+transId,
20953 callback : callback,
20959 window[trans.cb] = function(o){
20960 conn.handleResponse(o, trans);
20963 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20965 if(this.autoAbort !== false){
20969 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20971 var script = document.createElement("script");
20972 script.setAttribute("src", url);
20973 script.setAttribute("type", "text/javascript");
20974 script.setAttribute("id", trans.scriptId);
20975 this.head.appendChild(script);
20977 this.trans = trans;
20979 callback.call(scope||this, null, arg, false);
20984 isLoading : function(){
20985 return this.trans ? true : false;
20989 * Abort the current server request.
20991 abort : function(){
20992 if(this.isLoading()){
20993 this.destroyTrans(this.trans);
20998 destroyTrans : function(trans, isLoaded){
20999 this.head.removeChild(document.getElementById(trans.scriptId));
21000 clearTimeout(trans.timeoutId);
21002 window[trans.cb] = undefined;
21004 delete window[trans.cb];
21007 // if hasn't been loaded, wait for load to remove it to prevent script error
21008 window[trans.cb] = function(){
21009 window[trans.cb] = undefined;
21011 delete window[trans.cb];
21018 handleResponse : function(o, trans){
21019 this.trans = false;
21020 this.destroyTrans(trans, true);
21023 result = trans.reader.readRecords(o);
21025 this.fireEvent("loadexception", this, o, trans.arg, e);
21026 trans.callback.call(trans.scope||window, null, trans.arg, false);
21029 this.fireEvent("load", this, o, trans.arg);
21030 trans.callback.call(trans.scope||window, result, trans.arg, true);
21034 handleFailure : function(trans){
21035 this.trans = false;
21036 this.destroyTrans(trans, false);
21037 this.fireEvent("loadexception", this, null, trans.arg);
21038 trans.callback.call(trans.scope||window, null, trans.arg, false);
21042 * Ext JS Library 1.1.1
21043 * Copyright(c) 2006-2007, Ext JS, LLC.
21045 * Originally Released Under LGPL - original licence link has changed is not relivant.
21048 * <script type="text/javascript">
21052 * @class Roo.data.JsonReader
21053 * @extends Roo.data.DataReader
21054 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21055 * based on mappings in a provided Roo.data.Record constructor.
21057 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21058 * in the reply previously.
21063 var RecordDef = Roo.data.Record.create([
21064 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21065 {name: 'occupation'} // This field will use "occupation" as the mapping.
21067 var myReader = new Roo.data.JsonReader({
21068 totalProperty: "results", // The property which contains the total dataset size (optional)
21069 root: "rows", // The property which contains an Array of row objects
21070 id: "id" // The property within each row object that provides an ID for the record (optional)
21074 * This would consume a JSON file like this:
21076 { 'results': 2, 'rows': [
21077 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21078 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21081 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21082 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21083 * paged from the remote server.
21084 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21085 * @cfg {String} root name of the property which contains the Array of row objects.
21086 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21088 * Create a new JsonReader
21089 * @param {Object} meta Metadata configuration options
21090 * @param {Object} recordType Either an Array of field definition objects,
21091 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21093 Roo.data.JsonReader = function(meta, recordType){
21096 // set some defaults:
21097 Roo.applyIf(meta, {
21098 totalProperty: 'total',
21099 successProperty : 'success',
21104 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21106 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21109 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21110 * Used by Store query builder to append _requestMeta to params.
21113 metaFromRemote : false,
21115 * This method is only used by a DataProxy which has retrieved data from a remote server.
21116 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21117 * @return {Object} data A data block which is used by an Roo.data.Store object as
21118 * a cache of Roo.data.Records.
21120 read : function(response){
21121 var json = response.responseText;
21123 var o = /* eval:var:o */ eval("("+json+")");
21125 throw {message: "JsonReader.read: Json object not found"};
21131 this.metaFromRemote = true;
21132 this.meta = o.metaData;
21133 this.recordType = Roo.data.Record.create(o.metaData.fields);
21134 this.onMetaChange(this.meta, this.recordType, o);
21136 return this.readRecords(o);
21139 // private function a store will implement
21140 onMetaChange : function(meta, recordType, o){
21147 simpleAccess: function(obj, subsc) {
21154 getJsonAccessor: function(){
21156 return function(expr) {
21158 return(re.test(expr))
21159 ? new Function("obj", "return obj." + expr)
21164 return Roo.emptyFn;
21169 * Create a data block containing Roo.data.Records from an XML document.
21170 * @param {Object} o An object which contains an Array of row objects in the property specified
21171 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21172 * which contains the total size of the dataset.
21173 * @return {Object} data A data block which is used by an Roo.data.Store object as
21174 * a cache of Roo.data.Records.
21176 readRecords : function(o){
21178 * After any data loads, the raw JSON data is available for further custom processing.
21182 var s = this.meta, Record = this.recordType,
21183 f = Record.prototype.fields, fi = f.items, fl = f.length;
21185 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21187 if(s.totalProperty) {
21188 this.getTotal = this.getJsonAccessor(s.totalProperty);
21190 if(s.successProperty) {
21191 this.getSuccess = this.getJsonAccessor(s.successProperty);
21193 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21195 var g = this.getJsonAccessor(s.id);
21196 this.getId = function(rec) {
21198 return (r === undefined || r === "") ? null : r;
21201 this.getId = function(){return null;};
21204 for(var jj = 0; jj < fl; jj++){
21206 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21207 this.ef[jj] = this.getJsonAccessor(map);
21211 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21212 if(s.totalProperty){
21213 var vt = parseInt(this.getTotal(o), 10);
21218 if(s.successProperty){
21219 var vs = this.getSuccess(o);
21220 if(vs === false || vs === 'false'){
21225 for(var i = 0; i < c; i++){
21228 var id = this.getId(n);
21229 for(var j = 0; j < fl; j++){
21231 var v = this.ef[j](n);
21233 Roo.log('missing convert for ' + f.name);
21237 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21239 var record = new Record(values, id);
21241 records[i] = record;
21247 totalRecords : totalRecords
21252 * Ext JS Library 1.1.1
21253 * Copyright(c) 2006-2007, Ext JS, LLC.
21255 * Originally Released Under LGPL - original licence link has changed is not relivant.
21258 * <script type="text/javascript">
21262 * @class Roo.data.XmlReader
21263 * @extends Roo.data.DataReader
21264 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21265 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21267 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21268 * header in the HTTP response must be set to "text/xml".</em>
21272 var RecordDef = Roo.data.Record.create([
21273 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21274 {name: 'occupation'} // This field will use "occupation" as the mapping.
21276 var myReader = new Roo.data.XmlReader({
21277 totalRecords: "results", // The element which contains the total dataset size (optional)
21278 record: "row", // The repeated element which contains row information
21279 id: "id" // The element within the row that provides an ID for the record (optional)
21283 * This would consume an XML file like this:
21287 <results>2</results>
21290 <name>Bill</name>
21291 <occupation>Gardener</occupation>
21295 <name>Ben</name>
21296 <occupation>Horticulturalist</occupation>
21300 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21301 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21302 * paged from the remote server.
21303 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21304 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21305 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21306 * a record identifier value.
21308 * Create a new XmlReader
21309 * @param {Object} meta Metadata configuration options
21310 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21311 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21312 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21314 Roo.data.XmlReader = function(meta, recordType){
21316 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21318 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21320 * This method is only used by a DataProxy which has retrieved data from a remote server.
21321 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21322 * to contain a method called 'responseXML' that returns an XML document object.
21323 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21324 * a cache of Roo.data.Records.
21326 read : function(response){
21327 var doc = response.responseXML;
21329 throw {message: "XmlReader.read: XML Document not available"};
21331 return this.readRecords(doc);
21335 * Create a data block containing Roo.data.Records from an XML document.
21336 * @param {Object} doc A parsed XML document.
21337 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21338 * a cache of Roo.data.Records.
21340 readRecords : function(doc){
21342 * After any data loads/reads, the raw XML Document is available for further custom processing.
21343 * @type XMLDocument
21345 this.xmlData = doc;
21346 var root = doc.documentElement || doc;
21347 var q = Roo.DomQuery;
21348 var recordType = this.recordType, fields = recordType.prototype.fields;
21349 var sid = this.meta.id;
21350 var totalRecords = 0, success = true;
21351 if(this.meta.totalRecords){
21352 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21355 if(this.meta.success){
21356 var sv = q.selectValue(this.meta.success, root, true);
21357 success = sv !== false && sv !== 'false';
21360 var ns = q.select(this.meta.record, root);
21361 for(var i = 0, len = ns.length; i < len; i++) {
21364 var id = sid ? q.selectValue(sid, n) : undefined;
21365 for(var j = 0, jlen = fields.length; j < jlen; j++){
21366 var f = fields.items[j];
21367 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21369 values[f.name] = v;
21371 var record = new recordType(values, id);
21373 records[records.length] = record;
21379 totalRecords : totalRecords || records.length
21384 * Ext JS Library 1.1.1
21385 * Copyright(c) 2006-2007, Ext JS, LLC.
21387 * Originally Released Under LGPL - original licence link has changed is not relivant.
21390 * <script type="text/javascript">
21394 * @class Roo.data.ArrayReader
21395 * @extends Roo.data.DataReader
21396 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21397 * Each element of that Array represents a row of data fields. The
21398 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21399 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21403 var RecordDef = Roo.data.Record.create([
21404 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21405 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21407 var myReader = new Roo.data.ArrayReader({
21408 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21412 * This would consume an Array like this:
21414 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21416 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21418 * Create a new JsonReader
21419 * @param {Object} meta Metadata configuration options.
21420 * @param {Object} recordType Either an Array of field definition objects
21421 * as specified to {@link Roo.data.Record#create},
21422 * or an {@link Roo.data.Record} object
21423 * created using {@link Roo.data.Record#create}.
21425 Roo.data.ArrayReader = function(meta, recordType){
21426 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21429 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21431 * Create a data block containing Roo.data.Records from an XML document.
21432 * @param {Object} o An Array of row objects which represents the dataset.
21433 * @return {Object} data A data block which is used by an Roo.data.Store object as
21434 * a cache of Roo.data.Records.
21436 readRecords : function(o){
21437 var sid = this.meta ? this.meta.id : null;
21438 var recordType = this.recordType, fields = recordType.prototype.fields;
21441 for(var i = 0; i < root.length; i++){
21444 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21445 for(var j = 0, jlen = fields.length; j < jlen; j++){
21446 var f = fields.items[j];
21447 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21448 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21450 values[f.name] = v;
21452 var record = new recordType(values, id);
21454 records[records.length] = record;
21458 totalRecords : records.length
21463 * Ext JS Library 1.1.1
21464 * Copyright(c) 2006-2007, Ext JS, LLC.
21466 * Originally Released Under LGPL - original licence link has changed is not relivant.
21469 * <script type="text/javascript">
21474 * @class Roo.data.Tree
21475 * @extends Roo.util.Observable
21476 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21477 * in the tree have most standard DOM functionality.
21479 * @param {Node} root (optional) The root node
21481 Roo.data.Tree = function(root){
21482 this.nodeHash = {};
21484 * The root node for this tree
21489 this.setRootNode(root);
21494 * Fires when a new child node is appended to a node in this tree.
21495 * @param {Tree} tree The owner tree
21496 * @param {Node} parent The parent node
21497 * @param {Node} node The newly appended node
21498 * @param {Number} index The index of the newly appended node
21503 * Fires when a child node is removed from a node in this tree.
21504 * @param {Tree} tree The owner tree
21505 * @param {Node} parent The parent node
21506 * @param {Node} node The child node removed
21511 * Fires when a node is moved to a new location in the tree
21512 * @param {Tree} tree The owner tree
21513 * @param {Node} node The node moved
21514 * @param {Node} oldParent The old parent of this node
21515 * @param {Node} newParent The new parent of this node
21516 * @param {Number} index The index it was moved to
21521 * Fires when a new child node is inserted in a node in this tree.
21522 * @param {Tree} tree The owner tree
21523 * @param {Node} parent The parent node
21524 * @param {Node} node The child node inserted
21525 * @param {Node} refNode The child node the node was inserted before
21529 * @event beforeappend
21530 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21531 * @param {Tree} tree The owner tree
21532 * @param {Node} parent The parent node
21533 * @param {Node} node The child node to be appended
21535 "beforeappend" : true,
21537 * @event beforeremove
21538 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21539 * @param {Tree} tree The owner tree
21540 * @param {Node} parent The parent node
21541 * @param {Node} node The child node to be removed
21543 "beforeremove" : true,
21545 * @event beforemove
21546 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21547 * @param {Tree} tree The owner tree
21548 * @param {Node} node The node being moved
21549 * @param {Node} oldParent The parent of the node
21550 * @param {Node} newParent The new parent the node is moving to
21551 * @param {Number} index The index it is being moved to
21553 "beforemove" : true,
21555 * @event beforeinsert
21556 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21557 * @param {Tree} tree The owner tree
21558 * @param {Node} parent The parent node
21559 * @param {Node} node The child node to be inserted
21560 * @param {Node} refNode The child node the node is being inserted before
21562 "beforeinsert" : true
21565 Roo.data.Tree.superclass.constructor.call(this);
21568 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21569 pathSeparator: "/",
21571 proxyNodeEvent : function(){
21572 return this.fireEvent.apply(this, arguments);
21576 * Returns the root node for this tree.
21579 getRootNode : function(){
21584 * Sets the root node for this tree.
21585 * @param {Node} node
21588 setRootNode : function(node){
21590 node.ownerTree = this;
21591 node.isRoot = true;
21592 this.registerNode(node);
21597 * Gets a node in this tree by its id.
21598 * @param {String} id
21601 getNodeById : function(id){
21602 return this.nodeHash[id];
21605 registerNode : function(node){
21606 this.nodeHash[node.id] = node;
21609 unregisterNode : function(node){
21610 delete this.nodeHash[node.id];
21613 toString : function(){
21614 return "[Tree"+(this.id?" "+this.id:"")+"]";
21619 * @class Roo.data.Node
21620 * @extends Roo.util.Observable
21621 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21622 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21624 * @param {Object} attributes The attributes/config for the node
21626 Roo.data.Node = function(attributes){
21628 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21631 this.attributes = attributes || {};
21632 this.leaf = this.attributes.leaf;
21634 * The node id. @type String
21636 this.id = this.attributes.id;
21638 this.id = Roo.id(null, "ynode-");
21639 this.attributes.id = this.id;
21644 * All child nodes of this node. @type Array
21646 this.childNodes = [];
21647 if(!this.childNodes.indexOf){ // indexOf is a must
21648 this.childNodes.indexOf = function(o){
21649 for(var i = 0, len = this.length; i < len; i++){
21658 * The parent node for this node. @type Node
21660 this.parentNode = null;
21662 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21664 this.firstChild = null;
21666 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21668 this.lastChild = null;
21670 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21672 this.previousSibling = null;
21674 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21676 this.nextSibling = null;
21681 * Fires when a new child node is appended
21682 * @param {Tree} tree The owner tree
21683 * @param {Node} this This node
21684 * @param {Node} node The newly appended node
21685 * @param {Number} index The index of the newly appended node
21690 * Fires when a child node is removed
21691 * @param {Tree} tree The owner tree
21692 * @param {Node} this This node
21693 * @param {Node} node The removed node
21698 * Fires when this node is moved to a new location in the tree
21699 * @param {Tree} tree The owner tree
21700 * @param {Node} this This node
21701 * @param {Node} oldParent The old parent of this node
21702 * @param {Node} newParent The new parent of this node
21703 * @param {Number} index The index it was moved to
21708 * Fires when a new child node is inserted.
21709 * @param {Tree} tree The owner tree
21710 * @param {Node} this This node
21711 * @param {Node} node The child node inserted
21712 * @param {Node} refNode The child node the node was inserted before
21716 * @event beforeappend
21717 * Fires before a new child is appended, return false to cancel the append.
21718 * @param {Tree} tree The owner tree
21719 * @param {Node} this This node
21720 * @param {Node} node The child node to be appended
21722 "beforeappend" : true,
21724 * @event beforeremove
21725 * Fires before a child is removed, return false to cancel the remove.
21726 * @param {Tree} tree The owner tree
21727 * @param {Node} this This node
21728 * @param {Node} node The child node to be removed
21730 "beforeremove" : true,
21732 * @event beforemove
21733 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21734 * @param {Tree} tree The owner tree
21735 * @param {Node} this This node
21736 * @param {Node} oldParent The parent of this node
21737 * @param {Node} newParent The new parent this node is moving to
21738 * @param {Number} index The index it is being moved to
21740 "beforemove" : true,
21742 * @event beforeinsert
21743 * Fires before a new child is inserted, return false to cancel the insert.
21744 * @param {Tree} tree The owner tree
21745 * @param {Node} this This node
21746 * @param {Node} node The child node to be inserted
21747 * @param {Node} refNode The child node the node is being inserted before
21749 "beforeinsert" : true
21751 this.listeners = this.attributes.listeners;
21752 Roo.data.Node.superclass.constructor.call(this);
21755 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21756 fireEvent : function(evtName){
21757 // first do standard event for this node
21758 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21761 // then bubble it up to the tree if the event wasn't cancelled
21762 var ot = this.getOwnerTree();
21764 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21772 * Returns true if this node is a leaf
21773 * @return {Boolean}
21775 isLeaf : function(){
21776 return this.leaf === true;
21780 setFirstChild : function(node){
21781 this.firstChild = node;
21785 setLastChild : function(node){
21786 this.lastChild = node;
21791 * Returns true if this node is the last child of its parent
21792 * @return {Boolean}
21794 isLast : function(){
21795 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21799 * Returns true if this node is the first child of its parent
21800 * @return {Boolean}
21802 isFirst : function(){
21803 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21806 hasChildNodes : function(){
21807 return !this.isLeaf() && this.childNodes.length > 0;
21811 * Insert node(s) as the last child node of this node.
21812 * @param {Node/Array} node The node or Array of nodes to append
21813 * @return {Node} The appended node if single append, or null if an array was passed
21815 appendChild : function(node){
21817 if(node instanceof Array){
21819 }else if(arguments.length > 1){
21822 // if passed an array or multiple args do them one by one
21824 for(var i = 0, len = multi.length; i < len; i++) {
21825 this.appendChild(multi[i]);
21828 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21831 var index = this.childNodes.length;
21832 var oldParent = node.parentNode;
21833 // it's a move, make sure we move it cleanly
21835 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21838 oldParent.removeChild(node);
21840 index = this.childNodes.length;
21842 this.setFirstChild(node);
21844 this.childNodes.push(node);
21845 node.parentNode = this;
21846 var ps = this.childNodes[index-1];
21848 node.previousSibling = ps;
21849 ps.nextSibling = node;
21851 node.previousSibling = null;
21853 node.nextSibling = null;
21854 this.setLastChild(node);
21855 node.setOwnerTree(this.getOwnerTree());
21856 this.fireEvent("append", this.ownerTree, this, node, index);
21858 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21865 * Removes a child node from this node.
21866 * @param {Node} node The node to remove
21867 * @return {Node} The removed node
21869 removeChild : function(node){
21870 var index = this.childNodes.indexOf(node);
21874 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21878 // remove it from childNodes collection
21879 this.childNodes.splice(index, 1);
21882 if(node.previousSibling){
21883 node.previousSibling.nextSibling = node.nextSibling;
21885 if(node.nextSibling){
21886 node.nextSibling.previousSibling = node.previousSibling;
21889 // update child refs
21890 if(this.firstChild == node){
21891 this.setFirstChild(node.nextSibling);
21893 if(this.lastChild == node){
21894 this.setLastChild(node.previousSibling);
21897 node.setOwnerTree(null);
21898 // clear any references from the node
21899 node.parentNode = null;
21900 node.previousSibling = null;
21901 node.nextSibling = null;
21902 this.fireEvent("remove", this.ownerTree, this, node);
21907 * Inserts the first node before the second node in this nodes childNodes collection.
21908 * @param {Node} node The node to insert
21909 * @param {Node} refNode The node to insert before (if null the node is appended)
21910 * @return {Node} The inserted node
21912 insertBefore : function(node, refNode){
21913 if(!refNode){ // like standard Dom, refNode can be null for append
21914 return this.appendChild(node);
21917 if(node == refNode){
21921 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21924 var index = this.childNodes.indexOf(refNode);
21925 var oldParent = node.parentNode;
21926 var refIndex = index;
21928 // when moving internally, indexes will change after remove
21929 if(oldParent == this && this.childNodes.indexOf(node) < index){
21933 // it's a move, make sure we move it cleanly
21935 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21938 oldParent.removeChild(node);
21941 this.setFirstChild(node);
21943 this.childNodes.splice(refIndex, 0, node);
21944 node.parentNode = this;
21945 var ps = this.childNodes[refIndex-1];
21947 node.previousSibling = ps;
21948 ps.nextSibling = node;
21950 node.previousSibling = null;
21952 node.nextSibling = refNode;
21953 refNode.previousSibling = node;
21954 node.setOwnerTree(this.getOwnerTree());
21955 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21957 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21963 * Returns the child node at the specified index.
21964 * @param {Number} index
21967 item : function(index){
21968 return this.childNodes[index];
21972 * Replaces one child node in this node with another.
21973 * @param {Node} newChild The replacement node
21974 * @param {Node} oldChild The node to replace
21975 * @return {Node} The replaced node
21977 replaceChild : function(newChild, oldChild){
21978 this.insertBefore(newChild, oldChild);
21979 this.removeChild(oldChild);
21984 * Returns the index of a child node
21985 * @param {Node} node
21986 * @return {Number} The index of the node or -1 if it was not found
21988 indexOf : function(child){
21989 return this.childNodes.indexOf(child);
21993 * Returns the tree this node is in.
21996 getOwnerTree : function(){
21997 // if it doesn't have one, look for one
21998 if(!this.ownerTree){
22002 this.ownerTree = p.ownerTree;
22008 return this.ownerTree;
22012 * Returns depth of this node (the root node has a depth of 0)
22015 getDepth : function(){
22018 while(p.parentNode){
22026 setOwnerTree : function(tree){
22027 // if it's move, we need to update everyone
22028 if(tree != this.ownerTree){
22029 if(this.ownerTree){
22030 this.ownerTree.unregisterNode(this);
22032 this.ownerTree = tree;
22033 var cs = this.childNodes;
22034 for(var i = 0, len = cs.length; i < len; i++) {
22035 cs[i].setOwnerTree(tree);
22038 tree.registerNode(this);
22044 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22045 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22046 * @return {String} The path
22048 getPath : function(attr){
22049 attr = attr || "id";
22050 var p = this.parentNode;
22051 var b = [this.attributes[attr]];
22053 b.unshift(p.attributes[attr]);
22056 var sep = this.getOwnerTree().pathSeparator;
22057 return sep + b.join(sep);
22061 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22062 * function call will be the scope provided or the current node. The arguments to the function
22063 * will be the args provided or the current node. If the function returns false at any point,
22064 * the bubble is stopped.
22065 * @param {Function} fn The function to call
22066 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22067 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22069 bubble : function(fn, scope, args){
22072 if(fn.call(scope || p, args || p) === false){
22080 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22081 * function call will be the scope provided or the current node. The arguments to the function
22082 * will be the args provided or the current node. If the function returns false at any point,
22083 * the cascade is stopped on that branch.
22084 * @param {Function} fn The function to call
22085 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22086 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22088 cascade : function(fn, scope, args){
22089 if(fn.call(scope || this, args || this) !== false){
22090 var cs = this.childNodes;
22091 for(var i = 0, len = cs.length; i < len; i++) {
22092 cs[i].cascade(fn, scope, args);
22098 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22099 * function call will be the scope provided or the current node. The arguments to the function
22100 * will be the args provided or the current node. If the function returns false at any point,
22101 * the iteration stops.
22102 * @param {Function} fn The function to call
22103 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22104 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22106 eachChild : function(fn, scope, args){
22107 var cs = this.childNodes;
22108 for(var i = 0, len = cs.length; i < len; i++) {
22109 if(fn.call(scope || this, args || cs[i]) === false){
22116 * Finds the first child that has the attribute with the specified value.
22117 * @param {String} attribute The attribute name
22118 * @param {Mixed} value The value to search for
22119 * @return {Node} The found child or null if none was found
22121 findChild : function(attribute, value){
22122 var cs = this.childNodes;
22123 for(var i = 0, len = cs.length; i < len; i++) {
22124 if(cs[i].attributes[attribute] == value){
22132 * Finds the first child by a custom function. The child matches if the function passed
22134 * @param {Function} fn
22135 * @param {Object} scope (optional)
22136 * @return {Node} The found child or null if none was found
22138 findChildBy : function(fn, scope){
22139 var cs = this.childNodes;
22140 for(var i = 0, len = cs.length; i < len; i++) {
22141 if(fn.call(scope||cs[i], cs[i]) === true){
22149 * Sorts this nodes children using the supplied sort function
22150 * @param {Function} fn
22151 * @param {Object} scope (optional)
22153 sort : function(fn, scope){
22154 var cs = this.childNodes;
22155 var len = cs.length;
22157 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22159 for(var i = 0; i < len; i++){
22161 n.previousSibling = cs[i-1];
22162 n.nextSibling = cs[i+1];
22164 this.setFirstChild(n);
22167 this.setLastChild(n);
22174 * Returns true if this node is an ancestor (at any point) of the passed node.
22175 * @param {Node} node
22176 * @return {Boolean}
22178 contains : function(node){
22179 return node.isAncestor(this);
22183 * Returns true if the passed node is an ancestor (at any point) of this node.
22184 * @param {Node} node
22185 * @return {Boolean}
22187 isAncestor : function(node){
22188 var p = this.parentNode;
22198 toString : function(){
22199 return "[Node"+(this.id?" "+this.id:"")+"]";
22203 * Ext JS Library 1.1.1
22204 * Copyright(c) 2006-2007, Ext JS, LLC.
22206 * Originally Released Under LGPL - original licence link has changed is not relivant.
22209 * <script type="text/javascript">
22214 * @class Roo.ComponentMgr
22215 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22218 Roo.ComponentMgr = function(){
22219 var all = new Roo.util.MixedCollection();
22223 * Registers a component.
22224 * @param {Roo.Component} c The component
22226 register : function(c){
22231 * Unregisters a component.
22232 * @param {Roo.Component} c The component
22234 unregister : function(c){
22239 * Returns a component by id
22240 * @param {String} id The component id
22242 get : function(id){
22243 return all.get(id);
22247 * Registers a function that will be called when a specified component is added to ComponentMgr
22248 * @param {String} id The component id
22249 * @param {Funtction} fn The callback function
22250 * @param {Object} scope The scope of the callback
22252 onAvailable : function(id, fn, scope){
22253 all.on("add", function(index, o){
22255 fn.call(scope || o, o);
22256 all.un("add", fn, scope);
22263 * Ext JS Library 1.1.1
22264 * Copyright(c) 2006-2007, Ext JS, LLC.
22266 * Originally Released Under LGPL - original licence link has changed is not relivant.
22269 * <script type="text/javascript">
22273 * @class Roo.Component
22274 * @extends Roo.util.Observable
22275 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22276 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22277 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22278 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22279 * All visual components (widgets) that require rendering into a layout should subclass Component.
22281 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22282 * 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
22283 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22285 Roo.Component = function(config){
22286 config = config || {};
22287 if(config.tagName || config.dom || typeof config == "string"){ // element object
22288 config = {el: config, id: config.id || config};
22290 this.initialConfig = config;
22292 Roo.apply(this, config);
22296 * Fires after the component is disabled.
22297 * @param {Roo.Component} this
22302 * Fires after the component is enabled.
22303 * @param {Roo.Component} this
22307 * @event beforeshow
22308 * Fires before the component is shown. Return false to stop the show.
22309 * @param {Roo.Component} this
22314 * Fires after the component is shown.
22315 * @param {Roo.Component} this
22319 * @event beforehide
22320 * Fires before the component is hidden. Return false to stop the hide.
22321 * @param {Roo.Component} this
22326 * Fires after the component is hidden.
22327 * @param {Roo.Component} this
22331 * @event beforerender
22332 * Fires before the component is rendered. Return false to stop the render.
22333 * @param {Roo.Component} this
22335 beforerender : true,
22338 * Fires after the component is rendered.
22339 * @param {Roo.Component} this
22343 * @event beforedestroy
22344 * Fires before the component is destroyed. Return false to stop the destroy.
22345 * @param {Roo.Component} this
22347 beforedestroy : true,
22350 * Fires after the component is destroyed.
22351 * @param {Roo.Component} this
22356 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22358 Roo.ComponentMgr.register(this);
22359 Roo.Component.superclass.constructor.call(this);
22360 this.initComponent();
22361 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22362 this.render(this.renderTo);
22363 delete this.renderTo;
22368 Roo.Component.AUTO_ID = 1000;
22370 Roo.extend(Roo.Component, Roo.util.Observable, {
22372 * @scope Roo.Component.prototype
22374 * true if this component is hidden. Read-only.
22379 * true if this component is disabled. Read-only.
22384 * true if this component has been rendered. Read-only.
22388 /** @cfg {String} disableClass
22389 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22391 disabledClass : "x-item-disabled",
22392 /** @cfg {Boolean} allowDomMove
22393 * Whether the component can move the Dom node when rendering (defaults to true).
22395 allowDomMove : true,
22396 /** @cfg {String} hideMode
22397 * How this component should hidden. Supported values are
22398 * "visibility" (css visibility), "offsets" (negative offset position) and
22399 * "display" (css display) - defaults to "display".
22401 hideMode: 'display',
22404 ctype : "Roo.Component",
22407 * @cfg {String} actionMode
22408 * which property holds the element that used for hide() / show() / disable() / enable()
22414 getActionEl : function(){
22415 return this[this.actionMode];
22418 initComponent : Roo.emptyFn,
22420 * If this is a lazy rendering component, render it to its container element.
22421 * @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.
22423 render : function(container, position){
22424 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22425 if(!container && this.el){
22426 this.el = Roo.get(this.el);
22427 container = this.el.dom.parentNode;
22428 this.allowDomMove = false;
22430 this.container = Roo.get(container);
22431 this.rendered = true;
22432 if(position !== undefined){
22433 if(typeof position == 'number'){
22434 position = this.container.dom.childNodes[position];
22436 position = Roo.getDom(position);
22439 this.onRender(this.container, position || null);
22441 this.el.addClass(this.cls);
22445 this.el.applyStyles(this.style);
22448 this.fireEvent("render", this);
22449 this.afterRender(this.container);
22461 // default function is not really useful
22462 onRender : function(ct, position){
22464 this.el = Roo.get(this.el);
22465 if(this.allowDomMove !== false){
22466 ct.dom.insertBefore(this.el.dom, position);
22472 getAutoCreate : function(){
22473 var cfg = typeof this.autoCreate == "object" ?
22474 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22475 if(this.id && !cfg.id){
22482 afterRender : Roo.emptyFn,
22485 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22486 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22488 destroy : function(){
22489 if(this.fireEvent("beforedestroy", this) !== false){
22490 this.purgeListeners();
22491 this.beforeDestroy();
22493 this.el.removeAllListeners();
22495 if(this.actionMode == "container"){
22496 this.container.remove();
22500 Roo.ComponentMgr.unregister(this);
22501 this.fireEvent("destroy", this);
22506 beforeDestroy : function(){
22511 onDestroy : function(){
22516 * Returns the underlying {@link Roo.Element}.
22517 * @return {Roo.Element} The element
22519 getEl : function(){
22524 * Returns the id of this component.
22527 getId : function(){
22532 * Try to focus this component.
22533 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22534 * @return {Roo.Component} this
22536 focus : function(selectText){
22539 if(selectText === true){
22540 this.el.dom.select();
22555 * Disable this component.
22556 * @return {Roo.Component} this
22558 disable : function(){
22562 this.disabled = true;
22563 this.fireEvent("disable", this);
22568 onDisable : function(){
22569 this.getActionEl().addClass(this.disabledClass);
22570 this.el.dom.disabled = true;
22574 * Enable this component.
22575 * @return {Roo.Component} this
22577 enable : function(){
22581 this.disabled = false;
22582 this.fireEvent("enable", this);
22587 onEnable : function(){
22588 this.getActionEl().removeClass(this.disabledClass);
22589 this.el.dom.disabled = false;
22593 * Convenience function for setting disabled/enabled by boolean.
22594 * @param {Boolean} disabled
22596 setDisabled : function(disabled){
22597 this[disabled ? "disable" : "enable"]();
22601 * Show this component.
22602 * @return {Roo.Component} this
22605 if(this.fireEvent("beforeshow", this) !== false){
22606 this.hidden = false;
22610 this.fireEvent("show", this);
22616 onShow : function(){
22617 var ae = this.getActionEl();
22618 if(this.hideMode == 'visibility'){
22619 ae.dom.style.visibility = "visible";
22620 }else if(this.hideMode == 'offsets'){
22621 ae.removeClass('x-hidden');
22623 ae.dom.style.display = "";
22628 * Hide this component.
22629 * @return {Roo.Component} this
22632 if(this.fireEvent("beforehide", this) !== false){
22633 this.hidden = true;
22637 this.fireEvent("hide", this);
22643 onHide : function(){
22644 var ae = this.getActionEl();
22645 if(this.hideMode == 'visibility'){
22646 ae.dom.style.visibility = "hidden";
22647 }else if(this.hideMode == 'offsets'){
22648 ae.addClass('x-hidden');
22650 ae.dom.style.display = "none";
22655 * Convenience function to hide or show this component by boolean.
22656 * @param {Boolean} visible True to show, false to hide
22657 * @return {Roo.Component} this
22659 setVisible: function(visible){
22669 * Returns true if this component is visible.
22671 isVisible : function(){
22672 return this.getActionEl().isVisible();
22675 cloneConfig : function(overrides){
22676 overrides = overrides || {};
22677 var id = overrides.id || Roo.id();
22678 var cfg = Roo.applyIf(overrides, this.initialConfig);
22679 cfg.id = id; // prevent dup id
22680 return new this.constructor(cfg);
22684 * Ext JS Library 1.1.1
22685 * Copyright(c) 2006-2007, Ext JS, LLC.
22687 * Originally Released Under LGPL - original licence link has changed is not relivant.
22690 * <script type="text/javascript">
22695 * @extends Roo.Element
22696 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22697 * automatic maintaining of shadow/shim positions.
22698 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22699 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22700 * you can pass a string with a CSS class name. False turns off the shadow.
22701 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22702 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22703 * @cfg {String} cls CSS class to add to the element
22704 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22705 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22707 * @param {Object} config An object with config options.
22708 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22711 Roo.Layer = function(config, existingEl){
22712 config = config || {};
22713 var dh = Roo.DomHelper;
22714 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22716 this.dom = Roo.getDom(existingEl);
22719 var o = config.dh || {tag: "div", cls: "x-layer"};
22720 this.dom = dh.append(pel, o);
22723 this.addClass(config.cls);
22725 this.constrain = config.constrain !== false;
22726 this.visibilityMode = Roo.Element.VISIBILITY;
22728 this.id = this.dom.id = config.id;
22730 this.id = Roo.id(this.dom);
22732 this.zindex = config.zindex || this.getZIndex();
22733 this.position("absolute", this.zindex);
22735 this.shadowOffset = config.shadowOffset || 4;
22736 this.shadow = new Roo.Shadow({
22737 offset : this.shadowOffset,
22738 mode : config.shadow
22741 this.shadowOffset = 0;
22743 this.useShim = config.shim !== false && Roo.useShims;
22744 this.useDisplay = config.useDisplay;
22748 var supr = Roo.Element.prototype;
22750 // shims are shared among layer to keep from having 100 iframes
22753 Roo.extend(Roo.Layer, Roo.Element, {
22755 getZIndex : function(){
22756 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22759 getShim : function(){
22766 var shim = shims.shift();
22768 shim = this.createShim();
22769 shim.enableDisplayMode('block');
22770 shim.dom.style.display = 'none';
22771 shim.dom.style.visibility = 'visible';
22773 var pn = this.dom.parentNode;
22774 if(shim.dom.parentNode != pn){
22775 pn.insertBefore(shim.dom, this.dom);
22777 shim.setStyle('z-index', this.getZIndex()-2);
22782 hideShim : function(){
22784 this.shim.setDisplayed(false);
22785 shims.push(this.shim);
22790 disableShadow : function(){
22792 this.shadowDisabled = true;
22793 this.shadow.hide();
22794 this.lastShadowOffset = this.shadowOffset;
22795 this.shadowOffset = 0;
22799 enableShadow : function(show){
22801 this.shadowDisabled = false;
22802 this.shadowOffset = this.lastShadowOffset;
22803 delete this.lastShadowOffset;
22811 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22812 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22813 sync : function(doShow){
22814 var sw = this.shadow;
22815 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22816 var sh = this.getShim();
22818 var w = this.getWidth(),
22819 h = this.getHeight();
22821 var l = this.getLeft(true),
22822 t = this.getTop(true);
22824 if(sw && !this.shadowDisabled){
22825 if(doShow && !sw.isVisible()){
22828 sw.realign(l, t, w, h);
22834 // fit the shim behind the shadow, so it is shimmed too
22835 var a = sw.adjusts, s = sh.dom.style;
22836 s.left = (Math.min(l, l+a.l))+"px";
22837 s.top = (Math.min(t, t+a.t))+"px";
22838 s.width = (w+a.w)+"px";
22839 s.height = (h+a.h)+"px";
22846 sh.setLeftTop(l, t);
22853 destroy : function(){
22856 this.shadow.hide();
22858 this.removeAllListeners();
22859 var pn = this.dom.parentNode;
22861 pn.removeChild(this.dom);
22863 Roo.Element.uncache(this.id);
22866 remove : function(){
22871 beginUpdate : function(){
22872 this.updating = true;
22876 endUpdate : function(){
22877 this.updating = false;
22882 hideUnders : function(negOffset){
22884 this.shadow.hide();
22890 constrainXY : function(){
22891 if(this.constrain){
22892 var vw = Roo.lib.Dom.getViewWidth(),
22893 vh = Roo.lib.Dom.getViewHeight();
22894 var s = Roo.get(document).getScroll();
22896 var xy = this.getXY();
22897 var x = xy[0], y = xy[1];
22898 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22899 // only move it if it needs it
22901 // first validate right/bottom
22902 if((x + w) > vw+s.left){
22903 x = vw - w - this.shadowOffset;
22906 if((y + h) > vh+s.top){
22907 y = vh - h - this.shadowOffset;
22910 // then make sure top/left isn't negative
22921 var ay = this.avoidY;
22922 if(y <= ay && (y+h) >= ay){
22928 supr.setXY.call(this, xy);
22934 isVisible : function(){
22935 return this.visible;
22939 showAction : function(){
22940 this.visible = true; // track visibility to prevent getStyle calls
22941 if(this.useDisplay === true){
22942 this.setDisplayed("");
22943 }else if(this.lastXY){
22944 supr.setXY.call(this, this.lastXY);
22945 }else if(this.lastLT){
22946 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22951 hideAction : function(){
22952 this.visible = false;
22953 if(this.useDisplay === true){
22954 this.setDisplayed(false);
22956 this.setLeftTop(-10000,-10000);
22960 // overridden Element method
22961 setVisible : function(v, a, d, c, e){
22966 var cb = function(){
22971 }.createDelegate(this);
22972 supr.setVisible.call(this, true, true, d, cb, e);
22975 this.hideUnders(true);
22984 }.createDelegate(this);
22986 supr.setVisible.call(this, v, a, d, cb, e);
22995 storeXY : function(xy){
22996 delete this.lastLT;
23000 storeLeftTop : function(left, top){
23001 delete this.lastXY;
23002 this.lastLT = [left, top];
23006 beforeFx : function(){
23007 this.beforeAction();
23008 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23012 afterFx : function(){
23013 Roo.Layer.superclass.afterFx.apply(this, arguments);
23014 this.sync(this.isVisible());
23018 beforeAction : function(){
23019 if(!this.updating && this.shadow){
23020 this.shadow.hide();
23024 // overridden Element method
23025 setLeft : function(left){
23026 this.storeLeftTop(left, this.getTop(true));
23027 supr.setLeft.apply(this, arguments);
23031 setTop : function(top){
23032 this.storeLeftTop(this.getLeft(true), top);
23033 supr.setTop.apply(this, arguments);
23037 setLeftTop : function(left, top){
23038 this.storeLeftTop(left, top);
23039 supr.setLeftTop.apply(this, arguments);
23043 setXY : function(xy, a, d, c, e){
23045 this.beforeAction();
23047 var cb = this.createCB(c);
23048 supr.setXY.call(this, xy, a, d, cb, e);
23055 createCB : function(c){
23066 // overridden Element method
23067 setX : function(x, a, d, c, e){
23068 this.setXY([x, this.getY()], a, d, c, e);
23071 // overridden Element method
23072 setY : function(y, a, d, c, e){
23073 this.setXY([this.getX(), y], a, d, c, e);
23076 // overridden Element method
23077 setSize : function(w, h, a, d, c, e){
23078 this.beforeAction();
23079 var cb = this.createCB(c);
23080 supr.setSize.call(this, w, h, a, d, cb, e);
23086 // overridden Element method
23087 setWidth : function(w, a, d, c, e){
23088 this.beforeAction();
23089 var cb = this.createCB(c);
23090 supr.setWidth.call(this, w, a, d, cb, e);
23096 // overridden Element method
23097 setHeight : function(h, a, d, c, e){
23098 this.beforeAction();
23099 var cb = this.createCB(c);
23100 supr.setHeight.call(this, h, a, d, cb, e);
23106 // overridden Element method
23107 setBounds : function(x, y, w, h, a, d, c, e){
23108 this.beforeAction();
23109 var cb = this.createCB(c);
23111 this.storeXY([x, y]);
23112 supr.setXY.call(this, [x, y]);
23113 supr.setSize.call(this, w, h, a, d, cb, e);
23116 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23122 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23123 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23124 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23125 * @param {Number} zindex The new z-index to set
23126 * @return {this} The Layer
23128 setZIndex : function(zindex){
23129 this.zindex = zindex;
23130 this.setStyle("z-index", zindex + 2);
23132 this.shadow.setZIndex(zindex + 1);
23135 this.shim.setStyle("z-index", zindex);
23141 * Ext JS Library 1.1.1
23142 * Copyright(c) 2006-2007, Ext JS, LLC.
23144 * Originally Released Under LGPL - original licence link has changed is not relivant.
23147 * <script type="text/javascript">
23152 * @class Roo.Shadow
23153 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23154 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23155 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23157 * Create a new Shadow
23158 * @param {Object} config The config object
23160 Roo.Shadow = function(config){
23161 Roo.apply(this, config);
23162 if(typeof this.mode != "string"){
23163 this.mode = this.defaultMode;
23165 var o = this.offset, a = {h: 0};
23166 var rad = Math.floor(this.offset/2);
23167 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23173 a.l -= this.offset + rad;
23174 a.t -= this.offset + rad;
23185 a.l -= (this.offset - rad);
23186 a.t -= this.offset + rad;
23188 a.w -= (this.offset - rad)*2;
23199 a.l -= (this.offset - rad);
23200 a.t -= (this.offset - rad);
23202 a.w -= (this.offset + rad + 1);
23203 a.h -= (this.offset + rad);
23212 Roo.Shadow.prototype = {
23214 * @cfg {String} mode
23215 * The shadow display mode. Supports the following options:<br />
23216 * sides: Shadow displays on both sides and bottom only<br />
23217 * frame: Shadow displays equally on all four sides<br />
23218 * drop: Traditional bottom-right drop shadow (default)
23221 * @cfg {String} offset
23222 * The number of pixels to offset the shadow from the element (defaults to 4)
23227 defaultMode: "drop",
23230 * Displays the shadow under the target element
23231 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23233 show : function(target){
23234 target = Roo.get(target);
23236 this.el = Roo.Shadow.Pool.pull();
23237 if(this.el.dom.nextSibling != target.dom){
23238 this.el.insertBefore(target);
23241 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23243 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23246 target.getLeft(true),
23247 target.getTop(true),
23251 this.el.dom.style.display = "block";
23255 * Returns true if the shadow is visible, else false
23257 isVisible : function(){
23258 return this.el ? true : false;
23262 * Direct alignment when values are already available. Show must be called at least once before
23263 * calling this method to ensure it is initialized.
23264 * @param {Number} left The target element left position
23265 * @param {Number} top The target element top position
23266 * @param {Number} width The target element width
23267 * @param {Number} height The target element height
23269 realign : function(l, t, w, h){
23273 var a = this.adjusts, d = this.el.dom, s = d.style;
23275 s.left = (l+a.l)+"px";
23276 s.top = (t+a.t)+"px";
23277 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23279 if(s.width != sws || s.height != shs){
23283 var cn = d.childNodes;
23284 var sww = Math.max(0, (sw-12))+"px";
23285 cn[0].childNodes[1].style.width = sww;
23286 cn[1].childNodes[1].style.width = sww;
23287 cn[2].childNodes[1].style.width = sww;
23288 cn[1].style.height = Math.max(0, (sh-12))+"px";
23294 * Hides this shadow
23298 this.el.dom.style.display = "none";
23299 Roo.Shadow.Pool.push(this.el);
23305 * Adjust the z-index of this shadow
23306 * @param {Number} zindex The new z-index
23308 setZIndex : function(z){
23311 this.el.setStyle("z-index", z);
23316 // Private utility class that manages the internal Shadow cache
23317 Roo.Shadow.Pool = function(){
23319 var markup = Roo.isIE ?
23320 '<div class="x-ie-shadow"></div>' :
23321 '<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>';
23324 var sh = p.shift();
23326 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23327 sh.autoBoxAdjust = false;
23332 push : function(sh){
23338 * Ext JS Library 1.1.1
23339 * Copyright(c) 2006-2007, Ext JS, LLC.
23341 * Originally Released Under LGPL - original licence link has changed is not relivant.
23344 * <script type="text/javascript">
23348 * @class Roo.BoxComponent
23349 * @extends Roo.Component
23350 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23351 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23352 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23353 * layout containers.
23355 * @param {Roo.Element/String/Object} config The configuration options.
23357 Roo.BoxComponent = function(config){
23358 Roo.Component.call(this, config);
23362 * Fires after the component is resized.
23363 * @param {Roo.Component} this
23364 * @param {Number} adjWidth The box-adjusted width that was set
23365 * @param {Number} adjHeight The box-adjusted height that was set
23366 * @param {Number} rawWidth The width that was originally specified
23367 * @param {Number} rawHeight The height that was originally specified
23372 * Fires after the component is moved.
23373 * @param {Roo.Component} this
23374 * @param {Number} x The new x position
23375 * @param {Number} y The new y position
23381 Roo.extend(Roo.BoxComponent, Roo.Component, {
23382 // private, set in afterRender to signify that the component has been rendered
23384 // private, used to defer height settings to subclasses
23385 deferHeight: false,
23386 /** @cfg {Number} width
23387 * width (optional) size of component
23389 /** @cfg {Number} height
23390 * height (optional) size of component
23394 * Sets the width and height of the component. This method fires the resize event. This method can accept
23395 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23396 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23397 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23398 * @return {Roo.BoxComponent} this
23400 setSize : function(w, h){
23401 // support for standard size objects
23402 if(typeof w == 'object'){
23407 if(!this.boxReady){
23413 // prevent recalcs when not needed
23414 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23417 this.lastSize = {width: w, height: h};
23419 var adj = this.adjustSize(w, h);
23420 var aw = adj.width, ah = adj.height;
23421 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23422 var rz = this.getResizeEl();
23423 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23424 rz.setSize(aw, ah);
23425 }else if(!this.deferHeight && ah !== undefined){
23427 }else if(aw !== undefined){
23430 this.onResize(aw, ah, w, h);
23431 this.fireEvent('resize', this, aw, ah, w, h);
23437 * Gets the current size of the component's underlying element.
23438 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23440 getSize : function(){
23441 return this.el.getSize();
23445 * Gets the current XY position of the component's underlying element.
23446 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23447 * @return {Array} The XY position of the element (e.g., [100, 200])
23449 getPosition : function(local){
23450 if(local === true){
23451 return [this.el.getLeft(true), this.el.getTop(true)];
23453 return this.xy || this.el.getXY();
23457 * Gets the current box measurements of the component's underlying element.
23458 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23459 * @returns {Object} box An object in the format {x, y, width, height}
23461 getBox : function(local){
23462 var s = this.el.getSize();
23464 s.x = this.el.getLeft(true);
23465 s.y = this.el.getTop(true);
23467 var xy = this.xy || this.el.getXY();
23475 * Sets the current box measurements of the component's underlying element.
23476 * @param {Object} box An object in the format {x, y, width, height}
23477 * @returns {Roo.BoxComponent} this
23479 updateBox : function(box){
23480 this.setSize(box.width, box.height);
23481 this.setPagePosition(box.x, box.y);
23486 getResizeEl : function(){
23487 return this.resizeEl || this.el;
23491 getPositionEl : function(){
23492 return this.positionEl || this.el;
23496 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23497 * This method fires the move event.
23498 * @param {Number} left The new left
23499 * @param {Number} top The new top
23500 * @returns {Roo.BoxComponent} this
23502 setPosition : function(x, y){
23505 if(!this.boxReady){
23508 var adj = this.adjustPosition(x, y);
23509 var ax = adj.x, ay = adj.y;
23511 var el = this.getPositionEl();
23512 if(ax !== undefined || ay !== undefined){
23513 if(ax !== undefined && ay !== undefined){
23514 el.setLeftTop(ax, ay);
23515 }else if(ax !== undefined){
23517 }else if(ay !== undefined){
23520 this.onPosition(ax, ay);
23521 this.fireEvent('move', this, ax, ay);
23527 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23528 * This method fires the move event.
23529 * @param {Number} x The new x position
23530 * @param {Number} y The new y position
23531 * @returns {Roo.BoxComponent} this
23533 setPagePosition : function(x, y){
23536 if(!this.boxReady){
23539 if(x === undefined || y === undefined){ // cannot translate undefined points
23542 var p = this.el.translatePoints(x, y);
23543 this.setPosition(p.left, p.top);
23548 onRender : function(ct, position){
23549 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23551 this.resizeEl = Roo.get(this.resizeEl);
23553 if(this.positionEl){
23554 this.positionEl = Roo.get(this.positionEl);
23559 afterRender : function(){
23560 Roo.BoxComponent.superclass.afterRender.call(this);
23561 this.boxReady = true;
23562 this.setSize(this.width, this.height);
23563 if(this.x || this.y){
23564 this.setPosition(this.x, this.y);
23566 if(this.pageX || this.pageY){
23567 this.setPagePosition(this.pageX, this.pageY);
23572 * Force the component's size to recalculate based on the underlying element's current height and width.
23573 * @returns {Roo.BoxComponent} this
23575 syncSize : function(){
23576 delete this.lastSize;
23577 this.setSize(this.el.getWidth(), this.el.getHeight());
23582 * Called after the component is resized, this method is empty by default but can be implemented by any
23583 * subclass that needs to perform custom logic after a resize occurs.
23584 * @param {Number} adjWidth The box-adjusted width that was set
23585 * @param {Number} adjHeight The box-adjusted height that was set
23586 * @param {Number} rawWidth The width that was originally specified
23587 * @param {Number} rawHeight The height that was originally specified
23589 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23594 * Called after the component is moved, this method is empty by default but can be implemented by any
23595 * subclass that needs to perform custom logic after a move occurs.
23596 * @param {Number} x The new x position
23597 * @param {Number} y The new y position
23599 onPosition : function(x, y){
23604 adjustSize : function(w, h){
23605 if(this.autoWidth){
23608 if(this.autoHeight){
23611 return {width : w, height: h};
23615 adjustPosition : function(x, y){
23616 return {x : x, y: y};
23620 * Ext JS Library 1.1.1
23621 * Copyright(c) 2006-2007, Ext JS, LLC.
23623 * Originally Released Under LGPL - original licence link has changed is not relivant.
23626 * <script type="text/javascript">
23631 * @class Roo.SplitBar
23632 * @extends Roo.util.Observable
23633 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23637 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23638 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23639 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23640 split.minSize = 100;
23641 split.maxSize = 600;
23642 split.animate = true;
23643 split.on('moved', splitterMoved);
23646 * Create a new SplitBar
23647 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23648 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23649 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23650 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23651 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23652 position of the SplitBar).
23654 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23657 this.el = Roo.get(dragElement, true);
23658 this.el.dom.unselectable = "on";
23660 this.resizingEl = Roo.get(resizingElement, true);
23664 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23665 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23668 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23671 * The minimum size of the resizing element. (Defaults to 0)
23677 * The maximum size of the resizing element. (Defaults to 2000)
23680 this.maxSize = 2000;
23683 * Whether to animate the transition to the new size
23686 this.animate = false;
23689 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23692 this.useShim = false;
23697 if(!existingProxy){
23699 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23701 this.proxy = Roo.get(existingProxy).dom;
23704 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23707 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23710 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23713 this.dragSpecs = {};
23716 * @private The adapter to use to positon and resize elements
23718 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23719 this.adapter.init(this);
23721 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23723 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23724 this.el.addClass("x-splitbar-h");
23727 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23728 this.el.addClass("x-splitbar-v");
23734 * Fires when the splitter is moved (alias for {@link #event-moved})
23735 * @param {Roo.SplitBar} this
23736 * @param {Number} newSize the new width or height
23741 * Fires when the splitter is moved
23742 * @param {Roo.SplitBar} this
23743 * @param {Number} newSize the new width or height
23747 * @event beforeresize
23748 * Fires before the splitter is dragged
23749 * @param {Roo.SplitBar} this
23751 "beforeresize" : true,
23753 "beforeapply" : true
23756 Roo.util.Observable.call(this);
23759 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23760 onStartProxyDrag : function(x, y){
23761 this.fireEvent("beforeresize", this);
23763 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23765 o.enableDisplayMode("block");
23766 // all splitbars share the same overlay
23767 Roo.SplitBar.prototype.overlay = o;
23769 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23770 this.overlay.show();
23771 Roo.get(this.proxy).setDisplayed("block");
23772 var size = this.adapter.getElementSize(this);
23773 this.activeMinSize = this.getMinimumSize();;
23774 this.activeMaxSize = this.getMaximumSize();;
23775 var c1 = size - this.activeMinSize;
23776 var c2 = Math.max(this.activeMaxSize - size, 0);
23777 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23778 this.dd.resetConstraints();
23779 this.dd.setXConstraint(
23780 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23781 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23783 this.dd.setYConstraint(0, 0);
23785 this.dd.resetConstraints();
23786 this.dd.setXConstraint(0, 0);
23787 this.dd.setYConstraint(
23788 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23789 this.placement == Roo.SplitBar.TOP ? c2 : c1
23792 this.dragSpecs.startSize = size;
23793 this.dragSpecs.startPoint = [x, y];
23794 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23798 * @private Called after the drag operation by the DDProxy
23800 onEndProxyDrag : function(e){
23801 Roo.get(this.proxy).setDisplayed(false);
23802 var endPoint = Roo.lib.Event.getXY(e);
23804 this.overlay.hide();
23807 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23808 newSize = this.dragSpecs.startSize +
23809 (this.placement == Roo.SplitBar.LEFT ?
23810 endPoint[0] - this.dragSpecs.startPoint[0] :
23811 this.dragSpecs.startPoint[0] - endPoint[0]
23814 newSize = this.dragSpecs.startSize +
23815 (this.placement == Roo.SplitBar.TOP ?
23816 endPoint[1] - this.dragSpecs.startPoint[1] :
23817 this.dragSpecs.startPoint[1] - endPoint[1]
23820 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23821 if(newSize != this.dragSpecs.startSize){
23822 if(this.fireEvent('beforeapply', this, newSize) !== false){
23823 this.adapter.setElementSize(this, newSize);
23824 this.fireEvent("moved", this, newSize);
23825 this.fireEvent("resize", this, newSize);
23831 * Get the adapter this SplitBar uses
23832 * @return The adapter object
23834 getAdapter : function(){
23835 return this.adapter;
23839 * Set the adapter this SplitBar uses
23840 * @param {Object} adapter A SplitBar adapter object
23842 setAdapter : function(adapter){
23843 this.adapter = adapter;
23844 this.adapter.init(this);
23848 * Gets the minimum size for the resizing element
23849 * @return {Number} The minimum size
23851 getMinimumSize : function(){
23852 return this.minSize;
23856 * Sets the minimum size for the resizing element
23857 * @param {Number} minSize The minimum size
23859 setMinimumSize : function(minSize){
23860 this.minSize = minSize;
23864 * Gets the maximum size for the resizing element
23865 * @return {Number} The maximum size
23867 getMaximumSize : function(){
23868 return this.maxSize;
23872 * Sets the maximum size for the resizing element
23873 * @param {Number} maxSize The maximum size
23875 setMaximumSize : function(maxSize){
23876 this.maxSize = maxSize;
23880 * Sets the initialize size for the resizing element
23881 * @param {Number} size The initial size
23883 setCurrentSize : function(size){
23884 var oldAnimate = this.animate;
23885 this.animate = false;
23886 this.adapter.setElementSize(this, size);
23887 this.animate = oldAnimate;
23891 * Destroy this splitbar.
23892 * @param {Boolean} removeEl True to remove the element
23894 destroy : function(removeEl){
23896 this.shim.remove();
23899 this.proxy.parentNode.removeChild(this.proxy);
23907 * @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.
23909 Roo.SplitBar.createProxy = function(dir){
23910 var proxy = new Roo.Element(document.createElement("div"));
23911 proxy.unselectable();
23912 var cls = 'x-splitbar-proxy';
23913 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23914 document.body.appendChild(proxy.dom);
23919 * @class Roo.SplitBar.BasicLayoutAdapter
23920 * Default Adapter. It assumes the splitter and resizing element are not positioned
23921 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23923 Roo.SplitBar.BasicLayoutAdapter = function(){
23926 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23927 // do nothing for now
23928 init : function(s){
23932 * Called before drag operations to get the current size of the resizing element.
23933 * @param {Roo.SplitBar} s The SplitBar using this adapter
23935 getElementSize : function(s){
23936 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23937 return s.resizingEl.getWidth();
23939 return s.resizingEl.getHeight();
23944 * Called after drag operations to set the size of the resizing element.
23945 * @param {Roo.SplitBar} s The SplitBar using this adapter
23946 * @param {Number} newSize The new size to set
23947 * @param {Function} onComplete A function to be invoked when resizing is complete
23949 setElementSize : function(s, newSize, onComplete){
23950 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23952 s.resizingEl.setWidth(newSize);
23954 onComplete(s, newSize);
23957 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23962 s.resizingEl.setHeight(newSize);
23964 onComplete(s, newSize);
23967 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23974 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23975 * @extends Roo.SplitBar.BasicLayoutAdapter
23976 * Adapter that moves the splitter element to align with the resized sizing element.
23977 * Used with an absolute positioned SplitBar.
23978 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23979 * document.body, make sure you assign an id to the body element.
23981 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23982 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23983 this.container = Roo.get(container);
23986 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23987 init : function(s){
23988 this.basic.init(s);
23991 getElementSize : function(s){
23992 return this.basic.getElementSize(s);
23995 setElementSize : function(s, newSize, onComplete){
23996 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23999 moveSplitter : function(s){
24000 var yes = Roo.SplitBar;
24001 switch(s.placement){
24003 s.el.setX(s.resizingEl.getRight());
24006 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24009 s.el.setY(s.resizingEl.getBottom());
24012 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24019 * Orientation constant - Create a vertical SplitBar
24023 Roo.SplitBar.VERTICAL = 1;
24026 * Orientation constant - Create a horizontal SplitBar
24030 Roo.SplitBar.HORIZONTAL = 2;
24033 * Placement constant - The resizing element is to the left of the splitter element
24037 Roo.SplitBar.LEFT = 1;
24040 * Placement constant - The resizing element is to the right of the splitter element
24044 Roo.SplitBar.RIGHT = 2;
24047 * Placement constant - The resizing element is positioned above the splitter element
24051 Roo.SplitBar.TOP = 3;
24054 * Placement constant - The resizing element is positioned under splitter element
24058 Roo.SplitBar.BOTTOM = 4;
24061 * Ext JS Library 1.1.1
24062 * Copyright(c) 2006-2007, Ext JS, LLC.
24064 * Originally Released Under LGPL - original licence link has changed is not relivant.
24067 * <script type="text/javascript">
24072 * @extends Roo.util.Observable
24073 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24074 * This class also supports single and multi selection modes. <br>
24075 * Create a data model bound view:
24077 var store = new Roo.data.Store(...);
24079 var view = new Roo.View({
24081 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24083 singleSelect: true,
24084 selectedClass: "ydataview-selected",
24088 // listen for node click?
24089 view.on("click", function(vw, index, node, e){
24090 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24094 dataModel.load("foobar.xml");
24096 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24098 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24099 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24101 * Note: old style constructor is still suported (container, template, config)
24104 * Create a new View
24105 * @param {Object} config The config object
24108 Roo.View = function(config, depreciated_tpl, depreciated_config){
24110 if (typeof(depreciated_tpl) == 'undefined') {
24111 // new way.. - universal constructor.
24112 Roo.apply(this, config);
24113 this.el = Roo.get(this.el);
24116 this.el = Roo.get(config);
24117 this.tpl = depreciated_tpl;
24118 Roo.apply(this, depreciated_config);
24122 if(typeof(this.tpl) == "string"){
24123 this.tpl = new Roo.Template(this.tpl);
24125 // support xtype ctors..
24126 this.tpl = new Roo.factory(this.tpl, Roo);
24130 this.tpl.compile();
24137 * @event beforeclick
24138 * Fires before a click is processed. Returns false to cancel the default action.
24139 * @param {Roo.View} this
24140 * @param {Number} index The index of the target node
24141 * @param {HTMLElement} node The target node
24142 * @param {Roo.EventObject} e The raw event object
24144 "beforeclick" : true,
24147 * Fires when a template node is clicked.
24148 * @param {Roo.View} this
24149 * @param {Number} index The index of the target node
24150 * @param {HTMLElement} node The target node
24151 * @param {Roo.EventObject} e The raw event object
24156 * Fires when a template node is double clicked.
24157 * @param {Roo.View} this
24158 * @param {Number} index The index of the target node
24159 * @param {HTMLElement} node The target node
24160 * @param {Roo.EventObject} e The raw event object
24164 * @event contextmenu
24165 * Fires when a template node is right clicked.
24166 * @param {Roo.View} this
24167 * @param {Number} index The index of the target node
24168 * @param {HTMLElement} node The target node
24169 * @param {Roo.EventObject} e The raw event object
24171 "contextmenu" : true,
24173 * @event selectionchange
24174 * Fires when the selected nodes change.
24175 * @param {Roo.View} this
24176 * @param {Array} selections Array of the selected nodes
24178 "selectionchange" : true,
24181 * @event beforeselect
24182 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24183 * @param {Roo.View} this
24184 * @param {HTMLElement} node The node to be selected
24185 * @param {Array} selections Array of currently selected nodes
24187 "beforeselect" : true,
24189 * @event preparedata
24190 * Fires on every row to render, to allow you to change the data.
24191 * @param {Roo.View} this
24192 * @param {Object} data to be rendered (change this)
24194 "preparedata" : true
24198 "click": this.onClick,
24199 "dblclick": this.onDblClick,
24200 "contextmenu": this.onContextMenu,
24204 this.selections = [];
24206 this.cmp = new Roo.CompositeElementLite([]);
24208 this.store = Roo.factory(this.store, Roo.data);
24209 this.setStore(this.store, true);
24211 Roo.View.superclass.constructor.call(this);
24214 Roo.extend(Roo.View, Roo.util.Observable, {
24217 * @cfg {Roo.data.Store} store Data store to load data from.
24222 * @cfg {String|Roo.Element} el The container element.
24227 * @cfg {String|Roo.Template} tpl The template used by this View
24231 * @cfg {String} dataName the named area of the template to use as the data area
24232 * Works with domtemplates roo-name="name"
24236 * @cfg {String} selectedClass The css class to add to selected nodes
24238 selectedClass : "x-view-selected",
24240 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24245 * @cfg {String} text to display on mask (default Loading)
24249 * @cfg {Boolean} multiSelect Allow multiple selection
24251 multiSelect : false,
24253 * @cfg {Boolean} singleSelect Allow single selection
24255 singleSelect: false,
24258 * @cfg {Boolean} toggleSelect - selecting
24260 toggleSelect : false,
24263 * Returns the element this view is bound to.
24264 * @return {Roo.Element}
24266 getEl : function(){
24271 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24273 refresh : function(){
24276 // if we are using something like 'domtemplate', then
24277 // the what gets used is:
24278 // t.applySubtemplate(NAME, data, wrapping data..)
24279 // the outer template then get' applied with
24280 // the store 'extra data'
24281 // and the body get's added to the
24282 // roo-name="data" node?
24283 // <span class='roo-tpl-{name}'></span> ?????
24287 this.clearSelections();
24288 this.el.update("");
24290 var records = this.store.getRange();
24291 if(records.length < 1) {
24293 // is this valid?? = should it render a template??
24295 this.el.update(this.emptyText);
24299 if (this.dataName) {
24300 this.el.update(t.apply(this.store.meta)); //????
24301 el = this.el.child('.roo-tpl-' + this.dataName);
24304 for(var i = 0, len = records.length; i < len; i++){
24305 var data = this.prepareData(records[i].data, i, records[i]);
24306 this.fireEvent("preparedata", this, data, i, records[i]);
24307 html[html.length] = Roo.util.Format.trim(
24309 t.applySubtemplate(this.dataName, data, this.store.meta) :
24316 el.update(html.join(""));
24317 this.nodes = el.dom.childNodes;
24318 this.updateIndexes(0);
24322 * Function to override to reformat the data that is sent to
24323 * the template for each node.
24324 * DEPRICATED - use the preparedata event handler.
24325 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24326 * a JSON object for an UpdateManager bound view).
24328 prepareData : function(data, index, record)
24330 this.fireEvent("preparedata", this, data, index, record);
24334 onUpdate : function(ds, record){
24335 this.clearSelections();
24336 var index = this.store.indexOf(record);
24337 var n = this.nodes[index];
24338 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24339 n.parentNode.removeChild(n);
24340 this.updateIndexes(index, index);
24346 onAdd : function(ds, records, index)
24348 this.clearSelections();
24349 if(this.nodes.length == 0){
24353 var n = this.nodes[index];
24354 for(var i = 0, len = records.length; i < len; i++){
24355 var d = this.prepareData(records[i].data, i, records[i]);
24357 this.tpl.insertBefore(n, d);
24360 this.tpl.append(this.el, d);
24363 this.updateIndexes(index);
24366 onRemove : function(ds, record, index){
24367 this.clearSelections();
24368 var el = this.dataName ?
24369 this.el.child('.roo-tpl-' + this.dataName) :
24371 el.dom.removeChild(this.nodes[index]);
24372 this.updateIndexes(index);
24376 * Refresh an individual node.
24377 * @param {Number} index
24379 refreshNode : function(index){
24380 this.onUpdate(this.store, this.store.getAt(index));
24383 updateIndexes : function(startIndex, endIndex){
24384 var ns = this.nodes;
24385 startIndex = startIndex || 0;
24386 endIndex = endIndex || ns.length - 1;
24387 for(var i = startIndex; i <= endIndex; i++){
24388 ns[i].nodeIndex = i;
24393 * Changes the data store this view uses and refresh the view.
24394 * @param {Store} store
24396 setStore : function(store, initial){
24397 if(!initial && this.store){
24398 this.store.un("datachanged", this.refresh);
24399 this.store.un("add", this.onAdd);
24400 this.store.un("remove", this.onRemove);
24401 this.store.un("update", this.onUpdate);
24402 this.store.un("clear", this.refresh);
24403 this.store.un("beforeload", this.onBeforeLoad);
24404 this.store.un("load", this.onLoad);
24405 this.store.un("loadexception", this.onLoad);
24409 store.on("datachanged", this.refresh, this);
24410 store.on("add", this.onAdd, this);
24411 store.on("remove", this.onRemove, this);
24412 store.on("update", this.onUpdate, this);
24413 store.on("clear", this.refresh, this);
24414 store.on("beforeload", this.onBeforeLoad, this);
24415 store.on("load", this.onLoad, this);
24416 store.on("loadexception", this.onLoad, this);
24424 * onbeforeLoad - masks the loading area.
24427 onBeforeLoad : function()
24429 this.el.update("");
24430 this.el.mask(this.mask ? this.mask : "Loading" );
24432 onLoad : function ()
24439 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24440 * @param {HTMLElement} node
24441 * @return {HTMLElement} The template node
24443 findItemFromChild : function(node){
24444 var el = this.dataName ?
24445 this.el.child('.roo-tpl-' + this.dataName,true) :
24448 if(!node || node.parentNode == el){
24451 var p = node.parentNode;
24452 while(p && p != el){
24453 if(p.parentNode == el){
24462 onClick : function(e){
24463 var item = this.findItemFromChild(e.getTarget());
24465 var index = this.indexOf(item);
24466 if(this.onItemClick(item, index, e) !== false){
24467 this.fireEvent("click", this, index, item, e);
24470 this.clearSelections();
24475 onContextMenu : function(e){
24476 var item = this.findItemFromChild(e.getTarget());
24478 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24483 onDblClick : function(e){
24484 var item = this.findItemFromChild(e.getTarget());
24486 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24490 onItemClick : function(item, index, e)
24492 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24495 if (this.toggleSelect) {
24496 var m = this.isSelected(item) ? 'unselect' : 'select';
24499 _t[m](item, true, false);
24502 if(this.multiSelect || this.singleSelect){
24503 if(this.multiSelect && e.shiftKey && this.lastSelection){
24504 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24506 this.select(item, this.multiSelect && e.ctrlKey);
24507 this.lastSelection = item;
24509 e.preventDefault();
24515 * Get the number of selected nodes.
24518 getSelectionCount : function(){
24519 return this.selections.length;
24523 * Get the currently selected nodes.
24524 * @return {Array} An array of HTMLElements
24526 getSelectedNodes : function(){
24527 return this.selections;
24531 * Get the indexes of the selected nodes.
24534 getSelectedIndexes : function(){
24535 var indexes = [], s = this.selections;
24536 for(var i = 0, len = s.length; i < len; i++){
24537 indexes.push(s[i].nodeIndex);
24543 * Clear all selections
24544 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24546 clearSelections : function(suppressEvent){
24547 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24548 this.cmp.elements = this.selections;
24549 this.cmp.removeClass(this.selectedClass);
24550 this.selections = [];
24551 if(!suppressEvent){
24552 this.fireEvent("selectionchange", this, this.selections);
24558 * Returns true if the passed node is selected
24559 * @param {HTMLElement/Number} node The node or node index
24560 * @return {Boolean}
24562 isSelected : function(node){
24563 var s = this.selections;
24567 node = this.getNode(node);
24568 return s.indexOf(node) !== -1;
24573 * @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
24574 * @param {Boolean} keepExisting (optional) true to keep existing selections
24575 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24577 select : function(nodeInfo, keepExisting, suppressEvent){
24578 if(nodeInfo instanceof Array){
24580 this.clearSelections(true);
24582 for(var i = 0, len = nodeInfo.length; i < len; i++){
24583 this.select(nodeInfo[i], true, true);
24587 var node = this.getNode(nodeInfo);
24588 if(!node || this.isSelected(node)){
24589 return; // already selected.
24592 this.clearSelections(true);
24594 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24595 Roo.fly(node).addClass(this.selectedClass);
24596 this.selections.push(node);
24597 if(!suppressEvent){
24598 this.fireEvent("selectionchange", this, this.selections);
24606 * @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
24607 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24608 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24610 unselect : function(nodeInfo, keepExisting, suppressEvent)
24612 if(nodeInfo instanceof Array){
24613 Roo.each(this.selections, function(s) {
24614 this.unselect(s, nodeInfo);
24618 var node = this.getNode(nodeInfo);
24619 if(!node || !this.isSelected(node)){
24620 Roo.log("not selected");
24621 return; // not selected.
24625 Roo.each(this.selections, function(s) {
24627 Roo.fly(node).removeClass(this.selectedClass);
24634 this.selections= ns;
24635 this.fireEvent("selectionchange", this, this.selections);
24639 * Gets a template node.
24640 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24641 * @return {HTMLElement} The node or null if it wasn't found
24643 getNode : function(nodeInfo){
24644 if(typeof nodeInfo == "string"){
24645 return document.getElementById(nodeInfo);
24646 }else if(typeof nodeInfo == "number"){
24647 return this.nodes[nodeInfo];
24653 * Gets a range template nodes.
24654 * @param {Number} startIndex
24655 * @param {Number} endIndex
24656 * @return {Array} An array of nodes
24658 getNodes : function(start, end){
24659 var ns = this.nodes;
24660 start = start || 0;
24661 end = typeof end == "undefined" ? ns.length - 1 : end;
24664 for(var i = start; i <= end; i++){
24668 for(var i = start; i >= end; i--){
24676 * Finds the index of the passed node
24677 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24678 * @return {Number} The index of the node or -1
24680 indexOf : function(node){
24681 node = this.getNode(node);
24682 if(typeof node.nodeIndex == "number"){
24683 return node.nodeIndex;
24685 var ns = this.nodes;
24686 for(var i = 0, len = ns.length; i < len; i++){
24696 * Ext JS Library 1.1.1
24697 * Copyright(c) 2006-2007, Ext JS, LLC.
24699 * Originally Released Under LGPL - original licence link has changed is not relivant.
24702 * <script type="text/javascript">
24706 * @class Roo.JsonView
24707 * @extends Roo.View
24708 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24710 var view = new Roo.JsonView({
24711 container: "my-element",
24712 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24717 // listen for node click?
24718 view.on("click", function(vw, index, node, e){
24719 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24722 // direct load of JSON data
24723 view.load("foobar.php");
24725 // Example from my blog list
24726 var tpl = new Roo.Template(
24727 '<div class="entry">' +
24728 '<a class="entry-title" href="{link}">{title}</a>' +
24729 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24730 "</div><hr />"
24733 var moreView = new Roo.JsonView({
24734 container : "entry-list",
24738 moreView.on("beforerender", this.sortEntries, this);
24740 url: "/blog/get-posts.php",
24741 params: "allposts=true",
24742 text: "Loading Blog Entries..."
24746 * Note: old code is supported with arguments : (container, template, config)
24750 * Create a new JsonView
24752 * @param {Object} config The config object
24755 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24758 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24760 var um = this.el.getUpdateManager();
24761 um.setRenderer(this);
24762 um.on("update", this.onLoad, this);
24763 um.on("failure", this.onLoadException, this);
24766 * @event beforerender
24767 * Fires before rendering of the downloaded JSON data.
24768 * @param {Roo.JsonView} this
24769 * @param {Object} data The JSON data loaded
24773 * Fires when data is loaded.
24774 * @param {Roo.JsonView} this
24775 * @param {Object} data The JSON data loaded
24776 * @param {Object} response The raw Connect response object
24779 * @event loadexception
24780 * Fires when loading fails.
24781 * @param {Roo.JsonView} this
24782 * @param {Object} response The raw Connect response object
24785 'beforerender' : true,
24787 'loadexception' : true
24790 Roo.extend(Roo.JsonView, Roo.View, {
24792 * @type {String} The root property in the loaded JSON object that contains the data
24797 * Refreshes the view.
24799 refresh : function(){
24800 this.clearSelections();
24801 this.el.update("");
24803 var o = this.jsonData;
24804 if(o && o.length > 0){
24805 for(var i = 0, len = o.length; i < len; i++){
24806 var data = this.prepareData(o[i], i, o);
24807 html[html.length] = this.tpl.apply(data);
24810 html.push(this.emptyText);
24812 this.el.update(html.join(""));
24813 this.nodes = this.el.dom.childNodes;
24814 this.updateIndexes(0);
24818 * 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.
24819 * @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:
24822 url: "your-url.php",
24823 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24824 callback: yourFunction,
24825 scope: yourObject, //(optional scope)
24828 text: "Loading...",
24833 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24834 * 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.
24835 * @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}
24836 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24837 * @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.
24840 var um = this.el.getUpdateManager();
24841 um.update.apply(um, arguments);
24844 render : function(el, response){
24845 this.clearSelections();
24846 this.el.update("");
24849 o = Roo.util.JSON.decode(response.responseText);
24852 o = o[this.jsonRoot];
24857 * The current JSON data or null
24860 this.beforeRender();
24865 * Get the number of records in the current JSON dataset
24868 getCount : function(){
24869 return this.jsonData ? this.jsonData.length : 0;
24873 * Returns the JSON object for the specified node(s)
24874 * @param {HTMLElement/Array} node The node or an array of nodes
24875 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24876 * you get the JSON object for the node
24878 getNodeData : function(node){
24879 if(node instanceof Array){
24881 for(var i = 0, len = node.length; i < len; i++){
24882 data.push(this.getNodeData(node[i]));
24886 return this.jsonData[this.indexOf(node)] || null;
24889 beforeRender : function(){
24890 this.snapshot = this.jsonData;
24892 this.sort.apply(this, this.sortInfo);
24894 this.fireEvent("beforerender", this, this.jsonData);
24897 onLoad : function(el, o){
24898 this.fireEvent("load", this, this.jsonData, o);
24901 onLoadException : function(el, o){
24902 this.fireEvent("loadexception", this, o);
24906 * Filter the data by a specific property.
24907 * @param {String} property A property on your JSON objects
24908 * @param {String/RegExp} value Either string that the property values
24909 * should start with, or a RegExp to test against the property
24911 filter : function(property, value){
24914 var ss = this.snapshot;
24915 if(typeof value == "string"){
24916 var vlen = value.length;
24918 this.clearFilter();
24921 value = value.toLowerCase();
24922 for(var i = 0, len = ss.length; i < len; i++){
24924 if(o[property].substr(0, vlen).toLowerCase() == value){
24928 } else if(value.exec){ // regex?
24929 for(var i = 0, len = ss.length; i < len; i++){
24931 if(value.test(o[property])){
24938 this.jsonData = data;
24944 * Filter by a function. The passed function will be called with each
24945 * object in the current dataset. If the function returns true the value is kept,
24946 * otherwise it is filtered.
24947 * @param {Function} fn
24948 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24950 filterBy : function(fn, scope){
24953 var ss = this.snapshot;
24954 for(var i = 0, len = ss.length; i < len; i++){
24956 if(fn.call(scope || this, o)){
24960 this.jsonData = data;
24966 * Clears the current filter.
24968 clearFilter : function(){
24969 if(this.snapshot && this.jsonData != this.snapshot){
24970 this.jsonData = this.snapshot;
24977 * Sorts the data for this view and refreshes it.
24978 * @param {String} property A property on your JSON objects to sort on
24979 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24980 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24982 sort : function(property, dir, sortType){
24983 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24986 var dsc = dir && dir.toLowerCase() == "desc";
24987 var f = function(o1, o2){
24988 var v1 = sortType ? sortType(o1[p]) : o1[p];
24989 var v2 = sortType ? sortType(o2[p]) : o2[p];
24992 return dsc ? +1 : -1;
24993 } else if(v1 > v2){
24994 return dsc ? -1 : +1;
24999 this.jsonData.sort(f);
25001 if(this.jsonData != this.snapshot){
25002 this.snapshot.sort(f);
25008 * Ext JS Library 1.1.1
25009 * Copyright(c) 2006-2007, Ext JS, LLC.
25011 * Originally Released Under LGPL - original licence link has changed is not relivant.
25014 * <script type="text/javascript">
25019 * @class Roo.ColorPalette
25020 * @extends Roo.Component
25021 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25022 * Here's an example of typical usage:
25024 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25025 cp.render('my-div');
25027 cp.on('select', function(palette, selColor){
25028 // do something with selColor
25032 * Create a new ColorPalette
25033 * @param {Object} config The config object
25035 Roo.ColorPalette = function(config){
25036 Roo.ColorPalette.superclass.constructor.call(this, config);
25040 * Fires when a color is selected
25041 * @param {ColorPalette} this
25042 * @param {String} color The 6-digit color hex code (without the # symbol)
25048 this.on("select", this.handler, this.scope, true);
25051 Roo.extend(Roo.ColorPalette, Roo.Component, {
25053 * @cfg {String} itemCls
25054 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25056 itemCls : "x-color-palette",
25058 * @cfg {String} value
25059 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25060 * the hex codes are case-sensitive.
25063 clickEvent:'click',
25065 ctype: "Roo.ColorPalette",
25068 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25070 allowReselect : false,
25073 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25074 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25075 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25076 * of colors with the width setting until the box is symmetrical.</p>
25077 * <p>You can override individual colors if needed:</p>
25079 var cp = new Roo.ColorPalette();
25080 cp.colors[0] = "FF0000"; // change the first box to red
25083 Or you can provide a custom array of your own for complete control:
25085 var cp = new Roo.ColorPalette();
25086 cp.colors = ["000000", "993300", "333300"];
25091 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25092 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25093 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25094 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25095 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25099 onRender : function(container, position){
25100 var t = new Roo.MasterTemplate(
25101 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25103 var c = this.colors;
25104 for(var i = 0, len = c.length; i < len; i++){
25107 var el = document.createElement("div");
25108 el.className = this.itemCls;
25110 container.dom.insertBefore(el, position);
25111 this.el = Roo.get(el);
25112 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25113 if(this.clickEvent != 'click'){
25114 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25119 afterRender : function(){
25120 Roo.ColorPalette.superclass.afterRender.call(this);
25122 var s = this.value;
25129 handleClick : function(e, t){
25130 e.preventDefault();
25131 if(!this.disabled){
25132 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25133 this.select(c.toUpperCase());
25138 * Selects the specified color in the palette (fires the select event)
25139 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25141 select : function(color){
25142 color = color.replace("#", "");
25143 if(color != this.value || this.allowReselect){
25146 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25148 el.child("a.color-"+color).addClass("x-color-palette-sel");
25149 this.value = color;
25150 this.fireEvent("select", this, color);
25155 * Ext JS Library 1.1.1
25156 * Copyright(c) 2006-2007, Ext JS, LLC.
25158 * Originally Released Under LGPL - original licence link has changed is not relivant.
25161 * <script type="text/javascript">
25165 * @class Roo.DatePicker
25166 * @extends Roo.Component
25167 * Simple date picker class.
25169 * Create a new DatePicker
25170 * @param {Object} config The config object
25172 Roo.DatePicker = function(config){
25173 Roo.DatePicker.superclass.constructor.call(this, config);
25175 this.value = config && config.value ?
25176 config.value.clearTime() : new Date().clearTime();
25181 * Fires when a date is selected
25182 * @param {DatePicker} this
25183 * @param {Date} date The selected date
25187 * @event monthchange
25188 * Fires when the displayed month changes
25189 * @param {DatePicker} this
25190 * @param {Date} date The selected month
25192 'monthchange': true
25196 this.on("select", this.handler, this.scope || this);
25198 // build the disabledDatesRE
25199 if(!this.disabledDatesRE && this.disabledDates){
25200 var dd = this.disabledDates;
25202 for(var i = 0; i < dd.length; i++){
25204 if(i != dd.length-1) re += "|";
25206 this.disabledDatesRE = new RegExp(re + ")");
25210 Roo.extend(Roo.DatePicker, Roo.Component, {
25212 * @cfg {String} todayText
25213 * The text to display on the button that selects the current date (defaults to "Today")
25215 todayText : "Today",
25217 * @cfg {String} okText
25218 * The text to display on the ok button
25220 okText : " OK ", //   to give the user extra clicking room
25222 * @cfg {String} cancelText
25223 * The text to display on the cancel button
25225 cancelText : "Cancel",
25227 * @cfg {String} todayTip
25228 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25230 todayTip : "{0} (Spacebar)",
25232 * @cfg {Date} minDate
25233 * Minimum allowable date (JavaScript date object, defaults to null)
25237 * @cfg {Date} maxDate
25238 * Maximum allowable date (JavaScript date object, defaults to null)
25242 * @cfg {String} minText
25243 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25245 minText : "This date is before the minimum date",
25247 * @cfg {String} maxText
25248 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25250 maxText : "This date is after the maximum date",
25252 * @cfg {String} format
25253 * The default date format string which can be overriden for localization support. The format must be
25254 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25258 * @cfg {Array} disabledDays
25259 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25261 disabledDays : null,
25263 * @cfg {String} disabledDaysText
25264 * The tooltip to display when the date falls on a disabled day (defaults to "")
25266 disabledDaysText : "",
25268 * @cfg {RegExp} disabledDatesRE
25269 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25271 disabledDatesRE : null,
25273 * @cfg {String} disabledDatesText
25274 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25276 disabledDatesText : "",
25278 * @cfg {Boolean} constrainToViewport
25279 * True to constrain the date picker to the viewport (defaults to true)
25281 constrainToViewport : true,
25283 * @cfg {Array} monthNames
25284 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25286 monthNames : Date.monthNames,
25288 * @cfg {Array} dayNames
25289 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25291 dayNames : Date.dayNames,
25293 * @cfg {String} nextText
25294 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25296 nextText: 'Next Month (Control+Right)',
25298 * @cfg {String} prevText
25299 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25301 prevText: 'Previous Month (Control+Left)',
25303 * @cfg {String} monthYearText
25304 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25306 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25308 * @cfg {Number} startDay
25309 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25313 * @cfg {Bool} showClear
25314 * Show a clear button (usefull for date form elements that can be blank.)
25320 * Sets the value of the date field
25321 * @param {Date} value The date to set
25323 setValue : function(value){
25324 var old = this.value;
25326 if (typeof(value) == 'string') {
25328 value = Date.parseDate(value, this.format);
25331 value = new Date();
25334 this.value = value.clearTime(true);
25336 this.update(this.value);
25341 * Gets the current selected value of the date field
25342 * @return {Date} The selected date
25344 getValue : function(){
25349 focus : function(){
25351 this.update(this.activeDate);
25356 onRender : function(container, position){
25359 '<table cellspacing="0">',
25360 '<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>',
25361 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25362 var dn = this.dayNames;
25363 for(var i = 0; i < 7; i++){
25364 var d = this.startDay+i;
25368 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25370 m[m.length] = "</tr></thead><tbody><tr>";
25371 for(var i = 0; i < 42; i++) {
25372 if(i % 7 == 0 && i != 0){
25373 m[m.length] = "</tr><tr>";
25375 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25377 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25378 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25380 var el = document.createElement("div");
25381 el.className = "x-date-picker";
25382 el.innerHTML = m.join("");
25384 container.dom.insertBefore(el, position);
25386 this.el = Roo.get(el);
25387 this.eventEl = Roo.get(el.firstChild);
25389 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25390 handler: this.showPrevMonth,
25392 preventDefault:true,
25396 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25397 handler: this.showNextMonth,
25399 preventDefault:true,
25403 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25405 this.monthPicker = this.el.down('div.x-date-mp');
25406 this.monthPicker.enableDisplayMode('block');
25408 var kn = new Roo.KeyNav(this.eventEl, {
25409 "left" : function(e){
25411 this.showPrevMonth() :
25412 this.update(this.activeDate.add("d", -1));
25415 "right" : function(e){
25417 this.showNextMonth() :
25418 this.update(this.activeDate.add("d", 1));
25421 "up" : function(e){
25423 this.showNextYear() :
25424 this.update(this.activeDate.add("d", -7));
25427 "down" : function(e){
25429 this.showPrevYear() :
25430 this.update(this.activeDate.add("d", 7));
25433 "pageUp" : function(e){
25434 this.showNextMonth();
25437 "pageDown" : function(e){
25438 this.showPrevMonth();
25441 "enter" : function(e){
25442 e.stopPropagation();
25449 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25451 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25453 this.el.unselectable();
25455 this.cells = this.el.select("table.x-date-inner tbody td");
25456 this.textNodes = this.el.query("table.x-date-inner tbody span");
25458 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25460 tooltip: this.monthYearText
25463 this.mbtn.on('click', this.showMonthPicker, this);
25464 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25467 var today = (new Date()).dateFormat(this.format);
25469 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25470 if (this.showClear) {
25471 baseTb.add( new Roo.Toolbar.Fill());
25474 text: String.format(this.todayText, today),
25475 tooltip: String.format(this.todayTip, today),
25476 handler: this.selectToday,
25480 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25483 if (this.showClear) {
25485 baseTb.add( new Roo.Toolbar.Fill());
25488 cls: 'x-btn-icon x-btn-clear',
25489 handler: function() {
25491 this.fireEvent("select", this, '');
25501 this.update(this.value);
25504 createMonthPicker : function(){
25505 if(!this.monthPicker.dom.firstChild){
25506 var buf = ['<table border="0" cellspacing="0">'];
25507 for(var i = 0; i < 6; i++){
25509 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25510 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25512 '<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>' :
25513 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25517 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25519 '</button><button type="button" class="x-date-mp-cancel">',
25521 '</button></td></tr>',
25524 this.monthPicker.update(buf.join(''));
25525 this.monthPicker.on('click', this.onMonthClick, this);
25526 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25528 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25529 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25531 this.mpMonths.each(function(m, a, i){
25534 m.dom.xmonth = 5 + Math.round(i * .5);
25536 m.dom.xmonth = Math.round((i-1) * .5);
25542 showMonthPicker : function(){
25543 this.createMonthPicker();
25544 var size = this.el.getSize();
25545 this.monthPicker.setSize(size);
25546 this.monthPicker.child('table').setSize(size);
25548 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25549 this.updateMPMonth(this.mpSelMonth);
25550 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25551 this.updateMPYear(this.mpSelYear);
25553 this.monthPicker.slideIn('t', {duration:.2});
25556 updateMPYear : function(y){
25558 var ys = this.mpYears.elements;
25559 for(var i = 1; i <= 10; i++){
25560 var td = ys[i-1], y2;
25562 y2 = y + Math.round(i * .5);
25563 td.firstChild.innerHTML = y2;
25566 y2 = y - (5-Math.round(i * .5));
25567 td.firstChild.innerHTML = y2;
25570 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25574 updateMPMonth : function(sm){
25575 this.mpMonths.each(function(m, a, i){
25576 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25580 selectMPMonth: function(m){
25584 onMonthClick : function(e, t){
25586 var el = new Roo.Element(t), pn;
25587 if(el.is('button.x-date-mp-cancel')){
25588 this.hideMonthPicker();
25590 else if(el.is('button.x-date-mp-ok')){
25591 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25592 this.hideMonthPicker();
25594 else if(pn = el.up('td.x-date-mp-month', 2)){
25595 this.mpMonths.removeClass('x-date-mp-sel');
25596 pn.addClass('x-date-mp-sel');
25597 this.mpSelMonth = pn.dom.xmonth;
25599 else if(pn = el.up('td.x-date-mp-year', 2)){
25600 this.mpYears.removeClass('x-date-mp-sel');
25601 pn.addClass('x-date-mp-sel');
25602 this.mpSelYear = pn.dom.xyear;
25604 else if(el.is('a.x-date-mp-prev')){
25605 this.updateMPYear(this.mpyear-10);
25607 else if(el.is('a.x-date-mp-next')){
25608 this.updateMPYear(this.mpyear+10);
25612 onMonthDblClick : function(e, t){
25614 var el = new Roo.Element(t), pn;
25615 if(pn = el.up('td.x-date-mp-month', 2)){
25616 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25617 this.hideMonthPicker();
25619 else if(pn = el.up('td.x-date-mp-year', 2)){
25620 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25621 this.hideMonthPicker();
25625 hideMonthPicker : function(disableAnim){
25626 if(this.monthPicker){
25627 if(disableAnim === true){
25628 this.monthPicker.hide();
25630 this.monthPicker.slideOut('t', {duration:.2});
25636 showPrevMonth : function(e){
25637 this.update(this.activeDate.add("mo", -1));
25641 showNextMonth : function(e){
25642 this.update(this.activeDate.add("mo", 1));
25646 showPrevYear : function(){
25647 this.update(this.activeDate.add("y", -1));
25651 showNextYear : function(){
25652 this.update(this.activeDate.add("y", 1));
25656 handleMouseWheel : function(e){
25657 var delta = e.getWheelDelta();
25659 this.showPrevMonth();
25661 } else if(delta < 0){
25662 this.showNextMonth();
25668 handleDateClick : function(e, t){
25670 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25671 this.setValue(new Date(t.dateValue));
25672 this.fireEvent("select", this, this.value);
25677 selectToday : function(){
25678 this.setValue(new Date().clearTime());
25679 this.fireEvent("select", this, this.value);
25683 update : function(date)
25685 var vd = this.activeDate;
25686 this.activeDate = date;
25688 var t = date.getTime();
25689 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25690 this.cells.removeClass("x-date-selected");
25691 this.cells.each(function(c){
25692 if(c.dom.firstChild.dateValue == t){
25693 c.addClass("x-date-selected");
25694 setTimeout(function(){
25695 try{c.dom.firstChild.focus();}catch(e){}
25704 var days = date.getDaysInMonth();
25705 var firstOfMonth = date.getFirstDateOfMonth();
25706 var startingPos = firstOfMonth.getDay()-this.startDay;
25708 if(startingPos <= this.startDay){
25712 var pm = date.add("mo", -1);
25713 var prevStart = pm.getDaysInMonth()-startingPos;
25715 var cells = this.cells.elements;
25716 var textEls = this.textNodes;
25717 days += startingPos;
25719 // convert everything to numbers so it's fast
25720 var day = 86400000;
25721 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25722 var today = new Date().clearTime().getTime();
25723 var sel = date.clearTime().getTime();
25724 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25725 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25726 var ddMatch = this.disabledDatesRE;
25727 var ddText = this.disabledDatesText;
25728 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25729 var ddaysText = this.disabledDaysText;
25730 var format = this.format;
25732 var setCellClass = function(cal, cell){
25734 var t = d.getTime();
25735 cell.firstChild.dateValue = t;
25737 cell.className += " x-date-today";
25738 cell.title = cal.todayText;
25741 cell.className += " x-date-selected";
25742 setTimeout(function(){
25743 try{cell.firstChild.focus();}catch(e){}
25748 cell.className = " x-date-disabled";
25749 cell.title = cal.minText;
25753 cell.className = " x-date-disabled";
25754 cell.title = cal.maxText;
25758 if(ddays.indexOf(d.getDay()) != -1){
25759 cell.title = ddaysText;
25760 cell.className = " x-date-disabled";
25763 if(ddMatch && format){
25764 var fvalue = d.dateFormat(format);
25765 if(ddMatch.test(fvalue)){
25766 cell.title = ddText.replace("%0", fvalue);
25767 cell.className = " x-date-disabled";
25773 for(; i < startingPos; i++) {
25774 textEls[i].innerHTML = (++prevStart);
25775 d.setDate(d.getDate()+1);
25776 cells[i].className = "x-date-prevday";
25777 setCellClass(this, cells[i]);
25779 for(; i < days; i++){
25780 intDay = i - startingPos + 1;
25781 textEls[i].innerHTML = (intDay);
25782 d.setDate(d.getDate()+1);
25783 cells[i].className = "x-date-active";
25784 setCellClass(this, cells[i]);
25787 for(; i < 42; i++) {
25788 textEls[i].innerHTML = (++extraDays);
25789 d.setDate(d.getDate()+1);
25790 cells[i].className = "x-date-nextday";
25791 setCellClass(this, cells[i]);
25794 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25795 this.fireEvent('monthchange', this, date);
25797 if(!this.internalRender){
25798 var main = this.el.dom.firstChild;
25799 var w = main.offsetWidth;
25800 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25801 Roo.fly(main).setWidth(w);
25802 this.internalRender = true;
25803 // opera does not respect the auto grow header center column
25804 // then, after it gets a width opera refuses to recalculate
25805 // without a second pass
25806 if(Roo.isOpera && !this.secondPass){
25807 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25808 this.secondPass = true;
25809 this.update.defer(10, this, [date]);
25817 * Ext JS Library 1.1.1
25818 * Copyright(c) 2006-2007, Ext JS, LLC.
25820 * Originally Released Under LGPL - original licence link has changed is not relivant.
25823 * <script type="text/javascript">
25826 * @class Roo.TabPanel
25827 * @extends Roo.util.Observable
25828 * A lightweight tab container.
25832 // basic tabs 1, built from existing content
25833 var tabs = new Roo.TabPanel("tabs1");
25834 tabs.addTab("script", "View Script");
25835 tabs.addTab("markup", "View Markup");
25836 tabs.activate("script");
25838 // more advanced tabs, built from javascript
25839 var jtabs = new Roo.TabPanel("jtabs");
25840 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25842 // set up the UpdateManager
25843 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25844 var updater = tab2.getUpdateManager();
25845 updater.setDefaultUrl("ajax1.htm");
25846 tab2.on('activate', updater.refresh, updater, true);
25848 // Use setUrl for Ajax loading
25849 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25850 tab3.setUrl("ajax2.htm", null, true);
25853 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25856 jtabs.activate("jtabs-1");
25859 * Create a new TabPanel.
25860 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25861 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25863 Roo.TabPanel = function(container, config){
25865 * The container element for this TabPanel.
25866 * @type Roo.Element
25868 this.el = Roo.get(container, true);
25870 if(typeof config == "boolean"){
25871 this.tabPosition = config ? "bottom" : "top";
25873 Roo.apply(this, config);
25876 if(this.tabPosition == "bottom"){
25877 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25878 this.el.addClass("x-tabs-bottom");
25880 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25881 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25882 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25884 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25886 if(this.tabPosition != "bottom"){
25887 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25888 * @type Roo.Element
25890 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25891 this.el.addClass("x-tabs-top");
25895 this.bodyEl.setStyle("position", "relative");
25897 this.active = null;
25898 this.activateDelegate = this.activate.createDelegate(this);
25903 * Fires when the active tab changes
25904 * @param {Roo.TabPanel} this
25905 * @param {Roo.TabPanelItem} activePanel The new active tab
25909 * @event beforetabchange
25910 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25911 * @param {Roo.TabPanel} this
25912 * @param {Object} e Set cancel to true on this object to cancel the tab change
25913 * @param {Roo.TabPanelItem} tab The tab being changed to
25915 "beforetabchange" : true
25918 Roo.EventManager.onWindowResize(this.onResize, this);
25919 this.cpad = this.el.getPadding("lr");
25920 this.hiddenCount = 0;
25923 // toolbar on the tabbar support...
25924 if (this.toolbar) {
25925 var tcfg = this.toolbar;
25926 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25927 this.toolbar = new Roo.Toolbar(tcfg);
25928 if (Roo.isSafari) {
25929 var tbl = tcfg.container.child('table', true);
25930 tbl.setAttribute('width', '100%');
25937 Roo.TabPanel.superclass.constructor.call(this);
25940 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25942 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25944 tabPosition : "top",
25946 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25948 currentTabWidth : 0,
25950 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25954 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25958 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25960 preferredTabWidth : 175,
25962 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25964 resizeTabs : false,
25966 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25968 monitorResize : true,
25970 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25975 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25976 * @param {String} id The id of the div to use <b>or create</b>
25977 * @param {String} text The text for the tab
25978 * @param {String} content (optional) Content to put in the TabPanelItem body
25979 * @param {Boolean} closable (optional) True to create a close icon on the tab
25980 * @return {Roo.TabPanelItem} The created TabPanelItem
25982 addTab : function(id, text, content, closable){
25983 var item = new Roo.TabPanelItem(this, id, text, closable);
25984 this.addTabItem(item);
25986 item.setContent(content);
25992 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25993 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25994 * @return {Roo.TabPanelItem}
25996 getTab : function(id){
25997 return this.items[id];
26001 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26002 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26004 hideTab : function(id){
26005 var t = this.items[id];
26008 this.hiddenCount++;
26009 this.autoSizeTabs();
26014 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26015 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26017 unhideTab : function(id){
26018 var t = this.items[id];
26020 t.setHidden(false);
26021 this.hiddenCount--;
26022 this.autoSizeTabs();
26027 * Adds an existing {@link Roo.TabPanelItem}.
26028 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26030 addTabItem : function(item){
26031 this.items[item.id] = item;
26032 this.items.push(item);
26033 if(this.resizeTabs){
26034 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26035 this.autoSizeTabs();
26042 * Removes a {@link Roo.TabPanelItem}.
26043 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26045 removeTab : function(id){
26046 var items = this.items;
26047 var tab = items[id];
26048 if(!tab) { return; }
26049 var index = items.indexOf(tab);
26050 if(this.active == tab && items.length > 1){
26051 var newTab = this.getNextAvailable(index);
26056 this.stripEl.dom.removeChild(tab.pnode.dom);
26057 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26058 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26060 items.splice(index, 1);
26061 delete this.items[tab.id];
26062 tab.fireEvent("close", tab);
26063 tab.purgeListeners();
26064 this.autoSizeTabs();
26067 getNextAvailable : function(start){
26068 var items = this.items;
26070 // look for a next tab that will slide over to
26071 // replace the one being removed
26072 while(index < items.length){
26073 var item = items[++index];
26074 if(item && !item.isHidden()){
26078 // if one isn't found select the previous tab (on the left)
26081 var item = items[--index];
26082 if(item && !item.isHidden()){
26090 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26091 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26093 disableTab : function(id){
26094 var tab = this.items[id];
26095 if(tab && this.active != tab){
26101 * Enables a {@link Roo.TabPanelItem} that is disabled.
26102 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26104 enableTab : function(id){
26105 var tab = this.items[id];
26110 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26111 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26112 * @return {Roo.TabPanelItem} The TabPanelItem.
26114 activate : function(id){
26115 var tab = this.items[id];
26119 if(tab == this.active || tab.disabled){
26123 this.fireEvent("beforetabchange", this, e, tab);
26124 if(e.cancel !== true && !tab.disabled){
26126 this.active.hide();
26128 this.active = this.items[id];
26129 this.active.show();
26130 this.fireEvent("tabchange", this, this.active);
26136 * Gets the active {@link Roo.TabPanelItem}.
26137 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26139 getActiveTab : function(){
26140 return this.active;
26144 * Updates the tab body element to fit the height of the container element
26145 * for overflow scrolling
26146 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26148 syncHeight : function(targetHeight){
26149 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26150 var bm = this.bodyEl.getMargins();
26151 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26152 this.bodyEl.setHeight(newHeight);
26156 onResize : function(){
26157 if(this.monitorResize){
26158 this.autoSizeTabs();
26163 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26165 beginUpdate : function(){
26166 this.updating = true;
26170 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26172 endUpdate : function(){
26173 this.updating = false;
26174 this.autoSizeTabs();
26178 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26180 autoSizeTabs : function(){
26181 var count = this.items.length;
26182 var vcount = count - this.hiddenCount;
26183 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26184 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26185 var availWidth = Math.floor(w / vcount);
26186 var b = this.stripBody;
26187 if(b.getWidth() > w){
26188 var tabs = this.items;
26189 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26190 if(availWidth < this.minTabWidth){
26191 /*if(!this.sleft){ // incomplete scrolling code
26192 this.createScrollButtons();
26195 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26198 if(this.currentTabWidth < this.preferredTabWidth){
26199 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26205 * Returns the number of tabs in this TabPanel.
26208 getCount : function(){
26209 return this.items.length;
26213 * Resizes all the tabs to the passed width
26214 * @param {Number} The new width
26216 setTabWidth : function(width){
26217 this.currentTabWidth = width;
26218 for(var i = 0, len = this.items.length; i < len; i++) {
26219 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26224 * Destroys this TabPanel
26225 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26227 destroy : function(removeEl){
26228 Roo.EventManager.removeResizeListener(this.onResize, this);
26229 for(var i = 0, len = this.items.length; i < len; i++){
26230 this.items[i].purgeListeners();
26232 if(removeEl === true){
26233 this.el.update("");
26240 * @class Roo.TabPanelItem
26241 * @extends Roo.util.Observable
26242 * Represents an individual item (tab plus body) in a TabPanel.
26243 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26244 * @param {String} id The id of this TabPanelItem
26245 * @param {String} text The text for the tab of this TabPanelItem
26246 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26248 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26250 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26251 * @type Roo.TabPanel
26253 this.tabPanel = tabPanel;
26255 * The id for this TabPanelItem
26260 this.disabled = false;
26264 this.loaded = false;
26265 this.closable = closable;
26268 * The body element for this TabPanelItem.
26269 * @type Roo.Element
26271 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26272 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26273 this.bodyEl.setStyle("display", "block");
26274 this.bodyEl.setStyle("zoom", "1");
26277 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26279 this.el = Roo.get(els.el, true);
26280 this.inner = Roo.get(els.inner, true);
26281 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26282 this.pnode = Roo.get(els.el.parentNode, true);
26283 this.el.on("mousedown", this.onTabMouseDown, this);
26284 this.el.on("click", this.onTabClick, this);
26287 var c = Roo.get(els.close, true);
26288 c.dom.title = this.closeText;
26289 c.addClassOnOver("close-over");
26290 c.on("click", this.closeClick, this);
26296 * Fires when this tab becomes the active tab.
26297 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26298 * @param {Roo.TabPanelItem} this
26302 * @event beforeclose
26303 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26304 * @param {Roo.TabPanelItem} this
26305 * @param {Object} e Set cancel to true on this object to cancel the close.
26307 "beforeclose": true,
26310 * Fires when this tab is closed.
26311 * @param {Roo.TabPanelItem} this
26315 * @event deactivate
26316 * Fires when this tab is no longer the active tab.
26317 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26318 * @param {Roo.TabPanelItem} this
26320 "deactivate" : true
26322 this.hidden = false;
26324 Roo.TabPanelItem.superclass.constructor.call(this);
26327 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26328 purgeListeners : function(){
26329 Roo.util.Observable.prototype.purgeListeners.call(this);
26330 this.el.removeAllListeners();
26333 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26336 this.pnode.addClass("on");
26339 this.tabPanel.stripWrap.repaint();
26341 this.fireEvent("activate", this.tabPanel, this);
26345 * Returns true if this tab is the active tab.
26346 * @return {Boolean}
26348 isActive : function(){
26349 return this.tabPanel.getActiveTab() == this;
26353 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26356 this.pnode.removeClass("on");
26358 this.fireEvent("deactivate", this.tabPanel, this);
26361 hideAction : function(){
26362 this.bodyEl.hide();
26363 this.bodyEl.setStyle("position", "absolute");
26364 this.bodyEl.setLeft("-20000px");
26365 this.bodyEl.setTop("-20000px");
26368 showAction : function(){
26369 this.bodyEl.setStyle("position", "relative");
26370 this.bodyEl.setTop("");
26371 this.bodyEl.setLeft("");
26372 this.bodyEl.show();
26376 * Set the tooltip for the tab.
26377 * @param {String} tooltip The tab's tooltip
26379 setTooltip : function(text){
26380 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26381 this.textEl.dom.qtip = text;
26382 this.textEl.dom.removeAttribute('title');
26384 this.textEl.dom.title = text;
26388 onTabClick : function(e){
26389 e.preventDefault();
26390 this.tabPanel.activate(this.id);
26393 onTabMouseDown : function(e){
26394 e.preventDefault();
26395 this.tabPanel.activate(this.id);
26398 getWidth : function(){
26399 return this.inner.getWidth();
26402 setWidth : function(width){
26403 var iwidth = width - this.pnode.getPadding("lr");
26404 this.inner.setWidth(iwidth);
26405 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26406 this.pnode.setWidth(width);
26410 * Show or hide the tab
26411 * @param {Boolean} hidden True to hide or false to show.
26413 setHidden : function(hidden){
26414 this.hidden = hidden;
26415 this.pnode.setStyle("display", hidden ? "none" : "");
26419 * Returns true if this tab is "hidden"
26420 * @return {Boolean}
26422 isHidden : function(){
26423 return this.hidden;
26427 * Returns the text for this tab
26430 getText : function(){
26434 autoSize : function(){
26435 //this.el.beginMeasure();
26436 this.textEl.setWidth(1);
26437 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26438 //this.el.endMeasure();
26442 * Sets the text for the tab (Note: this also sets the tooltip text)
26443 * @param {String} text The tab's text and tooltip
26445 setText : function(text){
26447 this.textEl.update(text);
26448 this.setTooltip(text);
26449 if(!this.tabPanel.resizeTabs){
26454 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26456 activate : function(){
26457 this.tabPanel.activate(this.id);
26461 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26463 disable : function(){
26464 if(this.tabPanel.active != this){
26465 this.disabled = true;
26466 this.pnode.addClass("disabled");
26471 * Enables this TabPanelItem if it was previously disabled.
26473 enable : function(){
26474 this.disabled = false;
26475 this.pnode.removeClass("disabled");
26479 * Sets the content for this TabPanelItem.
26480 * @param {String} content The content
26481 * @param {Boolean} loadScripts true to look for and load scripts
26483 setContent : function(content, loadScripts){
26484 this.bodyEl.update(content, loadScripts);
26488 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26489 * @return {Roo.UpdateManager} The UpdateManager
26491 getUpdateManager : function(){
26492 return this.bodyEl.getUpdateManager();
26496 * Set a URL to be used to load the content for this TabPanelItem.
26497 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26498 * @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)
26499 * @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)
26500 * @return {Roo.UpdateManager} The UpdateManager
26502 setUrl : function(url, params, loadOnce){
26503 if(this.refreshDelegate){
26504 this.un('activate', this.refreshDelegate);
26506 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26507 this.on("activate", this.refreshDelegate);
26508 return this.bodyEl.getUpdateManager();
26512 _handleRefresh : function(url, params, loadOnce){
26513 if(!loadOnce || !this.loaded){
26514 var updater = this.bodyEl.getUpdateManager();
26515 updater.update(url, params, this._setLoaded.createDelegate(this));
26520 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26521 * Will fail silently if the setUrl method has not been called.
26522 * This does not activate the panel, just updates its content.
26524 refresh : function(){
26525 if(this.refreshDelegate){
26526 this.loaded = false;
26527 this.refreshDelegate();
26532 _setLoaded : function(){
26533 this.loaded = true;
26537 closeClick : function(e){
26540 this.fireEvent("beforeclose", this, o);
26541 if(o.cancel !== true){
26542 this.tabPanel.removeTab(this.id);
26546 * The text displayed in the tooltip for the close icon.
26549 closeText : "Close this tab"
26553 Roo.TabPanel.prototype.createStrip = function(container){
26554 var strip = document.createElement("div");
26555 strip.className = "x-tabs-wrap";
26556 container.appendChild(strip);
26560 Roo.TabPanel.prototype.createStripList = function(strip){
26561 // div wrapper for retard IE
26562 // returns the "tr" element.
26563 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26564 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26565 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26566 return strip.firstChild.firstChild.firstChild.firstChild;
26569 Roo.TabPanel.prototype.createBody = function(container){
26570 var body = document.createElement("div");
26571 Roo.id(body, "tab-body");
26572 Roo.fly(body).addClass("x-tabs-body");
26573 container.appendChild(body);
26577 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26578 var body = Roo.getDom(id);
26580 body = document.createElement("div");
26583 Roo.fly(body).addClass("x-tabs-item-body");
26584 bodyEl.insertBefore(body, bodyEl.firstChild);
26588 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26589 var td = document.createElement("td");
26590 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26591 //stripEl.appendChild(td);
26593 td.className = "x-tabs-closable";
26594 if(!this.closeTpl){
26595 this.closeTpl = new Roo.Template(
26596 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26597 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26598 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26601 var el = this.closeTpl.overwrite(td, {"text": text});
26602 var close = el.getElementsByTagName("div")[0];
26603 var inner = el.getElementsByTagName("em")[0];
26604 return {"el": el, "close": close, "inner": inner};
26607 this.tabTpl = new Roo.Template(
26608 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26609 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26612 var el = this.tabTpl.overwrite(td, {"text": text});
26613 var inner = el.getElementsByTagName("em")[0];
26614 return {"el": el, "inner": inner};
26618 * Ext JS Library 1.1.1
26619 * Copyright(c) 2006-2007, Ext JS, LLC.
26621 * Originally Released Under LGPL - original licence link has changed is not relivant.
26624 * <script type="text/javascript">
26628 * @class Roo.Button
26629 * @extends Roo.util.Observable
26630 * Simple Button class
26631 * @cfg {String} text The button text
26632 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26633 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26634 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26635 * @cfg {Object} scope The scope of the handler
26636 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26637 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26638 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26639 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26640 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26641 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26642 applies if enableToggle = true)
26643 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26644 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26645 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26647 * Create a new button
26648 * @param {Object} config The config object
26650 Roo.Button = function(renderTo, config)
26654 renderTo = config.renderTo || false;
26657 Roo.apply(this, config);
26661 * Fires when this button is clicked
26662 * @param {Button} this
26663 * @param {EventObject} e The click event
26668 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26669 * @param {Button} this
26670 * @param {Boolean} pressed
26675 * Fires when the mouse hovers over the button
26676 * @param {Button} this
26677 * @param {Event} e The event object
26679 'mouseover' : true,
26682 * Fires when the mouse exits the button
26683 * @param {Button} this
26684 * @param {Event} e The event object
26689 * Fires when the button is rendered
26690 * @param {Button} this
26695 this.menu = Roo.menu.MenuMgr.get(this.menu);
26697 // register listeners first!! - so render can be captured..
26698 Roo.util.Observable.call(this);
26700 this.render(renderTo);
26706 Roo.extend(Roo.Button, Roo.util.Observable, {
26712 * Read-only. True if this button is hidden
26717 * Read-only. True if this button is disabled
26722 * Read-only. True if this button is pressed (only if enableToggle = true)
26728 * @cfg {Number} tabIndex
26729 * The DOM tabIndex for this button (defaults to undefined)
26731 tabIndex : undefined,
26734 * @cfg {Boolean} enableToggle
26735 * True to enable pressed/not pressed toggling (defaults to false)
26737 enableToggle: false,
26739 * @cfg {Mixed} menu
26740 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26744 * @cfg {String} menuAlign
26745 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26747 menuAlign : "tl-bl?",
26750 * @cfg {String} iconCls
26751 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26753 iconCls : undefined,
26755 * @cfg {String} type
26756 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26761 menuClassTarget: 'tr',
26764 * @cfg {String} clickEvent
26765 * The type of event to map to the button's event handler (defaults to 'click')
26767 clickEvent : 'click',
26770 * @cfg {Boolean} handleMouseEvents
26771 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26773 handleMouseEvents : true,
26776 * @cfg {String} tooltipType
26777 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26779 tooltipType : 'qtip',
26782 * @cfg {String} cls
26783 * A CSS class to apply to the button's main element.
26787 * @cfg {Roo.Template} template (Optional)
26788 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26789 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26790 * require code modifications if required elements (e.g. a button) aren't present.
26794 render : function(renderTo){
26796 if(this.hideParent){
26797 this.parentEl = Roo.get(renderTo);
26799 if(!this.dhconfig){
26800 if(!this.template){
26801 if(!Roo.Button.buttonTemplate){
26802 // hideous table template
26803 Roo.Button.buttonTemplate = new Roo.Template(
26804 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26805 '<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>',
26806 "</tr></tbody></table>");
26808 this.template = Roo.Button.buttonTemplate;
26810 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26811 var btnEl = btn.child("button:first");
26812 btnEl.on('focus', this.onFocus, this);
26813 btnEl.on('blur', this.onBlur, this);
26815 btn.addClass(this.cls);
26818 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26821 btnEl.addClass(this.iconCls);
26823 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26826 if(this.tabIndex !== undefined){
26827 btnEl.dom.tabIndex = this.tabIndex;
26830 if(typeof this.tooltip == 'object'){
26831 Roo.QuickTips.tips(Roo.apply({
26835 btnEl.dom[this.tooltipType] = this.tooltip;
26839 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26843 this.el.dom.id = this.el.id = this.id;
26846 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26847 this.menu.on("show", this.onMenuShow, this);
26848 this.menu.on("hide", this.onMenuHide, this);
26850 btn.addClass("x-btn");
26851 if(Roo.isIE && !Roo.isIE7){
26852 this.autoWidth.defer(1, this);
26856 if(this.handleMouseEvents){
26857 btn.on("mouseover", this.onMouseOver, this);
26858 btn.on("mouseout", this.onMouseOut, this);
26859 btn.on("mousedown", this.onMouseDown, this);
26861 btn.on(this.clickEvent, this.onClick, this);
26862 //btn.on("mouseup", this.onMouseUp, this);
26869 Roo.ButtonToggleMgr.register(this);
26871 this.el.addClass("x-btn-pressed");
26874 var repeater = new Roo.util.ClickRepeater(btn,
26875 typeof this.repeat == "object" ? this.repeat : {}
26877 repeater.on("click", this.onClick, this);
26880 this.fireEvent('render', this);
26884 * Returns the button's underlying element
26885 * @return {Roo.Element} The element
26887 getEl : function(){
26892 * Destroys this Button and removes any listeners.
26894 destroy : function(){
26895 Roo.ButtonToggleMgr.unregister(this);
26896 this.el.removeAllListeners();
26897 this.purgeListeners();
26902 autoWidth : function(){
26904 this.el.setWidth("auto");
26905 if(Roo.isIE7 && Roo.isStrict){
26906 var ib = this.el.child('button');
26907 if(ib && ib.getWidth() > 20){
26909 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26914 this.el.beginMeasure();
26916 if(this.el.getWidth() < this.minWidth){
26917 this.el.setWidth(this.minWidth);
26920 this.el.endMeasure();
26927 * Assigns this button's click handler
26928 * @param {Function} handler The function to call when the button is clicked
26929 * @param {Object} scope (optional) Scope for the function passed in
26931 setHandler : function(handler, scope){
26932 this.handler = handler;
26933 this.scope = scope;
26937 * Sets this button's text
26938 * @param {String} text The button text
26940 setText : function(text){
26943 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26949 * Gets the text for this button
26950 * @return {String} The button text
26952 getText : function(){
26960 this.hidden = false;
26962 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26970 this.hidden = true;
26972 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26977 * Convenience function for boolean show/hide
26978 * @param {Boolean} visible True to show, false to hide
26980 setVisible: function(visible){
26989 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26990 * @param {Boolean} state (optional) Force a particular state
26992 toggle : function(state){
26993 state = state === undefined ? !this.pressed : state;
26994 if(state != this.pressed){
26996 this.el.addClass("x-btn-pressed");
26997 this.pressed = true;
26998 this.fireEvent("toggle", this, true);
27000 this.el.removeClass("x-btn-pressed");
27001 this.pressed = false;
27002 this.fireEvent("toggle", this, false);
27004 if(this.toggleHandler){
27005 this.toggleHandler.call(this.scope || this, this, state);
27013 focus : function(){
27014 this.el.child('button:first').focus();
27018 * Disable this button
27020 disable : function(){
27022 this.el.addClass("x-btn-disabled");
27024 this.disabled = true;
27028 * Enable this button
27030 enable : function(){
27032 this.el.removeClass("x-btn-disabled");
27034 this.disabled = false;
27038 * Convenience function for boolean enable/disable
27039 * @param {Boolean} enabled True to enable, false to disable
27041 setDisabled : function(v){
27042 this[v !== true ? "enable" : "disable"]();
27046 onClick : function(e){
27048 e.preventDefault();
27053 if(!this.disabled){
27054 if(this.enableToggle){
27057 if(this.menu && !this.menu.isVisible()){
27058 this.menu.show(this.el, this.menuAlign);
27060 this.fireEvent("click", this, e);
27062 this.el.removeClass("x-btn-over");
27063 this.handler.call(this.scope || this, this, e);
27068 onMouseOver : function(e){
27069 if(!this.disabled){
27070 this.el.addClass("x-btn-over");
27071 this.fireEvent('mouseover', this, e);
27075 onMouseOut : function(e){
27076 if(!e.within(this.el, true)){
27077 this.el.removeClass("x-btn-over");
27078 this.fireEvent('mouseout', this, e);
27082 onFocus : function(e){
27083 if(!this.disabled){
27084 this.el.addClass("x-btn-focus");
27088 onBlur : function(e){
27089 this.el.removeClass("x-btn-focus");
27092 onMouseDown : function(e){
27093 if(!this.disabled && e.button == 0){
27094 this.el.addClass("x-btn-click");
27095 Roo.get(document).on('mouseup', this.onMouseUp, this);
27099 onMouseUp : function(e){
27101 this.el.removeClass("x-btn-click");
27102 Roo.get(document).un('mouseup', this.onMouseUp, this);
27106 onMenuShow : function(e){
27107 this.el.addClass("x-btn-menu-active");
27110 onMenuHide : function(e){
27111 this.el.removeClass("x-btn-menu-active");
27115 // Private utility class used by Button
27116 Roo.ButtonToggleMgr = function(){
27119 function toggleGroup(btn, state){
27121 var g = groups[btn.toggleGroup];
27122 for(var i = 0, l = g.length; i < l; i++){
27124 g[i].toggle(false);
27131 register : function(btn){
27132 if(!btn.toggleGroup){
27135 var g = groups[btn.toggleGroup];
27137 g = groups[btn.toggleGroup] = [];
27140 btn.on("toggle", toggleGroup);
27143 unregister : function(btn){
27144 if(!btn.toggleGroup){
27147 var g = groups[btn.toggleGroup];
27150 btn.un("toggle", toggleGroup);
27156 * Ext JS Library 1.1.1
27157 * Copyright(c) 2006-2007, Ext JS, LLC.
27159 * Originally Released Under LGPL - original licence link has changed is not relivant.
27162 * <script type="text/javascript">
27166 * @class Roo.SplitButton
27167 * @extends Roo.Button
27168 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27169 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27170 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27171 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27172 * @cfg {String} arrowTooltip The title attribute of the arrow
27174 * Create a new menu button
27175 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27176 * @param {Object} config The config object
27178 Roo.SplitButton = function(renderTo, config){
27179 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27181 * @event arrowclick
27182 * Fires when this button's arrow is clicked
27183 * @param {SplitButton} this
27184 * @param {EventObject} e The click event
27186 this.addEvents({"arrowclick":true});
27189 Roo.extend(Roo.SplitButton, Roo.Button, {
27190 render : function(renderTo){
27191 // this is one sweet looking template!
27192 var tpl = new Roo.Template(
27193 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27194 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27195 '<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>',
27196 "</tbody></table></td><td>",
27197 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27198 '<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>',
27199 "</tbody></table></td></tr></table>"
27201 var btn = tpl.append(renderTo, [this.text, this.type], true);
27202 var btnEl = btn.child("button");
27204 btn.addClass(this.cls);
27207 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27210 btnEl.addClass(this.iconCls);
27212 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27216 if(this.handleMouseEvents){
27217 btn.on("mouseover", this.onMouseOver, this);
27218 btn.on("mouseout", this.onMouseOut, this);
27219 btn.on("mousedown", this.onMouseDown, this);
27220 btn.on("mouseup", this.onMouseUp, this);
27222 btn.on(this.clickEvent, this.onClick, this);
27224 if(typeof this.tooltip == 'object'){
27225 Roo.QuickTips.tips(Roo.apply({
27229 btnEl.dom[this.tooltipType] = this.tooltip;
27232 if(this.arrowTooltip){
27233 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27242 this.el.addClass("x-btn-pressed");
27244 if(Roo.isIE && !Roo.isIE7){
27245 this.autoWidth.defer(1, this);
27250 this.menu.on("show", this.onMenuShow, this);
27251 this.menu.on("hide", this.onMenuHide, this);
27253 this.fireEvent('render', this);
27257 autoWidth : function(){
27259 var tbl = this.el.child("table:first");
27260 var tbl2 = this.el.child("table:last");
27261 this.el.setWidth("auto");
27262 tbl.setWidth("auto");
27263 if(Roo.isIE7 && Roo.isStrict){
27264 var ib = this.el.child('button:first');
27265 if(ib && ib.getWidth() > 20){
27267 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27272 this.el.beginMeasure();
27274 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27275 tbl.setWidth(this.minWidth-tbl2.getWidth());
27278 this.el.endMeasure();
27281 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27285 * Sets this button's click handler
27286 * @param {Function} handler The function to call when the button is clicked
27287 * @param {Object} scope (optional) Scope for the function passed above
27289 setHandler : function(handler, scope){
27290 this.handler = handler;
27291 this.scope = scope;
27295 * Sets this button's arrow click handler
27296 * @param {Function} handler The function to call when the arrow is clicked
27297 * @param {Object} scope (optional) Scope for the function passed above
27299 setArrowHandler : function(handler, scope){
27300 this.arrowHandler = handler;
27301 this.scope = scope;
27307 focus : function(){
27309 this.el.child("button:first").focus();
27314 onClick : function(e){
27315 e.preventDefault();
27316 if(!this.disabled){
27317 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27318 if(this.menu && !this.menu.isVisible()){
27319 this.menu.show(this.el, this.menuAlign);
27321 this.fireEvent("arrowclick", this, e);
27322 if(this.arrowHandler){
27323 this.arrowHandler.call(this.scope || this, this, e);
27326 this.fireEvent("click", this, e);
27328 this.handler.call(this.scope || this, this, e);
27334 onMouseDown : function(e){
27335 if(!this.disabled){
27336 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27340 onMouseUp : function(e){
27341 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27346 // backwards compat
27347 Roo.MenuButton = Roo.SplitButton;/*
27349 * Ext JS Library 1.1.1
27350 * Copyright(c) 2006-2007, Ext JS, LLC.
27352 * Originally Released Under LGPL - original licence link has changed is not relivant.
27355 * <script type="text/javascript">
27359 * @class Roo.Toolbar
27360 * Basic Toolbar class.
27362 * Creates a new Toolbar
27363 * @param {Object} container The config object
27365 Roo.Toolbar = function(container, buttons, config)
27367 /// old consturctor format still supported..
27368 if(container instanceof Array){ // omit the container for later rendering
27369 buttons = container;
27373 if (typeof(container) == 'object' && container.xtype) {
27374 config = container;
27375 container = config.container;
27376 buttons = config.buttons || []; // not really - use items!!
27379 if (config && config.items) {
27380 xitems = config.items;
27381 delete config.items;
27383 Roo.apply(this, config);
27384 this.buttons = buttons;
27387 this.render(container);
27389 this.xitems = xitems;
27390 Roo.each(xitems, function(b) {
27396 Roo.Toolbar.prototype = {
27398 * @cfg {Array} items
27399 * array of button configs or elements to add (will be converted to a MixedCollection)
27403 * @cfg {String/HTMLElement/Element} container
27404 * The id or element that will contain the toolbar
27407 render : function(ct){
27408 this.el = Roo.get(ct);
27410 this.el.addClass(this.cls);
27412 // using a table allows for vertical alignment
27413 // 100% width is needed by Safari...
27414 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27415 this.tr = this.el.child("tr", true);
27417 this.items = new Roo.util.MixedCollection(false, function(o){
27418 return o.id || ("item" + (++autoId));
27421 this.add.apply(this, this.buttons);
27422 delete this.buttons;
27427 * Adds element(s) to the toolbar -- this function takes a variable number of
27428 * arguments of mixed type and adds them to the toolbar.
27429 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27431 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27432 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27433 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27434 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27435 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27436 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27437 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27438 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27439 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27441 * @param {Mixed} arg2
27442 * @param {Mixed} etc.
27445 var a = arguments, l = a.length;
27446 for(var i = 0; i < l; i++){
27451 _add : function(el) {
27454 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27457 if (el.applyTo){ // some kind of form field
27458 return this.addField(el);
27460 if (el.render){ // some kind of Toolbar.Item
27461 return this.addItem(el);
27463 if (typeof el == "string"){ // string
27464 if(el == "separator" || el == "-"){
27465 return this.addSeparator();
27468 return this.addSpacer();
27471 return this.addFill();
27473 return this.addText(el);
27476 if(el.tagName){ // element
27477 return this.addElement(el);
27479 if(typeof el == "object"){ // must be button config?
27480 return this.addButton(el);
27482 // and now what?!?!
27488 * Add an Xtype element
27489 * @param {Object} xtype Xtype Object
27490 * @return {Object} created Object
27492 addxtype : function(e){
27493 return this.add(e);
27497 * Returns the Element for this toolbar.
27498 * @return {Roo.Element}
27500 getEl : function(){
27506 * @return {Roo.Toolbar.Item} The separator item
27508 addSeparator : function(){
27509 return this.addItem(new Roo.Toolbar.Separator());
27513 * Adds a spacer element
27514 * @return {Roo.Toolbar.Spacer} The spacer item
27516 addSpacer : function(){
27517 return this.addItem(new Roo.Toolbar.Spacer());
27521 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27522 * @return {Roo.Toolbar.Fill} The fill item
27524 addFill : function(){
27525 return this.addItem(new Roo.Toolbar.Fill());
27529 * Adds any standard HTML element to the toolbar
27530 * @param {String/HTMLElement/Element} el The element or id of the element to add
27531 * @return {Roo.Toolbar.Item} The element's item
27533 addElement : function(el){
27534 return this.addItem(new Roo.Toolbar.Item(el));
27537 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27538 * @type Roo.util.MixedCollection
27543 * Adds any Toolbar.Item or subclass
27544 * @param {Roo.Toolbar.Item} item
27545 * @return {Roo.Toolbar.Item} The item
27547 addItem : function(item){
27548 var td = this.nextBlock();
27550 this.items.add(item);
27555 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27556 * @param {Object/Array} config A button config or array of configs
27557 * @return {Roo.Toolbar.Button/Array}
27559 addButton : function(config){
27560 if(config instanceof Array){
27562 for(var i = 0, len = config.length; i < len; i++) {
27563 buttons.push(this.addButton(config[i]));
27568 if(!(config instanceof Roo.Toolbar.Button)){
27570 new Roo.Toolbar.SplitButton(config) :
27571 new Roo.Toolbar.Button(config);
27573 var td = this.nextBlock();
27580 * Adds text to the toolbar
27581 * @param {String} text The text to add
27582 * @return {Roo.Toolbar.Item} The element's item
27584 addText : function(text){
27585 return this.addItem(new Roo.Toolbar.TextItem(text));
27589 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27590 * @param {Number} index The index where the item is to be inserted
27591 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27592 * @return {Roo.Toolbar.Button/Item}
27594 insertButton : function(index, item){
27595 if(item instanceof Array){
27597 for(var i = 0, len = item.length; i < len; i++) {
27598 buttons.push(this.insertButton(index + i, item[i]));
27602 if (!(item instanceof Roo.Toolbar.Button)){
27603 item = new Roo.Toolbar.Button(item);
27605 var td = document.createElement("td");
27606 this.tr.insertBefore(td, this.tr.childNodes[index]);
27608 this.items.insert(index, item);
27613 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27614 * @param {Object} config
27615 * @return {Roo.Toolbar.Item} The element's item
27617 addDom : function(config, returnEl){
27618 var td = this.nextBlock();
27619 Roo.DomHelper.overwrite(td, config);
27620 var ti = new Roo.Toolbar.Item(td.firstChild);
27622 this.items.add(ti);
27627 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27628 * @type Roo.util.MixedCollection
27633 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27634 * Note: the field should not have been rendered yet. For a field that has already been
27635 * rendered, use {@link #addElement}.
27636 * @param {Roo.form.Field} field
27637 * @return {Roo.ToolbarItem}
27641 addField : function(field) {
27642 if (!this.fields) {
27644 this.fields = new Roo.util.MixedCollection(false, function(o){
27645 return o.id || ("item" + (++autoId));
27650 var td = this.nextBlock();
27652 var ti = new Roo.Toolbar.Item(td.firstChild);
27654 this.items.add(ti);
27655 this.fields.add(field);
27666 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27667 this.el.child('div').hide();
27675 this.el.child('div').show();
27679 nextBlock : function(){
27680 var td = document.createElement("td");
27681 this.tr.appendChild(td);
27686 destroy : function(){
27687 if(this.items){ // rendered?
27688 Roo.destroy.apply(Roo, this.items.items);
27690 if(this.fields){ // rendered?
27691 Roo.destroy.apply(Roo, this.fields.items);
27693 Roo.Element.uncache(this.el, this.tr);
27698 * @class Roo.Toolbar.Item
27699 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27701 * Creates a new Item
27702 * @param {HTMLElement} el
27704 Roo.Toolbar.Item = function(el){
27705 this.el = Roo.getDom(el);
27706 this.id = Roo.id(this.el);
27707 this.hidden = false;
27710 Roo.Toolbar.Item.prototype = {
27713 * Get this item's HTML Element
27714 * @return {HTMLElement}
27716 getEl : function(){
27721 render : function(td){
27723 td.appendChild(this.el);
27727 * Removes and destroys this item.
27729 destroy : function(){
27730 this.td.parentNode.removeChild(this.td);
27737 this.hidden = false;
27738 this.td.style.display = "";
27745 this.hidden = true;
27746 this.td.style.display = "none";
27750 * Convenience function for boolean show/hide.
27751 * @param {Boolean} visible true to show/false to hide
27753 setVisible: function(visible){
27762 * Try to focus this item.
27764 focus : function(){
27765 Roo.fly(this.el).focus();
27769 * Disables this item.
27771 disable : function(){
27772 Roo.fly(this.td).addClass("x-item-disabled");
27773 this.disabled = true;
27774 this.el.disabled = true;
27778 * Enables this item.
27780 enable : function(){
27781 Roo.fly(this.td).removeClass("x-item-disabled");
27782 this.disabled = false;
27783 this.el.disabled = false;
27789 * @class Roo.Toolbar.Separator
27790 * @extends Roo.Toolbar.Item
27791 * A simple toolbar separator class
27793 * Creates a new Separator
27795 Roo.Toolbar.Separator = function(){
27796 var s = document.createElement("span");
27797 s.className = "ytb-sep";
27798 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27800 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27801 enable:Roo.emptyFn,
27802 disable:Roo.emptyFn,
27807 * @class Roo.Toolbar.Spacer
27808 * @extends Roo.Toolbar.Item
27809 * A simple element that adds extra horizontal space to a toolbar.
27811 * Creates a new Spacer
27813 Roo.Toolbar.Spacer = function(){
27814 var s = document.createElement("div");
27815 s.className = "ytb-spacer";
27816 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27818 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27819 enable:Roo.emptyFn,
27820 disable:Roo.emptyFn,
27825 * @class Roo.Toolbar.Fill
27826 * @extends Roo.Toolbar.Spacer
27827 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27829 * Creates a new Spacer
27831 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27833 render : function(td){
27834 td.style.width = '100%';
27835 Roo.Toolbar.Fill.superclass.render.call(this, td);
27840 * @class Roo.Toolbar.TextItem
27841 * @extends Roo.Toolbar.Item
27842 * A simple class that renders text directly into a toolbar.
27844 * Creates a new TextItem
27845 * @param {String} text
27847 Roo.Toolbar.TextItem = function(text){
27848 if (typeof(text) == 'object') {
27851 var s = document.createElement("span");
27852 s.className = "ytb-text";
27853 s.innerHTML = text;
27854 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27856 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27857 enable:Roo.emptyFn,
27858 disable:Roo.emptyFn,
27863 * @class Roo.Toolbar.Button
27864 * @extends Roo.Button
27865 * A button that renders into a toolbar.
27867 * Creates a new Button
27868 * @param {Object} config A standard {@link Roo.Button} config object
27870 Roo.Toolbar.Button = function(config){
27871 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27873 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27874 render : function(td){
27876 Roo.Toolbar.Button.superclass.render.call(this, td);
27880 * Removes and destroys this button
27882 destroy : function(){
27883 Roo.Toolbar.Button.superclass.destroy.call(this);
27884 this.td.parentNode.removeChild(this.td);
27888 * Shows this button
27891 this.hidden = false;
27892 this.td.style.display = "";
27896 * Hides this button
27899 this.hidden = true;
27900 this.td.style.display = "none";
27904 * Disables this item
27906 disable : function(){
27907 Roo.fly(this.td).addClass("x-item-disabled");
27908 this.disabled = true;
27912 * Enables this item
27914 enable : function(){
27915 Roo.fly(this.td).removeClass("x-item-disabled");
27916 this.disabled = false;
27919 // backwards compat
27920 Roo.ToolbarButton = Roo.Toolbar.Button;
27923 * @class Roo.Toolbar.SplitButton
27924 * @extends Roo.SplitButton
27925 * A menu button that renders into a toolbar.
27927 * Creates a new SplitButton
27928 * @param {Object} config A standard {@link Roo.SplitButton} config object
27930 Roo.Toolbar.SplitButton = function(config){
27931 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27933 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27934 render : function(td){
27936 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27940 * Removes and destroys this button
27942 destroy : function(){
27943 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27944 this.td.parentNode.removeChild(this.td);
27948 * Shows this button
27951 this.hidden = false;
27952 this.td.style.display = "";
27956 * Hides this button
27959 this.hidden = true;
27960 this.td.style.display = "none";
27964 // backwards compat
27965 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27967 * Ext JS Library 1.1.1
27968 * Copyright(c) 2006-2007, Ext JS, LLC.
27970 * Originally Released Under LGPL - original licence link has changed is not relivant.
27973 * <script type="text/javascript">
27977 * @class Roo.PagingToolbar
27978 * @extends Roo.Toolbar
27979 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27981 * Create a new PagingToolbar
27982 * @param {Object} config The config object
27984 Roo.PagingToolbar = function(el, ds, config)
27986 // old args format still supported... - xtype is prefered..
27987 if (typeof(el) == 'object' && el.xtype) {
27988 // created from xtype...
27990 ds = el.dataSource;
27991 el = config.container;
27994 if (config.items) {
27995 items = config.items;
27999 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28002 this.renderButtons(this.el);
28005 // supprot items array.
28007 Roo.each(items, function(e) {
28008 this.add(Roo.factory(e));
28013 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28015 * @cfg {Roo.data.Store} dataSource
28016 * The underlying data store providing the paged data
28019 * @cfg {String/HTMLElement/Element} container
28020 * container The id or element that will contain the toolbar
28023 * @cfg {Boolean} displayInfo
28024 * True to display the displayMsg (defaults to false)
28027 * @cfg {Number} pageSize
28028 * The number of records to display per page (defaults to 20)
28032 * @cfg {String} displayMsg
28033 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28035 displayMsg : 'Displaying {0} - {1} of {2}',
28037 * @cfg {String} emptyMsg
28038 * The message to display when no records are found (defaults to "No data to display")
28040 emptyMsg : 'No data to display',
28042 * Customizable piece of the default paging text (defaults to "Page")
28045 beforePageText : "Page",
28047 * Customizable piece of the default paging text (defaults to "of %0")
28050 afterPageText : "of {0}",
28052 * Customizable piece of the default paging text (defaults to "First Page")
28055 firstText : "First Page",
28057 * Customizable piece of the default paging text (defaults to "Previous Page")
28060 prevText : "Previous Page",
28062 * Customizable piece of the default paging text (defaults to "Next Page")
28065 nextText : "Next Page",
28067 * Customizable piece of the default paging text (defaults to "Last Page")
28070 lastText : "Last Page",
28072 * Customizable piece of the default paging text (defaults to "Refresh")
28075 refreshText : "Refresh",
28078 renderButtons : function(el){
28079 Roo.PagingToolbar.superclass.render.call(this, el);
28080 this.first = this.addButton({
28081 tooltip: this.firstText,
28082 cls: "x-btn-icon x-grid-page-first",
28084 handler: this.onClick.createDelegate(this, ["first"])
28086 this.prev = this.addButton({
28087 tooltip: this.prevText,
28088 cls: "x-btn-icon x-grid-page-prev",
28090 handler: this.onClick.createDelegate(this, ["prev"])
28092 //this.addSeparator();
28093 this.add(this.beforePageText);
28094 this.field = Roo.get(this.addDom({
28099 cls: "x-grid-page-number"
28101 this.field.on("keydown", this.onPagingKeydown, this);
28102 this.field.on("focus", function(){this.dom.select();});
28103 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28104 this.field.setHeight(18);
28105 //this.addSeparator();
28106 this.next = this.addButton({
28107 tooltip: this.nextText,
28108 cls: "x-btn-icon x-grid-page-next",
28110 handler: this.onClick.createDelegate(this, ["next"])
28112 this.last = this.addButton({
28113 tooltip: this.lastText,
28114 cls: "x-btn-icon x-grid-page-last",
28116 handler: this.onClick.createDelegate(this, ["last"])
28118 //this.addSeparator();
28119 this.loading = this.addButton({
28120 tooltip: this.refreshText,
28121 cls: "x-btn-icon x-grid-loading",
28122 handler: this.onClick.createDelegate(this, ["refresh"])
28125 if(this.displayInfo){
28126 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28131 updateInfo : function(){
28132 if(this.displayEl){
28133 var count = this.ds.getCount();
28134 var msg = count == 0 ?
28138 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28140 this.displayEl.update(msg);
28145 onLoad : function(ds, r, o){
28146 this.cursor = o.params ? o.params.start : 0;
28147 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28149 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28150 this.field.dom.value = ap;
28151 this.first.setDisabled(ap == 1);
28152 this.prev.setDisabled(ap == 1);
28153 this.next.setDisabled(ap == ps);
28154 this.last.setDisabled(ap == ps);
28155 this.loading.enable();
28160 getPageData : function(){
28161 var total = this.ds.getTotalCount();
28164 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28165 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28170 onLoadError : function(){
28171 this.loading.enable();
28175 onPagingKeydown : function(e){
28176 var k = e.getKey();
28177 var d = this.getPageData();
28179 var v = this.field.dom.value, pageNum;
28180 if(!v || isNaN(pageNum = parseInt(v, 10))){
28181 this.field.dom.value = d.activePage;
28184 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28185 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28188 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))
28190 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28191 this.field.dom.value = pageNum;
28192 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28195 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28197 var v = this.field.dom.value, pageNum;
28198 var increment = (e.shiftKey) ? 10 : 1;
28199 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28201 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28202 this.field.dom.value = d.activePage;
28205 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28207 this.field.dom.value = parseInt(v, 10) + increment;
28208 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28209 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28216 beforeLoad : function(){
28218 this.loading.disable();
28223 onClick : function(which){
28227 ds.load({params:{start: 0, limit: this.pageSize}});
28230 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28233 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28236 var total = ds.getTotalCount();
28237 var extra = total % this.pageSize;
28238 var lastStart = extra ? (total - extra) : total-this.pageSize;
28239 ds.load({params:{start: lastStart, limit: this.pageSize}});
28242 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28248 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28249 * @param {Roo.data.Store} store The data store to unbind
28251 unbind : function(ds){
28252 ds.un("beforeload", this.beforeLoad, this);
28253 ds.un("load", this.onLoad, this);
28254 ds.un("loadexception", this.onLoadError, this);
28255 ds.un("remove", this.updateInfo, this);
28256 ds.un("add", this.updateInfo, this);
28257 this.ds = undefined;
28261 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28262 * @param {Roo.data.Store} store The data store to bind
28264 bind : function(ds){
28265 ds.on("beforeload", this.beforeLoad, this);
28266 ds.on("load", this.onLoad, this);
28267 ds.on("loadexception", this.onLoadError, this);
28268 ds.on("remove", this.updateInfo, this);
28269 ds.on("add", this.updateInfo, this);
28274 * Ext JS Library 1.1.1
28275 * Copyright(c) 2006-2007, Ext JS, LLC.
28277 * Originally Released Under LGPL - original licence link has changed is not relivant.
28280 * <script type="text/javascript">
28284 * @class Roo.Resizable
28285 * @extends Roo.util.Observable
28286 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28287 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28288 * 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
28289 * the element will be wrapped for you automatically.</p>
28290 * <p>Here is the list of valid resize handles:</p>
28293 ------ -------------------
28302 'hd' horizontal drag
28305 * <p>Here's an example showing the creation of a typical Resizable:</p>
28307 var resizer = new Roo.Resizable("element-id", {
28315 resizer.on("resize", myHandler);
28317 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28318 * resizer.east.setDisplayed(false);</p>
28319 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28320 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28321 * resize operation's new size (defaults to [0, 0])
28322 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28323 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28324 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28325 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28326 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28327 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28328 * @cfg {Number} width The width of the element in pixels (defaults to null)
28329 * @cfg {Number} height The height of the element in pixels (defaults to null)
28330 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28331 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28332 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28333 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28334 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28335 * in favor of the handles config option (defaults to false)
28336 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28337 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28338 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28339 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28340 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28341 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28342 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28343 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28344 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28345 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28346 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28348 * Create a new resizable component
28349 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28350 * @param {Object} config configuration options
28352 Roo.Resizable = function(el, config)
28354 this.el = Roo.get(el);
28356 if(config && config.wrap){
28357 config.resizeChild = this.el;
28358 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28359 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28360 this.el.setStyle("overflow", "hidden");
28361 this.el.setPositioning(config.resizeChild.getPositioning());
28362 config.resizeChild.clearPositioning();
28363 if(!config.width || !config.height){
28364 var csize = config.resizeChild.getSize();
28365 this.el.setSize(csize.width, csize.height);
28367 if(config.pinned && !config.adjustments){
28368 config.adjustments = "auto";
28372 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28373 this.proxy.unselectable();
28374 this.proxy.enableDisplayMode('block');
28376 Roo.apply(this, config);
28379 this.disableTrackOver = true;
28380 this.el.addClass("x-resizable-pinned");
28382 // if the element isn't positioned, make it relative
28383 var position = this.el.getStyle("position");
28384 if(position != "absolute" && position != "fixed"){
28385 this.el.setStyle("position", "relative");
28387 if(!this.handles){ // no handles passed, must be legacy style
28388 this.handles = 's,e,se';
28389 if(this.multiDirectional){
28390 this.handles += ',n,w';
28393 if(this.handles == "all"){
28394 this.handles = "n s e w ne nw se sw";
28396 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28397 var ps = Roo.Resizable.positions;
28398 for(var i = 0, len = hs.length; i < len; i++){
28399 if(hs[i] && ps[hs[i]]){
28400 var pos = ps[hs[i]];
28401 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28405 this.corner = this.southeast;
28407 // updateBox = the box can move..
28408 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28409 this.updateBox = true;
28412 this.activeHandle = null;
28414 if(this.resizeChild){
28415 if(typeof this.resizeChild == "boolean"){
28416 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28418 this.resizeChild = Roo.get(this.resizeChild, true);
28422 if(this.adjustments == "auto"){
28423 var rc = this.resizeChild;
28424 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28425 if(rc && (hw || hn)){
28426 rc.position("relative");
28427 rc.setLeft(hw ? hw.el.getWidth() : 0);
28428 rc.setTop(hn ? hn.el.getHeight() : 0);
28430 this.adjustments = [
28431 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28432 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28436 if(this.draggable){
28437 this.dd = this.dynamic ?
28438 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28439 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28445 * @event beforeresize
28446 * Fired before resize is allowed. Set enabled to false to cancel resize.
28447 * @param {Roo.Resizable} this
28448 * @param {Roo.EventObject} e The mousedown event
28450 "beforeresize" : true,
28453 * Fired after a resize.
28454 * @param {Roo.Resizable} this
28455 * @param {Number} width The new width
28456 * @param {Number} height The new height
28457 * @param {Roo.EventObject} e The mouseup event
28462 if(this.width !== null && this.height !== null){
28463 this.resizeTo(this.width, this.height);
28465 this.updateChildSize();
28468 this.el.dom.style.zoom = 1;
28470 Roo.Resizable.superclass.constructor.call(this);
28473 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28474 resizeChild : false,
28475 adjustments : [0, 0],
28485 multiDirectional : false,
28486 disableTrackOver : false,
28487 easing : 'easeOutStrong',
28488 widthIncrement : 0,
28489 heightIncrement : 0,
28493 preserveRatio : false,
28494 transparent: false,
28500 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28502 constrainTo: undefined,
28504 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28506 resizeRegion: undefined,
28510 * Perform a manual resize
28511 * @param {Number} width
28512 * @param {Number} height
28514 resizeTo : function(width, height){
28515 this.el.setSize(width, height);
28516 this.updateChildSize();
28517 this.fireEvent("resize", this, width, height, null);
28521 startSizing : function(e, handle){
28522 this.fireEvent("beforeresize", this, e);
28523 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28526 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28527 this.overlay.unselectable();
28528 this.overlay.enableDisplayMode("block");
28529 this.overlay.on("mousemove", this.onMouseMove, this);
28530 this.overlay.on("mouseup", this.onMouseUp, this);
28532 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28534 this.resizing = true;
28535 this.startBox = this.el.getBox();
28536 this.startPoint = e.getXY();
28537 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28538 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28540 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28541 this.overlay.show();
28543 if(this.constrainTo) {
28544 var ct = Roo.get(this.constrainTo);
28545 this.resizeRegion = ct.getRegion().adjust(
28546 ct.getFrameWidth('t'),
28547 ct.getFrameWidth('l'),
28548 -ct.getFrameWidth('b'),
28549 -ct.getFrameWidth('r')
28553 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28555 this.proxy.setBox(this.startBox);
28557 this.proxy.setStyle('visibility', 'visible');
28563 onMouseDown : function(handle, e){
28566 this.activeHandle = handle;
28567 this.startSizing(e, handle);
28572 onMouseUp : function(e){
28573 var size = this.resizeElement();
28574 this.resizing = false;
28576 this.overlay.hide();
28578 this.fireEvent("resize", this, size.width, size.height, e);
28582 updateChildSize : function(){
28583 if(this.resizeChild){
28585 var child = this.resizeChild;
28586 var adj = this.adjustments;
28587 if(el.dom.offsetWidth){
28588 var b = el.getSize(true);
28589 child.setSize(b.width+adj[0], b.height+adj[1]);
28591 // Second call here for IE
28592 // The first call enables instant resizing and
28593 // the second call corrects scroll bars if they
28596 setTimeout(function(){
28597 if(el.dom.offsetWidth){
28598 var b = el.getSize(true);
28599 child.setSize(b.width+adj[0], b.height+adj[1]);
28607 snap : function(value, inc, min){
28608 if(!inc || !value) return value;
28609 var newValue = value;
28610 var m = value % inc;
28613 newValue = value + (inc-m);
28615 newValue = value - m;
28618 return Math.max(min, newValue);
28622 resizeElement : function(){
28623 var box = this.proxy.getBox();
28624 if(this.updateBox){
28625 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28627 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28629 this.updateChildSize();
28637 constrain : function(v, diff, m, mx){
28640 }else if(v - diff > mx){
28647 onMouseMove : function(e){
28649 try{// try catch so if something goes wrong the user doesn't get hung
28651 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28655 //var curXY = this.startPoint;
28656 var curSize = this.curSize || this.startBox;
28657 var x = this.startBox.x, y = this.startBox.y;
28658 var ox = x, oy = y;
28659 var w = curSize.width, h = curSize.height;
28660 var ow = w, oh = h;
28661 var mw = this.minWidth, mh = this.minHeight;
28662 var mxw = this.maxWidth, mxh = this.maxHeight;
28663 var wi = this.widthIncrement;
28664 var hi = this.heightIncrement;
28666 var eventXY = e.getXY();
28667 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28668 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28670 var pos = this.activeHandle.position;
28675 w = Math.min(Math.max(mw, w), mxw);
28680 h = Math.min(Math.max(mh, h), mxh);
28685 w = Math.min(Math.max(mw, w), mxw);
28686 h = Math.min(Math.max(mh, h), mxh);
28689 diffY = this.constrain(h, diffY, mh, mxh);
28696 var adiffX = Math.abs(diffX);
28697 var sub = (adiffX % wi); // how much
28698 if (sub > (wi/2)) { // far enough to snap
28699 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28701 // remove difference..
28702 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28706 x = Math.max(this.minX, x);
28709 diffX = this.constrain(w, diffX, mw, mxw);
28715 w = Math.min(Math.max(mw, w), mxw);
28716 diffY = this.constrain(h, diffY, mh, mxh);
28721 diffX = this.constrain(w, diffX, mw, mxw);
28722 diffY = this.constrain(h, diffY, mh, mxh);
28729 diffX = this.constrain(w, diffX, mw, mxw);
28731 h = Math.min(Math.max(mh, h), mxh);
28737 var sw = this.snap(w, wi, mw);
28738 var sh = this.snap(h, hi, mh);
28739 if(sw != w || sh != h){
28762 if(this.preserveRatio){
28767 h = Math.min(Math.max(mh, h), mxh);
28772 w = Math.min(Math.max(mw, w), mxw);
28777 w = Math.min(Math.max(mw, w), mxw);
28783 w = Math.min(Math.max(mw, w), mxw);
28789 h = Math.min(Math.max(mh, h), mxh);
28797 h = Math.min(Math.max(mh, h), mxh);
28807 h = Math.min(Math.max(mh, h), mxh);
28815 if (pos == 'hdrag') {
28818 this.proxy.setBounds(x, y, w, h);
28820 this.resizeElement();
28827 handleOver : function(){
28829 this.el.addClass("x-resizable-over");
28834 handleOut : function(){
28835 if(!this.resizing){
28836 this.el.removeClass("x-resizable-over");
28841 * Returns the element this component is bound to.
28842 * @return {Roo.Element}
28844 getEl : function(){
28849 * Returns the resizeChild element (or null).
28850 * @return {Roo.Element}
28852 getResizeChild : function(){
28853 return this.resizeChild;
28857 * Destroys this resizable. If the element was wrapped and
28858 * removeEl is not true then the element remains.
28859 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28861 destroy : function(removeEl){
28862 this.proxy.remove();
28864 this.overlay.removeAllListeners();
28865 this.overlay.remove();
28867 var ps = Roo.Resizable.positions;
28869 if(typeof ps[k] != "function" && this[ps[k]]){
28870 var h = this[ps[k]];
28871 h.el.removeAllListeners();
28876 this.el.update("");
28883 // hash to map config positions to true positions
28884 Roo.Resizable.positions = {
28885 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28890 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28892 // only initialize the template if resizable is used
28893 var tpl = Roo.DomHelper.createTemplate(
28894 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28897 Roo.Resizable.Handle.prototype.tpl = tpl;
28899 this.position = pos;
28901 // show north drag fro topdra
28902 var handlepos = pos == 'hdrag' ? 'north' : pos;
28904 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28905 if (pos == 'hdrag') {
28906 this.el.setStyle('cursor', 'pointer');
28908 this.el.unselectable();
28910 this.el.setOpacity(0);
28912 this.el.on("mousedown", this.onMouseDown, this);
28913 if(!disableTrackOver){
28914 this.el.on("mouseover", this.onMouseOver, this);
28915 this.el.on("mouseout", this.onMouseOut, this);
28920 Roo.Resizable.Handle.prototype = {
28921 afterResize : function(rz){
28925 onMouseDown : function(e){
28926 this.rz.onMouseDown(this, e);
28929 onMouseOver : function(e){
28930 this.rz.handleOver(this, e);
28933 onMouseOut : function(e){
28934 this.rz.handleOut(this, e);
28938 * Ext JS Library 1.1.1
28939 * Copyright(c) 2006-2007, Ext JS, LLC.
28941 * Originally Released Under LGPL - original licence link has changed is not relivant.
28944 * <script type="text/javascript">
28948 * @class Roo.Editor
28949 * @extends Roo.Component
28950 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28952 * Create a new Editor
28953 * @param {Roo.form.Field} field The Field object (or descendant)
28954 * @param {Object} config The config object
28956 Roo.Editor = function(field, config){
28957 Roo.Editor.superclass.constructor.call(this, config);
28958 this.field = field;
28961 * @event beforestartedit
28962 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28963 * false from the handler of this event.
28964 * @param {Editor} this
28965 * @param {Roo.Element} boundEl The underlying element bound to this editor
28966 * @param {Mixed} value The field value being set
28968 "beforestartedit" : true,
28971 * Fires when this editor is displayed
28972 * @param {Roo.Element} boundEl The underlying element bound to this editor
28973 * @param {Mixed} value The starting field value
28975 "startedit" : true,
28977 * @event beforecomplete
28978 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28979 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28980 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28981 * event will not fire since no edit actually occurred.
28982 * @param {Editor} this
28983 * @param {Mixed} value The current field value
28984 * @param {Mixed} startValue The original field value
28986 "beforecomplete" : true,
28989 * Fires after editing is complete and any changed value has been written to the underlying field.
28990 * @param {Editor} this
28991 * @param {Mixed} value The current field value
28992 * @param {Mixed} startValue The original field value
28996 * @event specialkey
28997 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28998 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28999 * @param {Roo.form.Field} this
29000 * @param {Roo.EventObject} e The event object
29002 "specialkey" : true
29006 Roo.extend(Roo.Editor, Roo.Component, {
29008 * @cfg {Boolean/String} autosize
29009 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29010 * or "height" to adopt the height only (defaults to false)
29013 * @cfg {Boolean} revertInvalid
29014 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29015 * validation fails (defaults to true)
29018 * @cfg {Boolean} ignoreNoChange
29019 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29020 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29021 * will never be ignored.
29024 * @cfg {Boolean} hideEl
29025 * False to keep the bound element visible while the editor is displayed (defaults to true)
29028 * @cfg {Mixed} value
29029 * The data value of the underlying field (defaults to "")
29033 * @cfg {String} alignment
29034 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29038 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29039 * for bottom-right shadow (defaults to "frame")
29043 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29047 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29049 completeOnEnter : false,
29051 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29053 cancelOnEsc : false,
29055 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29060 onRender : function(ct, position){
29061 this.el = new Roo.Layer({
29062 shadow: this.shadow,
29068 constrain: this.constrain
29070 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29071 if(this.field.msgTarget != 'title'){
29072 this.field.msgTarget = 'qtip';
29074 this.field.render(this.el);
29076 this.field.el.dom.setAttribute('autocomplete', 'off');
29078 this.field.on("specialkey", this.onSpecialKey, this);
29079 if(this.swallowKeys){
29080 this.field.el.swallowEvent(['keydown','keypress']);
29083 this.field.on("blur", this.onBlur, this);
29084 if(this.field.grow){
29085 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29089 onSpecialKey : function(field, e)
29091 //Roo.log('editor onSpecialKey');
29092 if(this.completeOnEnter && e.getKey() == e.ENTER){
29094 this.completeEdit();
29097 // do not fire special key otherwise it might hide close the editor...
29098 if(e.getKey() == e.ENTER){
29101 if(this.cancelOnEsc && e.getKey() == e.ESC){
29105 this.fireEvent('specialkey', field, e);
29110 * Starts the editing process and shows the editor.
29111 * @param {String/HTMLElement/Element} el The element to edit
29112 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29113 * to the innerHTML of el.
29115 startEdit : function(el, value){
29117 this.completeEdit();
29119 this.boundEl = Roo.get(el);
29120 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29121 if(!this.rendered){
29122 this.render(this.parentEl || document.body);
29124 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29127 this.startValue = v;
29128 this.field.setValue(v);
29130 var sz = this.boundEl.getSize();
29131 switch(this.autoSize){
29133 this.setSize(sz.width, "");
29136 this.setSize("", sz.height);
29139 this.setSize(sz.width, sz.height);
29142 this.el.alignTo(this.boundEl, this.alignment);
29143 this.editing = true;
29145 Roo.QuickTips.disable();
29151 * Sets the height and width of this editor.
29152 * @param {Number} width The new width
29153 * @param {Number} height The new height
29155 setSize : function(w, h){
29156 this.field.setSize(w, h);
29163 * Realigns the editor to the bound field based on the current alignment config value.
29165 realign : function(){
29166 this.el.alignTo(this.boundEl, this.alignment);
29170 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29171 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29173 completeEdit : function(remainVisible){
29177 var v = this.getValue();
29178 if(this.revertInvalid !== false && !this.field.isValid()){
29179 v = this.startValue;
29180 this.cancelEdit(true);
29182 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29183 this.editing = false;
29187 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29188 this.editing = false;
29189 if(this.updateEl && this.boundEl){
29190 this.boundEl.update(v);
29192 if(remainVisible !== true){
29195 this.fireEvent("complete", this, v, this.startValue);
29200 onShow : function(){
29202 if(this.hideEl !== false){
29203 this.boundEl.hide();
29206 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29207 this.fixIEFocus = true;
29208 this.deferredFocus.defer(50, this);
29210 this.field.focus();
29212 this.fireEvent("startedit", this.boundEl, this.startValue);
29215 deferredFocus : function(){
29217 this.field.focus();
29222 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29223 * reverted to the original starting value.
29224 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29225 * cancel (defaults to false)
29227 cancelEdit : function(remainVisible){
29229 this.setValue(this.startValue);
29230 if(remainVisible !== true){
29237 onBlur : function(){
29238 if(this.allowBlur !== true && this.editing){
29239 this.completeEdit();
29244 onHide : function(){
29246 this.completeEdit();
29250 if(this.field.collapse){
29251 this.field.collapse();
29254 if(this.hideEl !== false){
29255 this.boundEl.show();
29258 Roo.QuickTips.enable();
29263 * Sets the data value of the editor
29264 * @param {Mixed} value Any valid value supported by the underlying field
29266 setValue : function(v){
29267 this.field.setValue(v);
29271 * Gets the data value of the editor
29272 * @return {Mixed} The data value
29274 getValue : function(){
29275 return this.field.getValue();
29279 * Ext JS Library 1.1.1
29280 * Copyright(c) 2006-2007, Ext JS, LLC.
29282 * Originally Released Under LGPL - original licence link has changed is not relivant.
29285 * <script type="text/javascript">
29289 * @class Roo.BasicDialog
29290 * @extends Roo.util.Observable
29291 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29293 var dlg = new Roo.BasicDialog("my-dlg", {
29302 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29303 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29304 dlg.addButton('Cancel', dlg.hide, dlg);
29307 <b>A Dialog should always be a direct child of the body element.</b>
29308 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29309 * @cfg {String} title Default text to display in the title bar (defaults to null)
29310 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29311 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29312 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29313 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29314 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29315 * (defaults to null with no animation)
29316 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29317 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29318 * property for valid values (defaults to 'all')
29319 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29320 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29321 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29322 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29323 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29324 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29325 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29326 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29327 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29328 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29329 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29330 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29331 * draggable = true (defaults to false)
29332 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29333 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29334 * shadow (defaults to false)
29335 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29336 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29337 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29338 * @cfg {Array} buttons Array of buttons
29339 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29341 * Create a new BasicDialog.
29342 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29343 * @param {Object} config Configuration options
29345 Roo.BasicDialog = function(el, config){
29346 this.el = Roo.get(el);
29347 var dh = Roo.DomHelper;
29348 if(!this.el && config && config.autoCreate){
29349 if(typeof config.autoCreate == "object"){
29350 if(!config.autoCreate.id){
29351 config.autoCreate.id = el;
29353 this.el = dh.append(document.body,
29354 config.autoCreate, true);
29356 this.el = dh.append(document.body,
29357 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29361 el.setDisplayed(true);
29362 el.hide = this.hideAction;
29364 el.addClass("x-dlg");
29366 Roo.apply(this, config);
29368 this.proxy = el.createProxy("x-dlg-proxy");
29369 this.proxy.hide = this.hideAction;
29370 this.proxy.setOpacity(.5);
29374 el.setWidth(config.width);
29377 el.setHeight(config.height);
29379 this.size = el.getSize();
29380 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29381 this.xy = [config.x,config.y];
29383 this.xy = el.getCenterXY(true);
29385 /** The header element @type Roo.Element */
29386 this.header = el.child("> .x-dlg-hd");
29387 /** The body element @type Roo.Element */
29388 this.body = el.child("> .x-dlg-bd");
29389 /** The footer element @type Roo.Element */
29390 this.footer = el.child("> .x-dlg-ft");
29393 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29396 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29399 this.header.unselectable();
29401 this.header.update(this.title);
29403 // this element allows the dialog to be focused for keyboard event
29404 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29405 this.focusEl.swallowEvent("click", true);
29407 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29409 // wrap the body and footer for special rendering
29410 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29412 this.bwrap.dom.appendChild(this.footer.dom);
29415 this.bg = this.el.createChild({
29416 tag: "div", cls:"x-dlg-bg",
29417 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29419 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29422 if(this.autoScroll !== false && !this.autoTabs){
29423 this.body.setStyle("overflow", "auto");
29426 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29428 if(this.closable !== false){
29429 this.el.addClass("x-dlg-closable");
29430 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29431 this.close.on("click", this.closeClick, this);
29432 this.close.addClassOnOver("x-dlg-close-over");
29434 if(this.collapsible !== false){
29435 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29436 this.collapseBtn.on("click", this.collapseClick, this);
29437 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29438 this.header.on("dblclick", this.collapseClick, this);
29440 if(this.resizable !== false){
29441 this.el.addClass("x-dlg-resizable");
29442 this.resizer = new Roo.Resizable(el, {
29443 minWidth: this.minWidth || 80,
29444 minHeight:this.minHeight || 80,
29445 handles: this.resizeHandles || "all",
29448 this.resizer.on("beforeresize", this.beforeResize, this);
29449 this.resizer.on("resize", this.onResize, this);
29451 if(this.draggable !== false){
29452 el.addClass("x-dlg-draggable");
29453 if (!this.proxyDrag) {
29454 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29457 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29459 dd.setHandleElId(this.header.id);
29460 dd.endDrag = this.endMove.createDelegate(this);
29461 dd.startDrag = this.startMove.createDelegate(this);
29462 dd.onDrag = this.onDrag.createDelegate(this);
29467 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29468 this.mask.enableDisplayMode("block");
29470 this.el.addClass("x-dlg-modal");
29473 this.shadow = new Roo.Shadow({
29474 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29475 offset : this.shadowOffset
29478 this.shadowOffset = 0;
29480 if(Roo.useShims && this.shim !== false){
29481 this.shim = this.el.createShim();
29482 this.shim.hide = this.hideAction;
29490 if (this.buttons) {
29491 var bts= this.buttons;
29493 Roo.each(bts, function(b) {
29502 * Fires when a key is pressed
29503 * @param {Roo.BasicDialog} this
29504 * @param {Roo.EventObject} e
29509 * Fires when this dialog is moved by the user.
29510 * @param {Roo.BasicDialog} this
29511 * @param {Number} x The new page X
29512 * @param {Number} y The new page Y
29517 * Fires when this dialog is resized by the user.
29518 * @param {Roo.BasicDialog} this
29519 * @param {Number} width The new width
29520 * @param {Number} height The new height
29524 * @event beforehide
29525 * Fires before this dialog is hidden.
29526 * @param {Roo.BasicDialog} this
29528 "beforehide" : true,
29531 * Fires when this dialog is hidden.
29532 * @param {Roo.BasicDialog} this
29536 * @event beforeshow
29537 * Fires before this dialog is shown.
29538 * @param {Roo.BasicDialog} this
29540 "beforeshow" : true,
29543 * Fires when this dialog is shown.
29544 * @param {Roo.BasicDialog} this
29548 el.on("keydown", this.onKeyDown, this);
29549 el.on("mousedown", this.toFront, this);
29550 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29552 Roo.DialogManager.register(this);
29553 Roo.BasicDialog.superclass.constructor.call(this);
29556 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29557 shadowOffset: Roo.isIE ? 6 : 5,
29560 minButtonWidth: 75,
29561 defaultButton: null,
29562 buttonAlign: "right",
29567 * Sets the dialog title text
29568 * @param {String} text The title text to display
29569 * @return {Roo.BasicDialog} this
29571 setTitle : function(text){
29572 this.header.update(text);
29577 closeClick : function(){
29582 collapseClick : function(){
29583 this[this.collapsed ? "expand" : "collapse"]();
29587 * Collapses the dialog to its minimized state (only the title bar is visible).
29588 * Equivalent to the user clicking the collapse dialog button.
29590 collapse : function(){
29591 if(!this.collapsed){
29592 this.collapsed = true;
29593 this.el.addClass("x-dlg-collapsed");
29594 this.restoreHeight = this.el.getHeight();
29595 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29600 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29601 * clicking the expand dialog button.
29603 expand : function(){
29604 if(this.collapsed){
29605 this.collapsed = false;
29606 this.el.removeClass("x-dlg-collapsed");
29607 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29612 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29613 * @return {Roo.TabPanel} The tabs component
29615 initTabs : function(){
29616 var tabs = this.getTabs();
29617 while(tabs.getTab(0)){
29620 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29622 tabs.addTab(Roo.id(dom), dom.title);
29630 beforeResize : function(){
29631 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29635 onResize : function(){
29636 this.refreshSize();
29637 this.syncBodyHeight();
29638 this.adjustAssets();
29640 this.fireEvent("resize", this, this.size.width, this.size.height);
29644 onKeyDown : function(e){
29645 if(this.isVisible()){
29646 this.fireEvent("keydown", this, e);
29651 * Resizes the dialog.
29652 * @param {Number} width
29653 * @param {Number} height
29654 * @return {Roo.BasicDialog} this
29656 resizeTo : function(width, height){
29657 this.el.setSize(width, height);
29658 this.size = {width: width, height: height};
29659 this.syncBodyHeight();
29660 if(this.fixedcenter){
29663 if(this.isVisible()){
29664 this.constrainXY();
29665 this.adjustAssets();
29667 this.fireEvent("resize", this, width, height);
29673 * Resizes the dialog to fit the specified content size.
29674 * @param {Number} width
29675 * @param {Number} height
29676 * @return {Roo.BasicDialog} this
29678 setContentSize : function(w, h){
29679 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29680 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29681 //if(!this.el.isBorderBox()){
29682 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29683 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29686 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29687 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29689 this.resizeTo(w, h);
29694 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29695 * executed in response to a particular key being pressed while the dialog is active.
29696 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29697 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29698 * @param {Function} fn The function to call
29699 * @param {Object} scope (optional) The scope of the function
29700 * @return {Roo.BasicDialog} this
29702 addKeyListener : function(key, fn, scope){
29703 var keyCode, shift, ctrl, alt;
29704 if(typeof key == "object" && !(key instanceof Array)){
29705 keyCode = key["key"];
29706 shift = key["shift"];
29707 ctrl = key["ctrl"];
29712 var handler = function(dlg, e){
29713 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29714 var k = e.getKey();
29715 if(keyCode instanceof Array){
29716 for(var i = 0, len = keyCode.length; i < len; i++){
29717 if(keyCode[i] == k){
29718 fn.call(scope || window, dlg, k, e);
29724 fn.call(scope || window, dlg, k, e);
29729 this.on("keydown", handler);
29734 * Returns the TabPanel component (creates it if it doesn't exist).
29735 * Note: If you wish to simply check for the existence of tabs without creating them,
29736 * check for a null 'tabs' property.
29737 * @return {Roo.TabPanel} The tabs component
29739 getTabs : function(){
29741 this.el.addClass("x-dlg-auto-tabs");
29742 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29743 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29749 * Adds a button to the footer section of the dialog.
29750 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29751 * object or a valid Roo.DomHelper element config
29752 * @param {Function} handler The function called when the button is clicked
29753 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29754 * @return {Roo.Button} The new button
29756 addButton : function(config, handler, scope){
29757 var dh = Roo.DomHelper;
29759 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29761 if(!this.btnContainer){
29762 var tb = this.footer.createChild({
29764 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29765 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29767 this.btnContainer = tb.firstChild.firstChild.firstChild;
29772 minWidth: this.minButtonWidth,
29775 if(typeof config == "string"){
29776 bconfig.text = config;
29779 bconfig.dhconfig = config;
29781 Roo.apply(bconfig, config);
29785 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29786 bconfig.position = Math.max(0, bconfig.position);
29787 fc = this.btnContainer.childNodes[bconfig.position];
29790 var btn = new Roo.Button(
29792 this.btnContainer.insertBefore(document.createElement("td"),fc)
29793 : this.btnContainer.appendChild(document.createElement("td")),
29794 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29797 this.syncBodyHeight();
29800 * Array of all the buttons that have been added to this dialog via addButton
29805 this.buttons.push(btn);
29810 * Sets the default button to be focused when the dialog is displayed.
29811 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29812 * @return {Roo.BasicDialog} this
29814 setDefaultButton : function(btn){
29815 this.defaultButton = btn;
29820 getHeaderFooterHeight : function(safe){
29823 height += this.header.getHeight();
29826 var fm = this.footer.getMargins();
29827 height += (this.footer.getHeight()+fm.top+fm.bottom);
29829 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29830 height += this.centerBg.getPadding("tb");
29835 syncBodyHeight : function()
29837 var bd = this.body, // the text
29838 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
29840 var height = this.size.height - this.getHeaderFooterHeight(false);
29841 bd.setHeight(height-bd.getMargins("tb"));
29842 var hh = this.header.getHeight();
29843 var h = this.size.height-hh;
29846 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29847 bw.setHeight(h-cb.getPadding("tb"));
29849 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29850 bd.setWidth(bw.getWidth(true));
29852 this.tabs.syncHeight();
29854 this.tabs.el.repaint();
29860 * Restores the previous state of the dialog if Roo.state is configured.
29861 * @return {Roo.BasicDialog} this
29863 restoreState : function(){
29864 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29865 if(box && box.width){
29866 this.xy = [box.x, box.y];
29867 this.resizeTo(box.width, box.height);
29873 beforeShow : function(){
29875 if(this.fixedcenter){
29876 this.xy = this.el.getCenterXY(true);
29879 Roo.get(document.body).addClass("x-body-masked");
29880 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29883 this.constrainXY();
29887 animShow : function(){
29888 var b = Roo.get(this.animateTarget).getBox();
29889 this.proxy.setSize(b.width, b.height);
29890 this.proxy.setLocation(b.x, b.y);
29892 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29893 true, .35, this.showEl.createDelegate(this));
29897 * Shows the dialog.
29898 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29899 * @return {Roo.BasicDialog} this
29901 show : function(animateTarget){
29902 if (this.fireEvent("beforeshow", this) === false){
29905 if(this.syncHeightBeforeShow){
29906 this.syncBodyHeight();
29907 }else if(this.firstShow){
29908 this.firstShow = false;
29909 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29911 this.animateTarget = animateTarget || this.animateTarget;
29912 if(!this.el.isVisible()){
29914 if(this.animateTarget && Roo.get(this.animateTarget)){
29924 showEl : function(){
29926 this.el.setXY(this.xy);
29928 this.adjustAssets(true);
29931 // IE peekaboo bug - fix found by Dave Fenwick
29935 this.fireEvent("show", this);
29939 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29940 * dialog itself will receive focus.
29942 focus : function(){
29943 if(this.defaultButton){
29944 this.defaultButton.focus();
29946 this.focusEl.focus();
29951 constrainXY : function(){
29952 if(this.constraintoviewport !== false){
29953 if(!this.viewSize){
29954 if(this.container){
29955 var s = this.container.getSize();
29956 this.viewSize = [s.width, s.height];
29958 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29961 var s = Roo.get(this.container||document).getScroll();
29963 var x = this.xy[0], y = this.xy[1];
29964 var w = this.size.width, h = this.size.height;
29965 var vw = this.viewSize[0], vh = this.viewSize[1];
29966 // only move it if it needs it
29968 // first validate right/bottom
29969 if(x + w > vw+s.left){
29973 if(y + h > vh+s.top){
29977 // then make sure top/left isn't negative
29989 if(this.isVisible()){
29990 this.el.setLocation(x, y);
29991 this.adjustAssets();
29998 onDrag : function(){
29999 if(!this.proxyDrag){
30000 this.xy = this.el.getXY();
30001 this.adjustAssets();
30006 adjustAssets : function(doShow){
30007 var x = this.xy[0], y = this.xy[1];
30008 var w = this.size.width, h = this.size.height;
30009 if(doShow === true){
30011 this.shadow.show(this.el);
30017 if(this.shadow && this.shadow.isVisible()){
30018 this.shadow.show(this.el);
30020 if(this.shim && this.shim.isVisible()){
30021 this.shim.setBounds(x, y, w, h);
30026 adjustViewport : function(w, h){
30028 w = Roo.lib.Dom.getViewWidth();
30029 h = Roo.lib.Dom.getViewHeight();
30032 this.viewSize = [w, h];
30033 if(this.modal && this.mask.isVisible()){
30034 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30035 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30037 if(this.isVisible()){
30038 this.constrainXY();
30043 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30044 * shadow, proxy, mask, etc.) Also removes all event listeners.
30045 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30047 destroy : function(removeEl){
30048 if(this.isVisible()){
30049 this.animateTarget = null;
30052 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30054 this.tabs.destroy(removeEl);
30067 for(var i = 0, len = this.buttons.length; i < len; i++){
30068 this.buttons[i].destroy();
30071 this.el.removeAllListeners();
30072 if(removeEl === true){
30073 this.el.update("");
30076 Roo.DialogManager.unregister(this);
30080 startMove : function(){
30081 if(this.proxyDrag){
30084 if(this.constraintoviewport !== false){
30085 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30090 endMove : function(){
30091 if(!this.proxyDrag){
30092 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30094 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30097 this.refreshSize();
30098 this.adjustAssets();
30100 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30104 * Brings this dialog to the front of any other visible dialogs
30105 * @return {Roo.BasicDialog} this
30107 toFront : function(){
30108 Roo.DialogManager.bringToFront(this);
30113 * Sends this dialog to the back (under) of any other visible dialogs
30114 * @return {Roo.BasicDialog} this
30116 toBack : function(){
30117 Roo.DialogManager.sendToBack(this);
30122 * Centers this dialog in the viewport
30123 * @return {Roo.BasicDialog} this
30125 center : function(){
30126 var xy = this.el.getCenterXY(true);
30127 this.moveTo(xy[0], xy[1]);
30132 * Moves the dialog's top-left corner to the specified point
30133 * @param {Number} x
30134 * @param {Number} y
30135 * @return {Roo.BasicDialog} this
30137 moveTo : function(x, y){
30139 if(this.isVisible()){
30140 this.el.setXY(this.xy);
30141 this.adjustAssets();
30147 * Aligns the dialog to the specified element
30148 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30149 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30150 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30151 * @return {Roo.BasicDialog} this
30153 alignTo : function(element, position, offsets){
30154 this.xy = this.el.getAlignToXY(element, position, offsets);
30155 if(this.isVisible()){
30156 this.el.setXY(this.xy);
30157 this.adjustAssets();
30163 * Anchors an element to another element and realigns it when the window is resized.
30164 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30165 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30166 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30167 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30168 * is a number, it is used as the buffer delay (defaults to 50ms).
30169 * @return {Roo.BasicDialog} this
30171 anchorTo : function(el, alignment, offsets, monitorScroll){
30172 var action = function(){
30173 this.alignTo(el, alignment, offsets);
30175 Roo.EventManager.onWindowResize(action, this);
30176 var tm = typeof monitorScroll;
30177 if(tm != 'undefined'){
30178 Roo.EventManager.on(window, 'scroll', action, this,
30179 {buffer: tm == 'number' ? monitorScroll : 50});
30186 * Returns true if the dialog is visible
30187 * @return {Boolean}
30189 isVisible : function(){
30190 return this.el.isVisible();
30194 animHide : function(callback){
30195 var b = Roo.get(this.animateTarget).getBox();
30197 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30199 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30200 this.hideEl.createDelegate(this, [callback]));
30204 * Hides the dialog.
30205 * @param {Function} callback (optional) Function to call when the dialog is hidden
30206 * @return {Roo.BasicDialog} this
30208 hide : function(callback){
30209 if (this.fireEvent("beforehide", this) === false){
30213 this.shadow.hide();
30218 // sometimes animateTarget seems to get set.. causing problems...
30219 // this just double checks..
30220 if(this.animateTarget && Roo.get(this.animateTarget)) {
30221 this.animHide(callback);
30224 this.hideEl(callback);
30230 hideEl : function(callback){
30234 Roo.get(document.body).removeClass("x-body-masked");
30236 this.fireEvent("hide", this);
30237 if(typeof callback == "function"){
30243 hideAction : function(){
30244 this.setLeft("-10000px");
30245 this.setTop("-10000px");
30246 this.setStyle("visibility", "hidden");
30250 refreshSize : function(){
30251 this.size = this.el.getSize();
30252 this.xy = this.el.getXY();
30253 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30257 // z-index is managed by the DialogManager and may be overwritten at any time
30258 setZIndex : function(index){
30260 this.mask.setStyle("z-index", index);
30263 this.shim.setStyle("z-index", ++index);
30266 this.shadow.setZIndex(++index);
30268 this.el.setStyle("z-index", ++index);
30270 this.proxy.setStyle("z-index", ++index);
30273 this.resizer.proxy.setStyle("z-index", ++index);
30276 this.lastZIndex = index;
30280 * Returns the element for this dialog
30281 * @return {Roo.Element} The underlying dialog Element
30283 getEl : function(){
30289 * @class Roo.DialogManager
30290 * Provides global access to BasicDialogs that have been created and
30291 * support for z-indexing (layering) multiple open dialogs.
30293 Roo.DialogManager = function(){
30295 var accessList = [];
30299 var sortDialogs = function(d1, d2){
30300 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30304 var orderDialogs = function(){
30305 accessList.sort(sortDialogs);
30306 var seed = Roo.DialogManager.zseed;
30307 for(var i = 0, len = accessList.length; i < len; i++){
30308 var dlg = accessList[i];
30310 dlg.setZIndex(seed + (i*10));
30317 * The starting z-index for BasicDialogs (defaults to 9000)
30318 * @type Number The z-index value
30323 register : function(dlg){
30324 list[dlg.id] = dlg;
30325 accessList.push(dlg);
30329 unregister : function(dlg){
30330 delete list[dlg.id];
30333 if(!accessList.indexOf){
30334 for( i = 0, len = accessList.length; i < len; i++){
30335 if(accessList[i] == dlg){
30336 accessList.splice(i, 1);
30341 i = accessList.indexOf(dlg);
30343 accessList.splice(i, 1);
30349 * Gets a registered dialog by id
30350 * @param {String/Object} id The id of the dialog or a dialog
30351 * @return {Roo.BasicDialog} this
30353 get : function(id){
30354 return typeof id == "object" ? id : list[id];
30358 * Brings the specified dialog to the front
30359 * @param {String/Object} dlg The id of the dialog or a dialog
30360 * @return {Roo.BasicDialog} this
30362 bringToFront : function(dlg){
30363 dlg = this.get(dlg);
30366 dlg._lastAccess = new Date().getTime();
30373 * Sends the specified dialog to the back
30374 * @param {String/Object} dlg The id of the dialog or a dialog
30375 * @return {Roo.BasicDialog} this
30377 sendToBack : function(dlg){
30378 dlg = this.get(dlg);
30379 dlg._lastAccess = -(new Date().getTime());
30385 * Hides all dialogs
30387 hideAll : function(){
30388 for(var id in list){
30389 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30398 * @class Roo.LayoutDialog
30399 * @extends Roo.BasicDialog
30400 * Dialog which provides adjustments for working with a layout in a Dialog.
30401 * Add your necessary layout config options to the dialog's config.<br>
30402 * Example usage (including a nested layout):
30405 dialog = new Roo.LayoutDialog("download-dlg", {
30414 // layout config merges with the dialog config
30416 tabPosition: "top",
30417 alwaysShowTabs: true
30420 dialog.addKeyListener(27, dialog.hide, dialog);
30421 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30422 dialog.addButton("Build It!", this.getDownload, this);
30424 // we can even add nested layouts
30425 var innerLayout = new Roo.BorderLayout("dl-inner", {
30435 innerLayout.beginUpdate();
30436 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30437 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30438 innerLayout.endUpdate(true);
30440 var layout = dialog.getLayout();
30441 layout.beginUpdate();
30442 layout.add("center", new Roo.ContentPanel("standard-panel",
30443 {title: "Download the Source", fitToFrame:true}));
30444 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30445 {title: "Build your own roo.js"}));
30446 layout.getRegion("center").showPanel(sp);
30447 layout.endUpdate();
30451 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30452 * @param {Object} config configuration options
30454 Roo.LayoutDialog = function(el, cfg){
30457 if (typeof(cfg) == 'undefined') {
30458 config = Roo.apply({}, el);
30459 // not sure why we use documentElement here.. - it should always be body.
30460 // IE7 borks horribly if we use documentElement.
30461 // webkit also does not like documentElement - it creates a body element...
30462 el = Roo.get( document.body || document.documentElement ).createChild();
30463 //config.autoCreate = true;
30467 config.autoTabs = false;
30468 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30469 this.body.setStyle({overflow:"hidden", position:"relative"});
30470 this.layout = new Roo.BorderLayout(this.body.dom, config);
30471 this.layout.monitorWindowResize = false;
30472 this.el.addClass("x-dlg-auto-layout");
30473 // fix case when center region overwrites center function
30474 this.center = Roo.BasicDialog.prototype.center;
30475 this.on("show", this.layout.layout, this.layout, true);
30476 if (config.items) {
30477 var xitems = config.items;
30478 delete config.items;
30479 Roo.each(xitems, this.addxtype, this);
30484 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30486 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30489 endUpdate : function(){
30490 this.layout.endUpdate();
30494 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30497 beginUpdate : function(){
30498 this.layout.beginUpdate();
30502 * Get the BorderLayout for this dialog
30503 * @return {Roo.BorderLayout}
30505 getLayout : function(){
30506 return this.layout;
30509 showEl : function(){
30510 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30512 this.layout.layout();
30517 // Use the syncHeightBeforeShow config option to control this automatically
30518 syncBodyHeight : function(){
30519 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30520 if(this.layout){this.layout.layout();}
30524 * Add an xtype element (actually adds to the layout.)
30525 * @return {Object} xdata xtype object data.
30528 addxtype : function(c) {
30529 return this.layout.addxtype(c);
30533 * Ext JS Library 1.1.1
30534 * Copyright(c) 2006-2007, Ext JS, LLC.
30536 * Originally Released Under LGPL - original licence link has changed is not relivant.
30539 * <script type="text/javascript">
30543 * @class Roo.MessageBox
30544 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30548 Roo.Msg.alert('Status', 'Changes saved successfully.');
30550 // Prompt for user data:
30551 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30553 // process text value...
30557 // Show a dialog using config options:
30559 title:'Save Changes?',
30560 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30561 buttons: Roo.Msg.YESNOCANCEL,
30568 Roo.MessageBox = function(){
30569 var dlg, opt, mask, waitTimer;
30570 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30571 var buttons, activeTextEl, bwidth;
30574 var handleButton = function(button){
30576 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30580 var handleHide = function(){
30581 if(opt && opt.cls){
30582 dlg.el.removeClass(opt.cls);
30585 Roo.TaskMgr.stop(waitTimer);
30591 var updateButtons = function(b){
30594 buttons["ok"].hide();
30595 buttons["cancel"].hide();
30596 buttons["yes"].hide();
30597 buttons["no"].hide();
30598 dlg.footer.dom.style.display = 'none';
30601 dlg.footer.dom.style.display = '';
30602 for(var k in buttons){
30603 if(typeof buttons[k] != "function"){
30606 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30607 width += buttons[k].el.getWidth()+15;
30617 var handleEsc = function(d, k, e){
30618 if(opt && opt.closable !== false){
30628 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30629 * @return {Roo.BasicDialog} The BasicDialog element
30631 getDialog : function(){
30633 dlg = new Roo.BasicDialog("x-msg-box", {
30638 constraintoviewport:false,
30640 collapsible : false,
30643 width:400, height:100,
30644 buttonAlign:"center",
30645 closeClick : function(){
30646 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30647 handleButton("no");
30649 handleButton("cancel");
30653 dlg.on("hide", handleHide);
30655 dlg.addKeyListener(27, handleEsc);
30657 var bt = this.buttonText;
30658 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30659 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30660 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30661 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30662 bodyEl = dlg.body.createChild({
30664 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>'
30666 msgEl = bodyEl.dom.firstChild;
30667 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30668 textboxEl.enableDisplayMode();
30669 textboxEl.addKeyListener([10,13], function(){
30670 if(dlg.isVisible() && opt && opt.buttons){
30671 if(opt.buttons.ok){
30672 handleButton("ok");
30673 }else if(opt.buttons.yes){
30674 handleButton("yes");
30678 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30679 textareaEl.enableDisplayMode();
30680 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30681 progressEl.enableDisplayMode();
30682 var pf = progressEl.dom.firstChild;
30684 pp = Roo.get(pf.firstChild);
30685 pp.setHeight(pf.offsetHeight);
30693 * Updates the message box body text
30694 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30695 * the XHTML-compliant non-breaking space character '&#160;')
30696 * @return {Roo.MessageBox} This message box
30698 updateText : function(text){
30699 if(!dlg.isVisible() && !opt.width){
30700 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30702 msgEl.innerHTML = text || ' ';
30704 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30705 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30707 Math.min(opt.width || cw , this.maxWidth),
30708 Math.max(opt.minWidth || this.minWidth, bwidth)
30711 activeTextEl.setWidth(w);
30713 if(dlg.isVisible()){
30714 dlg.fixedcenter = false;
30716 // to big, make it scroll. = But as usual stupid IE does not support
30719 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30720 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30721 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30723 bodyEl.dom.style.height = '';
30724 bodyEl.dom.style.overflowY = '';
30727 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30729 bodyEl.dom.style.overflowX = '';
30732 dlg.setContentSize(w, bodyEl.getHeight());
30733 if(dlg.isVisible()){
30734 dlg.fixedcenter = true;
30740 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30741 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30742 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30743 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30744 * @return {Roo.MessageBox} This message box
30746 updateProgress : function(value, text){
30748 this.updateText(text);
30750 if (pp) { // weird bug on my firefox - for some reason this is not defined
30751 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30757 * Returns true if the message box is currently displayed
30758 * @return {Boolean} True if the message box is visible, else false
30760 isVisible : function(){
30761 return dlg && dlg.isVisible();
30765 * Hides the message box if it is displayed
30768 if(this.isVisible()){
30774 * Displays a new message box, or reinitializes an existing message box, based on the config options
30775 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30776 * The following config object properties are supported:
30778 Property Type Description
30779 ---------- --------------- ------------------------------------------------------------------------------------
30780 animEl String/Element An id or Element from which the message box should animate as it opens and
30781 closes (defaults to undefined)
30782 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30783 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30784 closable Boolean False to hide the top-right close button (defaults to true). Note that
30785 progress and wait dialogs will ignore this property and always hide the
30786 close button as they can only be closed programmatically.
30787 cls String A custom CSS class to apply to the message box element
30788 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30789 displayed (defaults to 75)
30790 fn Function A callback function to execute after closing the dialog. The arguments to the
30791 function will be btn (the name of the button that was clicked, if applicable,
30792 e.g. "ok"), and text (the value of the active text field, if applicable).
30793 Progress and wait dialogs will ignore this option since they do not respond to
30794 user actions and can only be closed programmatically, so any required function
30795 should be called by the same code after it closes the dialog.
30796 icon String A CSS class that provides a background image to be used as an icon for
30797 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30798 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30799 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30800 modal Boolean False to allow user interaction with the page while the message box is
30801 displayed (defaults to true)
30802 msg String A string that will replace the existing message box body text (defaults
30803 to the XHTML-compliant non-breaking space character ' ')
30804 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30805 progress Boolean True to display a progress bar (defaults to false)
30806 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30807 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30808 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30809 title String The title text
30810 value String The string value to set into the active textbox element if displayed
30811 wait Boolean True to display a progress bar (defaults to false)
30812 width Number The width of the dialog in pixels
30819 msg: 'Please enter your address:',
30821 buttons: Roo.MessageBox.OKCANCEL,
30824 animEl: 'addAddressBtn'
30827 * @param {Object} config Configuration options
30828 * @return {Roo.MessageBox} This message box
30830 show : function(options)
30833 // this causes nightmares if you show one dialog after another
30834 // especially on callbacks..
30836 if(this.isVisible()){
30839 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30840 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30841 Roo.log("New Dialog Message:" + options.msg )
30842 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30843 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30846 var d = this.getDialog();
30848 d.setTitle(opt.title || " ");
30849 d.close.setDisplayed(opt.closable !== false);
30850 activeTextEl = textboxEl;
30851 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30856 textareaEl.setHeight(typeof opt.multiline == "number" ?
30857 opt.multiline : this.defaultTextHeight);
30858 activeTextEl = textareaEl;
30867 progressEl.setDisplayed(opt.progress === true);
30868 this.updateProgress(0);
30869 activeTextEl.dom.value = opt.value || "";
30871 dlg.setDefaultButton(activeTextEl);
30873 var bs = opt.buttons;
30876 db = buttons["ok"];
30877 }else if(bs && bs.yes){
30878 db = buttons["yes"];
30880 dlg.setDefaultButton(db);
30882 bwidth = updateButtons(opt.buttons);
30883 this.updateText(opt.msg);
30885 d.el.addClass(opt.cls);
30887 d.proxyDrag = opt.proxyDrag === true;
30888 d.modal = opt.modal !== false;
30889 d.mask = opt.modal !== false ? mask : false;
30890 if(!d.isVisible()){
30891 // force it to the end of the z-index stack so it gets a cursor in FF
30892 document.body.appendChild(dlg.el.dom);
30893 d.animateTarget = null;
30894 d.show(options.animEl);
30900 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30901 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30902 * and closing the message box when the process is complete.
30903 * @param {String} title The title bar text
30904 * @param {String} msg The message box body text
30905 * @return {Roo.MessageBox} This message box
30907 progress : function(title, msg){
30914 minWidth: this.minProgressWidth,
30921 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30922 * If a callback function is passed it will be called after the user clicks the button, and the
30923 * id of the button that was clicked will be passed as the only parameter to the callback
30924 * (could also be the top-right close button).
30925 * @param {String} title The title bar text
30926 * @param {String} msg The message box body text
30927 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30928 * @param {Object} scope (optional) The scope of the callback function
30929 * @return {Roo.MessageBox} This message box
30931 alert : function(title, msg, fn, scope){
30944 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30945 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30946 * You are responsible for closing the message box when the process is complete.
30947 * @param {String} msg The message box body text
30948 * @param {String} title (optional) The title bar text
30949 * @return {Roo.MessageBox} This message box
30951 wait : function(msg, title){
30962 waitTimer = Roo.TaskMgr.start({
30964 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30972 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30973 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30974 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30975 * @param {String} title The title bar text
30976 * @param {String} msg The message box body text
30977 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30978 * @param {Object} scope (optional) The scope of the callback function
30979 * @return {Roo.MessageBox} This message box
30981 confirm : function(title, msg, fn, scope){
30985 buttons: this.YESNO,
30994 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30995 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30996 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30997 * (could also be the top-right close button) and the text that was entered will be passed as the two
30998 * parameters to the callback.
30999 * @param {String} title The title bar text
31000 * @param {String} msg The message box body text
31001 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31002 * @param {Object} scope (optional) The scope of the callback function
31003 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31004 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31005 * @return {Roo.MessageBox} This message box
31007 prompt : function(title, msg, fn, scope, multiline){
31011 buttons: this.OKCANCEL,
31016 multiline: multiline,
31023 * Button config that displays a single OK button
31028 * Button config that displays Yes and No buttons
31031 YESNO : {yes:true, no:true},
31033 * Button config that displays OK and Cancel buttons
31036 OKCANCEL : {ok:true, cancel:true},
31038 * Button config that displays Yes, No and Cancel buttons
31041 YESNOCANCEL : {yes:true, no:true, cancel:true},
31044 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31047 defaultTextHeight : 75,
31049 * The maximum width in pixels of the message box (defaults to 600)
31054 * The minimum width in pixels of the message box (defaults to 100)
31059 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31060 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31063 minProgressWidth : 250,
31065 * An object containing the default button text strings that can be overriden for localized language support.
31066 * Supported properties are: ok, cancel, yes and no.
31067 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31080 * Shorthand for {@link Roo.MessageBox}
31082 Roo.Msg = Roo.MessageBox;/*
31084 * Ext JS Library 1.1.1
31085 * Copyright(c) 2006-2007, Ext JS, LLC.
31087 * Originally Released Under LGPL - original licence link has changed is not relivant.
31090 * <script type="text/javascript">
31093 * @class Roo.QuickTips
31094 * Provides attractive and customizable tooltips for any element.
31097 Roo.QuickTips = function(){
31098 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31099 var ce, bd, xy, dd;
31100 var visible = false, disabled = true, inited = false;
31101 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31103 var onOver = function(e){
31107 var t = e.getTarget();
31108 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31111 if(ce && t == ce.el){
31112 clearTimeout(hideProc);
31115 if(t && tagEls[t.id]){
31116 tagEls[t.id].el = t;
31117 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31120 var ttp, et = Roo.fly(t);
31121 var ns = cfg.namespace;
31122 if(tm.interceptTitles && t.title){
31125 t.removeAttribute("title");
31126 e.preventDefault();
31128 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31131 showProc = show.defer(tm.showDelay, tm, [{
31134 width: et.getAttributeNS(ns, cfg.width),
31135 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31136 title: et.getAttributeNS(ns, cfg.title),
31137 cls: et.getAttributeNS(ns, cfg.cls)
31142 var onOut = function(e){
31143 clearTimeout(showProc);
31144 var t = e.getTarget();
31145 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31146 hideProc = setTimeout(hide, tm.hideDelay);
31150 var onMove = function(e){
31156 if(tm.trackMouse && ce){
31161 var onDown = function(e){
31162 clearTimeout(showProc);
31163 clearTimeout(hideProc);
31165 if(tm.hideOnClick){
31168 tm.enable.defer(100, tm);
31173 var getPad = function(){
31174 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31177 var show = function(o){
31181 clearTimeout(dismissProc);
31183 if(removeCls){ // in case manually hidden
31184 el.removeClass(removeCls);
31188 el.addClass(ce.cls);
31189 removeCls = ce.cls;
31192 tipTitle.update(ce.title);
31195 tipTitle.update('');
31198 el.dom.style.width = tm.maxWidth+'px';
31199 //tipBody.dom.style.width = '';
31200 tipBodyText.update(o.text);
31201 var p = getPad(), w = ce.width;
31203 var td = tipBodyText.dom;
31204 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31205 if(aw > tm.maxWidth){
31207 }else if(aw < tm.minWidth){
31213 //tipBody.setWidth(w);
31214 el.setWidth(parseInt(w, 10) + p);
31215 if(ce.autoHide === false){
31216 close.setDisplayed(true);
31221 close.setDisplayed(false);
31227 el.avoidY = xy[1]-18;
31232 el.setStyle("visibility", "visible");
31233 el.fadeIn({callback: afterShow});
31239 var afterShow = function(){
31243 if(tm.autoDismiss && ce.autoHide !== false){
31244 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31249 var hide = function(noanim){
31250 clearTimeout(dismissProc);
31251 clearTimeout(hideProc);
31253 if(el.isVisible()){
31255 if(noanim !== true && tm.animate){
31256 el.fadeOut({callback: afterHide});
31263 var afterHide = function(){
31266 el.removeClass(removeCls);
31273 * @cfg {Number} minWidth
31274 * The minimum width of the quick tip (defaults to 40)
31278 * @cfg {Number} maxWidth
31279 * The maximum width of the quick tip (defaults to 300)
31283 * @cfg {Boolean} interceptTitles
31284 * True to automatically use the element's DOM title value if available (defaults to false)
31286 interceptTitles : false,
31288 * @cfg {Boolean} trackMouse
31289 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31291 trackMouse : false,
31293 * @cfg {Boolean} hideOnClick
31294 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31296 hideOnClick : true,
31298 * @cfg {Number} showDelay
31299 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31303 * @cfg {Number} hideDelay
31304 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31308 * @cfg {Boolean} autoHide
31309 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31310 * Used in conjunction with hideDelay.
31315 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31316 * (defaults to true). Used in conjunction with autoDismissDelay.
31318 autoDismiss : true,
31321 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31323 autoDismissDelay : 5000,
31325 * @cfg {Boolean} animate
31326 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31331 * @cfg {String} title
31332 * Title text to display (defaults to ''). This can be any valid HTML markup.
31336 * @cfg {String} text
31337 * Body text to display (defaults to ''). This can be any valid HTML markup.
31341 * @cfg {String} cls
31342 * A CSS class to apply to the base quick tip element (defaults to '').
31346 * @cfg {Number} width
31347 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31348 * minWidth or maxWidth.
31353 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31354 * or display QuickTips in a page.
31357 tm = Roo.QuickTips;
31358 cfg = tm.tagConfig;
31360 if(!Roo.isReady){ // allow calling of init() before onReady
31361 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31364 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31365 el.fxDefaults = {stopFx: true};
31366 // maximum custom styling
31367 //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>');
31368 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>');
31369 tipTitle = el.child('h3');
31370 tipTitle.enableDisplayMode("block");
31371 tipBody = el.child('div.x-tip-bd');
31372 tipBodyText = el.child('div.x-tip-bd-inner');
31373 //bdLeft = el.child('div.x-tip-bd-left');
31374 //bdRight = el.child('div.x-tip-bd-right');
31375 close = el.child('div.x-tip-close');
31376 close.enableDisplayMode("block");
31377 close.on("click", hide);
31378 var d = Roo.get(document);
31379 d.on("mousedown", onDown);
31380 d.on("mouseover", onOver);
31381 d.on("mouseout", onOut);
31382 d.on("mousemove", onMove);
31383 esc = d.addKeyListener(27, hide);
31386 dd = el.initDD("default", null, {
31387 onDrag : function(){
31391 dd.setHandleElId(tipTitle.id);
31400 * Configures a new quick tip instance and assigns it to a target element. The following config options
31403 Property Type Description
31404 ---------- --------------------- ------------------------------------------------------------------------
31405 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31407 * @param {Object} config The config object
31409 register : function(config){
31410 var cs = config instanceof Array ? config : arguments;
31411 for(var i = 0, len = cs.length; i < len; i++) {
31413 var target = c.target;
31415 if(target instanceof Array){
31416 for(var j = 0, jlen = target.length; j < jlen; j++){
31417 tagEls[target[j]] = c;
31420 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31427 * Removes this quick tip from its element and destroys it.
31428 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31430 unregister : function(el){
31431 delete tagEls[Roo.id(el)];
31435 * Enable this quick tip.
31437 enable : function(){
31438 if(inited && disabled){
31440 if(locks.length < 1){
31447 * Disable this quick tip.
31449 disable : function(){
31451 clearTimeout(showProc);
31452 clearTimeout(hideProc);
31453 clearTimeout(dismissProc);
31461 * Returns true if the quick tip is enabled, else false.
31463 isEnabled : function(){
31470 attribute : "qtip",
31480 // backwards compat
31481 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31483 * Ext JS Library 1.1.1
31484 * Copyright(c) 2006-2007, Ext JS, LLC.
31486 * Originally Released Under LGPL - original licence link has changed is not relivant.
31489 * <script type="text/javascript">
31494 * @class Roo.tree.TreePanel
31495 * @extends Roo.data.Tree
31497 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31498 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31499 * @cfg {Boolean} enableDD true to enable drag and drop
31500 * @cfg {Boolean} enableDrag true to enable just drag
31501 * @cfg {Boolean} enableDrop true to enable just drop
31502 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31503 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31504 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31505 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31506 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31507 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31508 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31509 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31510 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31511 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31512 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31513 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31514 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31515 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31516 * @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>
31517 * @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>
31520 * @param {String/HTMLElement/Element} el The container element
31521 * @param {Object} config
31523 Roo.tree.TreePanel = function(el, config){
31525 var loader = false;
31527 root = config.root;
31528 delete config.root;
31530 if (config.loader) {
31531 loader = config.loader;
31532 delete config.loader;
31535 Roo.apply(this, config);
31536 Roo.tree.TreePanel.superclass.constructor.call(this);
31537 this.el = Roo.get(el);
31538 this.el.addClass('x-tree');
31539 //console.log(root);
31541 this.setRootNode( Roo.factory(root, Roo.tree));
31544 this.loader = Roo.factory(loader, Roo.tree);
31547 * Read-only. The id of the container element becomes this TreePanel's id.
31549 this.id = this.el.id;
31552 * @event beforeload
31553 * Fires before a node is loaded, return false to cancel
31554 * @param {Node} node The node being loaded
31556 "beforeload" : true,
31559 * Fires when a node is loaded
31560 * @param {Node} node The node that was loaded
31564 * @event textchange
31565 * Fires when the text for a node is changed
31566 * @param {Node} node The node
31567 * @param {String} text The new text
31568 * @param {String} oldText The old text
31570 "textchange" : true,
31572 * @event beforeexpand
31573 * Fires before a node is expanded, return false to cancel.
31574 * @param {Node} node The node
31575 * @param {Boolean} deep
31576 * @param {Boolean} anim
31578 "beforeexpand" : true,
31580 * @event beforecollapse
31581 * Fires before a node is collapsed, return false to cancel.
31582 * @param {Node} node The node
31583 * @param {Boolean} deep
31584 * @param {Boolean} anim
31586 "beforecollapse" : true,
31589 * Fires when a node is expanded
31590 * @param {Node} node The node
31594 * @event disabledchange
31595 * Fires when the disabled status of a node changes
31596 * @param {Node} node The node
31597 * @param {Boolean} disabled
31599 "disabledchange" : true,
31602 * Fires when a node is collapsed
31603 * @param {Node} node The node
31607 * @event beforeclick
31608 * Fires before click processing on a node. Return false to cancel the default action.
31609 * @param {Node} node The node
31610 * @param {Roo.EventObject} e The event object
31612 "beforeclick":true,
31614 * @event checkchange
31615 * Fires when a node with a checkbox's checked property changes
31616 * @param {Node} this This node
31617 * @param {Boolean} checked
31619 "checkchange":true,
31622 * Fires when a node is clicked
31623 * @param {Node} node The node
31624 * @param {Roo.EventObject} e The event object
31629 * Fires when a node is double clicked
31630 * @param {Node} node The node
31631 * @param {Roo.EventObject} e The event object
31635 * @event contextmenu
31636 * Fires when a node is right clicked
31637 * @param {Node} node The node
31638 * @param {Roo.EventObject} e The event object
31640 "contextmenu":true,
31642 * @event beforechildrenrendered
31643 * Fires right before the child nodes for a node are rendered
31644 * @param {Node} node The node
31646 "beforechildrenrendered":true,
31649 * Fires when a node starts being dragged
31650 * @param {Roo.tree.TreePanel} this
31651 * @param {Roo.tree.TreeNode} node
31652 * @param {event} e The raw browser event
31654 "startdrag" : true,
31657 * Fires when a drag operation is complete
31658 * @param {Roo.tree.TreePanel} this
31659 * @param {Roo.tree.TreeNode} node
31660 * @param {event} e The raw browser event
31665 * Fires when a dragged node is dropped on a valid DD target
31666 * @param {Roo.tree.TreePanel} this
31667 * @param {Roo.tree.TreeNode} node
31668 * @param {DD} dd The dd it was dropped on
31669 * @param {event} e The raw browser event
31673 * @event beforenodedrop
31674 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31675 * passed to handlers has the following properties:<br />
31676 * <ul style="padding:5px;padding-left:16px;">
31677 * <li>tree - The TreePanel</li>
31678 * <li>target - The node being targeted for the drop</li>
31679 * <li>data - The drag data from the drag source</li>
31680 * <li>point - The point of the drop - append, above or below</li>
31681 * <li>source - The drag source</li>
31682 * <li>rawEvent - Raw mouse event</li>
31683 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31684 * to be inserted by setting them on this object.</li>
31685 * <li>cancel - Set this to true to cancel the drop.</li>
31687 * @param {Object} dropEvent
31689 "beforenodedrop" : true,
31692 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31693 * passed to handlers has the following properties:<br />
31694 * <ul style="padding:5px;padding-left:16px;">
31695 * <li>tree - The TreePanel</li>
31696 * <li>target - The node being targeted for the drop</li>
31697 * <li>data - The drag data from the drag source</li>
31698 * <li>point - The point of the drop - append, above or below</li>
31699 * <li>source - The drag source</li>
31700 * <li>rawEvent - Raw mouse event</li>
31701 * <li>dropNode - Dropped node(s).</li>
31703 * @param {Object} dropEvent
31707 * @event nodedragover
31708 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31709 * passed to handlers has the following properties:<br />
31710 * <ul style="padding:5px;padding-left:16px;">
31711 * <li>tree - The TreePanel</li>
31712 * <li>target - The node being targeted for the drop</li>
31713 * <li>data - The drag data from the drag source</li>
31714 * <li>point - The point of the drop - append, above or below</li>
31715 * <li>source - The drag source</li>
31716 * <li>rawEvent - Raw mouse event</li>
31717 * <li>dropNode - Drop node(s) provided by the source.</li>
31718 * <li>cancel - Set this to true to signal drop not allowed.</li>
31720 * @param {Object} dragOverEvent
31722 "nodedragover" : true
31725 if(this.singleExpand){
31726 this.on("beforeexpand", this.restrictExpand, this);
31729 this.editor.tree = this;
31730 this.editor = Roo.factory(this.editor, Roo.tree);
31733 if (this.selModel) {
31734 this.selModel = Roo.factory(this.selModel, Roo.tree);
31738 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31739 rootVisible : true,
31740 animate: Roo.enableFx,
31743 hlDrop : Roo.enableFx,
31747 rendererTip: false,
31749 restrictExpand : function(node){
31750 var p = node.parentNode;
31752 if(p.expandedChild && p.expandedChild.parentNode == p){
31753 p.expandedChild.collapse();
31755 p.expandedChild = node;
31759 // private override
31760 setRootNode : function(node){
31761 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31762 if(!this.rootVisible){
31763 node.ui = new Roo.tree.RootTreeNodeUI(node);
31769 * Returns the container element for this TreePanel
31771 getEl : function(){
31776 * Returns the default TreeLoader for this TreePanel
31778 getLoader : function(){
31779 return this.loader;
31785 expandAll : function(){
31786 this.root.expand(true);
31790 * Collapse all nodes
31792 collapseAll : function(){
31793 this.root.collapse(true);
31797 * Returns the selection model used by this TreePanel
31799 getSelectionModel : function(){
31800 if(!this.selModel){
31801 this.selModel = new Roo.tree.DefaultSelectionModel();
31803 return this.selModel;
31807 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31808 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31809 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31812 getChecked : function(a, startNode){
31813 startNode = startNode || this.root;
31815 var f = function(){
31816 if(this.attributes.checked){
31817 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31820 startNode.cascade(f);
31825 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31826 * @param {String} path
31827 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31828 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31829 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31831 expandPath : function(path, attr, callback){
31832 attr = attr || "id";
31833 var keys = path.split(this.pathSeparator);
31834 var curNode = this.root;
31835 if(curNode.attributes[attr] != keys[1]){ // invalid root
31837 callback(false, null);
31842 var f = function(){
31843 if(++index == keys.length){
31845 callback(true, curNode);
31849 var c = curNode.findChild(attr, keys[index]);
31852 callback(false, curNode);
31857 c.expand(false, false, f);
31859 curNode.expand(false, false, f);
31863 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31864 * @param {String} path
31865 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31866 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31867 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31869 selectPath : function(path, attr, callback){
31870 attr = attr || "id";
31871 var keys = path.split(this.pathSeparator);
31872 var v = keys.pop();
31873 if(keys.length > 0){
31874 var f = function(success, node){
31875 if(success && node){
31876 var n = node.findChild(attr, v);
31882 }else if(callback){
31883 callback(false, n);
31887 callback(false, n);
31891 this.expandPath(keys.join(this.pathSeparator), attr, f);
31893 this.root.select();
31895 callback(true, this.root);
31900 getTreeEl : function(){
31905 * Trigger rendering of this TreePanel
31907 render : function(){
31908 if (this.innerCt) {
31909 return this; // stop it rendering more than once!!
31912 this.innerCt = this.el.createChild({tag:"ul",
31913 cls:"x-tree-root-ct " +
31914 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31916 if(this.containerScroll){
31917 Roo.dd.ScrollManager.register(this.el);
31919 if((this.enableDD || this.enableDrop) && !this.dropZone){
31921 * The dropZone used by this tree if drop is enabled
31922 * @type Roo.tree.TreeDropZone
31924 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31925 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31928 if((this.enableDD || this.enableDrag) && !this.dragZone){
31930 * The dragZone used by this tree if drag is enabled
31931 * @type Roo.tree.TreeDragZone
31933 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31934 ddGroup: this.ddGroup || "TreeDD",
31935 scroll: this.ddScroll
31938 this.getSelectionModel().init(this);
31940 Roo.log("ROOT not set in tree");
31943 this.root.render();
31944 if(!this.rootVisible){
31945 this.root.renderChildren();
31951 * Ext JS Library 1.1.1
31952 * Copyright(c) 2006-2007, Ext JS, LLC.
31954 * Originally Released Under LGPL - original licence link has changed is not relivant.
31957 * <script type="text/javascript">
31962 * @class Roo.tree.DefaultSelectionModel
31963 * @extends Roo.util.Observable
31964 * The default single selection for a TreePanel.
31965 * @param {Object} cfg Configuration
31967 Roo.tree.DefaultSelectionModel = function(cfg){
31968 this.selNode = null;
31974 * @event selectionchange
31975 * Fires when the selected node changes
31976 * @param {DefaultSelectionModel} this
31977 * @param {TreeNode} node the new selection
31979 "selectionchange" : true,
31982 * @event beforeselect
31983 * Fires before the selected node changes, return false to cancel the change
31984 * @param {DefaultSelectionModel} this
31985 * @param {TreeNode} node the new selection
31986 * @param {TreeNode} node the old selection
31988 "beforeselect" : true
31991 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31994 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31995 init : function(tree){
31997 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31998 tree.on("click", this.onNodeClick, this);
32001 onNodeClick : function(node, e){
32002 if (e.ctrlKey && this.selNode == node) {
32003 this.unselect(node);
32011 * @param {TreeNode} node The node to select
32012 * @return {TreeNode} The selected node
32014 select : function(node){
32015 var last = this.selNode;
32016 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32018 last.ui.onSelectedChange(false);
32020 this.selNode = node;
32021 node.ui.onSelectedChange(true);
32022 this.fireEvent("selectionchange", this, node, last);
32029 * @param {TreeNode} node The node to unselect
32031 unselect : function(node){
32032 if(this.selNode == node){
32033 this.clearSelections();
32038 * Clear all selections
32040 clearSelections : function(){
32041 var n = this.selNode;
32043 n.ui.onSelectedChange(false);
32044 this.selNode = null;
32045 this.fireEvent("selectionchange", this, null);
32051 * Get the selected node
32052 * @return {TreeNode} The selected node
32054 getSelectedNode : function(){
32055 return this.selNode;
32059 * Returns true if the node is selected
32060 * @param {TreeNode} node The node to check
32061 * @return {Boolean}
32063 isSelected : function(node){
32064 return this.selNode == node;
32068 * Selects the node above the selected node in the tree, intelligently walking the nodes
32069 * @return TreeNode The new selection
32071 selectPrevious : function(){
32072 var s = this.selNode || this.lastSelNode;
32076 var ps = s.previousSibling;
32078 if(!ps.isExpanded() || ps.childNodes.length < 1){
32079 return this.select(ps);
32081 var lc = ps.lastChild;
32082 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32085 return this.select(lc);
32087 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32088 return this.select(s.parentNode);
32094 * Selects the node above the selected node in the tree, intelligently walking the nodes
32095 * @return TreeNode The new selection
32097 selectNext : function(){
32098 var s = this.selNode || this.lastSelNode;
32102 if(s.firstChild && s.isExpanded()){
32103 return this.select(s.firstChild);
32104 }else if(s.nextSibling){
32105 return this.select(s.nextSibling);
32106 }else if(s.parentNode){
32108 s.parentNode.bubble(function(){
32109 if(this.nextSibling){
32110 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32119 onKeyDown : function(e){
32120 var s = this.selNode || this.lastSelNode;
32121 // undesirable, but required
32126 var k = e.getKey();
32134 this.selectPrevious();
32137 e.preventDefault();
32138 if(s.hasChildNodes()){
32139 if(!s.isExpanded()){
32141 }else if(s.firstChild){
32142 this.select(s.firstChild, e);
32147 e.preventDefault();
32148 if(s.hasChildNodes() && s.isExpanded()){
32150 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32151 this.select(s.parentNode, e);
32159 * @class Roo.tree.MultiSelectionModel
32160 * @extends Roo.util.Observable
32161 * Multi selection for a TreePanel.
32162 * @param {Object} cfg Configuration
32164 Roo.tree.MultiSelectionModel = function(){
32165 this.selNodes = [];
32169 * @event selectionchange
32170 * Fires when the selected nodes change
32171 * @param {MultiSelectionModel} this
32172 * @param {Array} nodes Array of the selected nodes
32174 "selectionchange" : true
32176 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32180 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32181 init : function(tree){
32183 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32184 tree.on("click", this.onNodeClick, this);
32187 onNodeClick : function(node, e){
32188 this.select(node, e, e.ctrlKey);
32193 * @param {TreeNode} node The node to select
32194 * @param {EventObject} e (optional) An event associated with the selection
32195 * @param {Boolean} keepExisting True to retain existing selections
32196 * @return {TreeNode} The selected node
32198 select : function(node, e, keepExisting){
32199 if(keepExisting !== true){
32200 this.clearSelections(true);
32202 if(this.isSelected(node)){
32203 this.lastSelNode = node;
32206 this.selNodes.push(node);
32207 this.selMap[node.id] = node;
32208 this.lastSelNode = node;
32209 node.ui.onSelectedChange(true);
32210 this.fireEvent("selectionchange", this, this.selNodes);
32216 * @param {TreeNode} node The node to unselect
32218 unselect : function(node){
32219 if(this.selMap[node.id]){
32220 node.ui.onSelectedChange(false);
32221 var sn = this.selNodes;
32224 index = sn.indexOf(node);
32226 for(var i = 0, len = sn.length; i < len; i++){
32234 this.selNodes.splice(index, 1);
32236 delete this.selMap[node.id];
32237 this.fireEvent("selectionchange", this, this.selNodes);
32242 * Clear all selections
32244 clearSelections : function(suppressEvent){
32245 var sn = this.selNodes;
32247 for(var i = 0, len = sn.length; i < len; i++){
32248 sn[i].ui.onSelectedChange(false);
32250 this.selNodes = [];
32252 if(suppressEvent !== true){
32253 this.fireEvent("selectionchange", this, this.selNodes);
32259 * Returns true if the node is selected
32260 * @param {TreeNode} node The node to check
32261 * @return {Boolean}
32263 isSelected : function(node){
32264 return this.selMap[node.id] ? true : false;
32268 * Returns an array of the selected nodes
32271 getSelectedNodes : function(){
32272 return this.selNodes;
32275 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32277 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32279 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32282 * Ext JS Library 1.1.1
32283 * Copyright(c) 2006-2007, Ext JS, LLC.
32285 * Originally Released Under LGPL - original licence link has changed is not relivant.
32288 * <script type="text/javascript">
32292 * @class Roo.tree.TreeNode
32293 * @extends Roo.data.Node
32294 * @cfg {String} text The text for this node
32295 * @cfg {Boolean} expanded true to start the node expanded
32296 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32297 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32298 * @cfg {Boolean} disabled true to start the node disabled
32299 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32300 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32301 * @cfg {String} cls A css class to be added to the node
32302 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32303 * @cfg {String} href URL of the link used for the node (defaults to #)
32304 * @cfg {String} hrefTarget target frame for the link
32305 * @cfg {String} qtip An Ext QuickTip for the node
32306 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32307 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32308 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32309 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32310 * (defaults to undefined with no checkbox rendered)
32312 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32314 Roo.tree.TreeNode = function(attributes){
32315 attributes = attributes || {};
32316 if(typeof attributes == "string"){
32317 attributes = {text: attributes};
32319 this.childrenRendered = false;
32320 this.rendered = false;
32321 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32322 this.expanded = attributes.expanded === true;
32323 this.isTarget = attributes.isTarget !== false;
32324 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32325 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32328 * Read-only. The text for this node. To change it use setText().
32331 this.text = attributes.text;
32333 * True if this node is disabled.
32336 this.disabled = attributes.disabled === true;
32340 * @event textchange
32341 * Fires when the text for this node is changed
32342 * @param {Node} this This node
32343 * @param {String} text The new text
32344 * @param {String} oldText The old text
32346 "textchange" : true,
32348 * @event beforeexpand
32349 * Fires before this node is expanded, return false to cancel.
32350 * @param {Node} this This node
32351 * @param {Boolean} deep
32352 * @param {Boolean} anim
32354 "beforeexpand" : true,
32356 * @event beforecollapse
32357 * Fires before this node is collapsed, return false to cancel.
32358 * @param {Node} this This node
32359 * @param {Boolean} deep
32360 * @param {Boolean} anim
32362 "beforecollapse" : true,
32365 * Fires when this node is expanded
32366 * @param {Node} this This node
32370 * @event disabledchange
32371 * Fires when the disabled status of this node changes
32372 * @param {Node} this This node
32373 * @param {Boolean} disabled
32375 "disabledchange" : true,
32378 * Fires when this node is collapsed
32379 * @param {Node} this This node
32383 * @event beforeclick
32384 * Fires before click processing. Return false to cancel the default action.
32385 * @param {Node} this This node
32386 * @param {Roo.EventObject} e The event object
32388 "beforeclick":true,
32390 * @event checkchange
32391 * Fires when a node with a checkbox's checked property changes
32392 * @param {Node} this This node
32393 * @param {Boolean} checked
32395 "checkchange":true,
32398 * Fires when this node is clicked
32399 * @param {Node} this This node
32400 * @param {Roo.EventObject} e The event object
32405 * Fires when this node is double clicked
32406 * @param {Node} this This node
32407 * @param {Roo.EventObject} e The event object
32411 * @event contextmenu
32412 * Fires when this node is right clicked
32413 * @param {Node} this This node
32414 * @param {Roo.EventObject} e The event object
32416 "contextmenu":true,
32418 * @event beforechildrenrendered
32419 * Fires right before the child nodes for this node are rendered
32420 * @param {Node} this This node
32422 "beforechildrenrendered":true
32425 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32428 * Read-only. The UI for this node
32431 this.ui = new uiClass(this);
32433 // finally support items[]
32434 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32439 Roo.each(this.attributes.items, function(c) {
32440 this.appendChild(Roo.factory(c,Roo.Tree));
32442 delete this.attributes.items;
32447 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32448 preventHScroll: true,
32450 * Returns true if this node is expanded
32451 * @return {Boolean}
32453 isExpanded : function(){
32454 return this.expanded;
32458 * Returns the UI object for this node
32459 * @return {TreeNodeUI}
32461 getUI : function(){
32465 // private override
32466 setFirstChild : function(node){
32467 var of = this.firstChild;
32468 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32469 if(this.childrenRendered && of && node != of){
32470 of.renderIndent(true, true);
32473 this.renderIndent(true, true);
32477 // private override
32478 setLastChild : function(node){
32479 var ol = this.lastChild;
32480 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32481 if(this.childrenRendered && ol && node != ol){
32482 ol.renderIndent(true, true);
32485 this.renderIndent(true, true);
32489 // these methods are overridden to provide lazy rendering support
32490 // private override
32491 appendChild : function()
32493 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32494 if(node && this.childrenRendered){
32497 this.ui.updateExpandIcon();
32501 // private override
32502 removeChild : function(node){
32503 this.ownerTree.getSelectionModel().unselect(node);
32504 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32505 // if it's been rendered remove dom node
32506 if(this.childrenRendered){
32509 if(this.childNodes.length < 1){
32510 this.collapse(false, false);
32512 this.ui.updateExpandIcon();
32514 if(!this.firstChild) {
32515 this.childrenRendered = false;
32520 // private override
32521 insertBefore : function(node, refNode){
32522 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32523 if(newNode && refNode && this.childrenRendered){
32526 this.ui.updateExpandIcon();
32531 * Sets the text for this node
32532 * @param {String} text
32534 setText : function(text){
32535 var oldText = this.text;
32537 this.attributes.text = text;
32538 if(this.rendered){ // event without subscribing
32539 this.ui.onTextChange(this, text, oldText);
32541 this.fireEvent("textchange", this, text, oldText);
32545 * Triggers selection of this node
32547 select : function(){
32548 this.getOwnerTree().getSelectionModel().select(this);
32552 * Triggers deselection of this node
32554 unselect : function(){
32555 this.getOwnerTree().getSelectionModel().unselect(this);
32559 * Returns true if this node is selected
32560 * @return {Boolean}
32562 isSelected : function(){
32563 return this.getOwnerTree().getSelectionModel().isSelected(this);
32567 * Expand this node.
32568 * @param {Boolean} deep (optional) True to expand all children as well
32569 * @param {Boolean} anim (optional) false to cancel the default animation
32570 * @param {Function} callback (optional) A callback to be called when
32571 * expanding this node completes (does not wait for deep expand to complete).
32572 * Called with 1 parameter, this node.
32574 expand : function(deep, anim, callback){
32575 if(!this.expanded){
32576 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32579 if(!this.childrenRendered){
32580 this.renderChildren();
32582 this.expanded = true;
32583 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32584 this.ui.animExpand(function(){
32585 this.fireEvent("expand", this);
32586 if(typeof callback == "function"){
32590 this.expandChildNodes(true);
32592 }.createDelegate(this));
32596 this.fireEvent("expand", this);
32597 if(typeof callback == "function"){
32602 if(typeof callback == "function"){
32607 this.expandChildNodes(true);
32611 isHiddenRoot : function(){
32612 return this.isRoot && !this.getOwnerTree().rootVisible;
32616 * Collapse this node.
32617 * @param {Boolean} deep (optional) True to collapse all children as well
32618 * @param {Boolean} anim (optional) false to cancel the default animation
32620 collapse : function(deep, anim){
32621 if(this.expanded && !this.isHiddenRoot()){
32622 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32625 this.expanded = false;
32626 if((this.getOwnerTree().animate && anim !== false) || anim){
32627 this.ui.animCollapse(function(){
32628 this.fireEvent("collapse", this);
32630 this.collapseChildNodes(true);
32632 }.createDelegate(this));
32635 this.ui.collapse();
32636 this.fireEvent("collapse", this);
32640 var cs = this.childNodes;
32641 for(var i = 0, len = cs.length; i < len; i++) {
32642 cs[i].collapse(true, false);
32648 delayedExpand : function(delay){
32649 if(!this.expandProcId){
32650 this.expandProcId = this.expand.defer(delay, this);
32655 cancelExpand : function(){
32656 if(this.expandProcId){
32657 clearTimeout(this.expandProcId);
32659 this.expandProcId = false;
32663 * Toggles expanded/collapsed state of the node
32665 toggle : function(){
32674 * Ensures all parent nodes are expanded
32676 ensureVisible : function(callback){
32677 var tree = this.getOwnerTree();
32678 tree.expandPath(this.parentNode.getPath(), false, function(){
32679 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32680 Roo.callback(callback);
32681 }.createDelegate(this));
32685 * Expand all child nodes
32686 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32688 expandChildNodes : function(deep){
32689 var cs = this.childNodes;
32690 for(var i = 0, len = cs.length; i < len; i++) {
32691 cs[i].expand(deep);
32696 * Collapse all child nodes
32697 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32699 collapseChildNodes : function(deep){
32700 var cs = this.childNodes;
32701 for(var i = 0, len = cs.length; i < len; i++) {
32702 cs[i].collapse(deep);
32707 * Disables this node
32709 disable : function(){
32710 this.disabled = true;
32712 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32713 this.ui.onDisableChange(this, true);
32715 this.fireEvent("disabledchange", this, true);
32719 * Enables this node
32721 enable : function(){
32722 this.disabled = false;
32723 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32724 this.ui.onDisableChange(this, false);
32726 this.fireEvent("disabledchange", this, false);
32730 renderChildren : function(suppressEvent){
32731 if(suppressEvent !== false){
32732 this.fireEvent("beforechildrenrendered", this);
32734 var cs = this.childNodes;
32735 for(var i = 0, len = cs.length; i < len; i++){
32736 cs[i].render(true);
32738 this.childrenRendered = true;
32742 sort : function(fn, scope){
32743 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32744 if(this.childrenRendered){
32745 var cs = this.childNodes;
32746 for(var i = 0, len = cs.length; i < len; i++){
32747 cs[i].render(true);
32753 render : function(bulkRender){
32754 this.ui.render(bulkRender);
32755 if(!this.rendered){
32756 this.rendered = true;
32758 this.expanded = false;
32759 this.expand(false, false);
32765 renderIndent : function(deep, refresh){
32767 this.ui.childIndent = null;
32769 this.ui.renderIndent();
32770 if(deep === true && this.childrenRendered){
32771 var cs = this.childNodes;
32772 for(var i = 0, len = cs.length; i < len; i++){
32773 cs[i].renderIndent(true, refresh);
32779 * Ext JS Library 1.1.1
32780 * Copyright(c) 2006-2007, Ext JS, LLC.
32782 * Originally Released Under LGPL - original licence link has changed is not relivant.
32785 * <script type="text/javascript">
32789 * @class Roo.tree.AsyncTreeNode
32790 * @extends Roo.tree.TreeNode
32791 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32793 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32795 Roo.tree.AsyncTreeNode = function(config){
32796 this.loaded = false;
32797 this.loading = false;
32798 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32800 * @event beforeload
32801 * Fires before this node is loaded, return false to cancel
32802 * @param {Node} this This node
32804 this.addEvents({'beforeload':true, 'load': true});
32807 * Fires when this node is loaded
32808 * @param {Node} this This node
32811 * The loader used by this node (defaults to using the tree's defined loader)
32816 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32817 expand : function(deep, anim, callback){
32818 if(this.loading){ // if an async load is already running, waiting til it's done
32820 var f = function(){
32821 if(!this.loading){ // done loading
32822 clearInterval(timer);
32823 this.expand(deep, anim, callback);
32825 }.createDelegate(this);
32826 timer = setInterval(f, 200);
32830 if(this.fireEvent("beforeload", this) === false){
32833 this.loading = true;
32834 this.ui.beforeLoad(this);
32835 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32837 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32841 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32845 * Returns true if this node is currently loading
32846 * @return {Boolean}
32848 isLoading : function(){
32849 return this.loading;
32852 loadComplete : function(deep, anim, callback){
32853 this.loading = false;
32854 this.loaded = true;
32855 this.ui.afterLoad(this);
32856 this.fireEvent("load", this);
32857 this.expand(deep, anim, callback);
32861 * Returns true if this node has been loaded
32862 * @return {Boolean}
32864 isLoaded : function(){
32865 return this.loaded;
32868 hasChildNodes : function(){
32869 if(!this.isLeaf() && !this.loaded){
32872 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32877 * Trigger a reload for this node
32878 * @param {Function} callback
32880 reload : function(callback){
32881 this.collapse(false, false);
32882 while(this.firstChild){
32883 this.removeChild(this.firstChild);
32885 this.childrenRendered = false;
32886 this.loaded = false;
32887 if(this.isHiddenRoot()){
32888 this.expanded = false;
32890 this.expand(false, false, callback);
32894 * Ext JS Library 1.1.1
32895 * Copyright(c) 2006-2007, Ext JS, LLC.
32897 * Originally Released Under LGPL - original licence link has changed is not relivant.
32900 * <script type="text/javascript">
32904 * @class Roo.tree.TreeNodeUI
32906 * @param {Object} node The node to render
32907 * The TreeNode UI implementation is separate from the
32908 * tree implementation. Unless you are customizing the tree UI,
32909 * you should never have to use this directly.
32911 Roo.tree.TreeNodeUI = function(node){
32913 this.rendered = false;
32914 this.animating = false;
32915 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32918 Roo.tree.TreeNodeUI.prototype = {
32919 removeChild : function(node){
32921 this.ctNode.removeChild(node.ui.getEl());
32925 beforeLoad : function(){
32926 this.addClass("x-tree-node-loading");
32929 afterLoad : function(){
32930 this.removeClass("x-tree-node-loading");
32933 onTextChange : function(node, text, oldText){
32935 this.textNode.innerHTML = text;
32939 onDisableChange : function(node, state){
32940 this.disabled = state;
32942 this.addClass("x-tree-node-disabled");
32944 this.removeClass("x-tree-node-disabled");
32948 onSelectedChange : function(state){
32951 this.addClass("x-tree-selected");
32954 this.removeClass("x-tree-selected");
32958 onMove : function(tree, node, oldParent, newParent, index, refNode){
32959 this.childIndent = null;
32961 var targetNode = newParent.ui.getContainer();
32962 if(!targetNode){//target not rendered
32963 this.holder = document.createElement("div");
32964 this.holder.appendChild(this.wrap);
32967 var insertBefore = refNode ? refNode.ui.getEl() : null;
32969 targetNode.insertBefore(this.wrap, insertBefore);
32971 targetNode.appendChild(this.wrap);
32973 this.node.renderIndent(true);
32977 addClass : function(cls){
32979 Roo.fly(this.elNode).addClass(cls);
32983 removeClass : function(cls){
32985 Roo.fly(this.elNode).removeClass(cls);
32989 remove : function(){
32991 this.holder = document.createElement("div");
32992 this.holder.appendChild(this.wrap);
32996 fireEvent : function(){
32997 return this.node.fireEvent.apply(this.node, arguments);
33000 initEvents : function(){
33001 this.node.on("move", this.onMove, this);
33002 var E = Roo.EventManager;
33003 var a = this.anchor;
33005 var el = Roo.fly(a, '_treeui');
33007 if(Roo.isOpera){ // opera render bug ignores the CSS
33008 el.setStyle("text-decoration", "none");
33011 el.on("click", this.onClick, this);
33012 el.on("dblclick", this.onDblClick, this);
33015 Roo.EventManager.on(this.checkbox,
33016 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33019 el.on("contextmenu", this.onContextMenu, this);
33021 var icon = Roo.fly(this.iconNode);
33022 icon.on("click", this.onClick, this);
33023 icon.on("dblclick", this.onDblClick, this);
33024 icon.on("contextmenu", this.onContextMenu, this);
33025 E.on(this.ecNode, "click", this.ecClick, this, true);
33027 if(this.node.disabled){
33028 this.addClass("x-tree-node-disabled");
33030 if(this.node.hidden){
33031 this.addClass("x-tree-node-disabled");
33033 var ot = this.node.getOwnerTree();
33034 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33035 if(dd && (!this.node.isRoot || ot.rootVisible)){
33036 Roo.dd.Registry.register(this.elNode, {
33038 handles: this.getDDHandles(),
33044 getDDHandles : function(){
33045 return [this.iconNode, this.textNode];
33050 this.wrap.style.display = "none";
33056 this.wrap.style.display = "";
33060 onContextMenu : function(e){
33061 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33062 e.preventDefault();
33064 this.fireEvent("contextmenu", this.node, e);
33068 onClick : function(e){
33073 if(this.fireEvent("beforeclick", this.node, e) !== false){
33074 if(!this.disabled && this.node.attributes.href){
33075 this.fireEvent("click", this.node, e);
33078 e.preventDefault();
33083 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33084 this.node.toggle();
33087 this.fireEvent("click", this.node, e);
33093 onDblClick : function(e){
33094 e.preventDefault();
33099 this.toggleCheck();
33101 if(!this.animating && this.node.hasChildNodes()){
33102 this.node.toggle();
33104 this.fireEvent("dblclick", this.node, e);
33107 onCheckChange : function(){
33108 var checked = this.checkbox.checked;
33109 this.node.attributes.checked = checked;
33110 this.fireEvent('checkchange', this.node, checked);
33113 ecClick : function(e){
33114 if(!this.animating && this.node.hasChildNodes()){
33115 this.node.toggle();
33119 startDrop : function(){
33120 this.dropping = true;
33123 // delayed drop so the click event doesn't get fired on a drop
33124 endDrop : function(){
33125 setTimeout(function(){
33126 this.dropping = false;
33127 }.createDelegate(this), 50);
33130 expand : function(){
33131 this.updateExpandIcon();
33132 this.ctNode.style.display = "";
33135 focus : function(){
33136 if(!this.node.preventHScroll){
33137 try{this.anchor.focus();
33139 }else if(!Roo.isIE){
33141 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33142 var l = noscroll.scrollLeft;
33143 this.anchor.focus();
33144 noscroll.scrollLeft = l;
33149 toggleCheck : function(value){
33150 var cb = this.checkbox;
33152 cb.checked = (value === undefined ? !cb.checked : value);
33158 this.anchor.blur();
33162 animExpand : function(callback){
33163 var ct = Roo.get(this.ctNode);
33165 if(!this.node.hasChildNodes()){
33166 this.updateExpandIcon();
33167 this.ctNode.style.display = "";
33168 Roo.callback(callback);
33171 this.animating = true;
33172 this.updateExpandIcon();
33175 callback : function(){
33176 this.animating = false;
33177 Roo.callback(callback);
33180 duration: this.node.ownerTree.duration || .25
33184 highlight : function(){
33185 var tree = this.node.getOwnerTree();
33186 Roo.fly(this.wrap).highlight(
33187 tree.hlColor || "C3DAF9",
33188 {endColor: tree.hlBaseColor}
33192 collapse : function(){
33193 this.updateExpandIcon();
33194 this.ctNode.style.display = "none";
33197 animCollapse : function(callback){
33198 var ct = Roo.get(this.ctNode);
33199 ct.enableDisplayMode('block');
33202 this.animating = true;
33203 this.updateExpandIcon();
33206 callback : function(){
33207 this.animating = false;
33208 Roo.callback(callback);
33211 duration: this.node.ownerTree.duration || .25
33215 getContainer : function(){
33216 return this.ctNode;
33219 getEl : function(){
33223 appendDDGhost : function(ghostNode){
33224 ghostNode.appendChild(this.elNode.cloneNode(true));
33227 getDDRepairXY : function(){
33228 return Roo.lib.Dom.getXY(this.iconNode);
33231 onRender : function(){
33235 render : function(bulkRender){
33236 var n = this.node, a = n.attributes;
33237 var targetNode = n.parentNode ?
33238 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33240 if(!this.rendered){
33241 this.rendered = true;
33243 this.renderElements(n, a, targetNode, bulkRender);
33246 if(this.textNode.setAttributeNS){
33247 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33249 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33252 this.textNode.setAttribute("ext:qtip", a.qtip);
33254 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33257 }else if(a.qtipCfg){
33258 a.qtipCfg.target = Roo.id(this.textNode);
33259 Roo.QuickTips.register(a.qtipCfg);
33262 if(!this.node.expanded){
33263 this.updateExpandIcon();
33266 if(bulkRender === true) {
33267 targetNode.appendChild(this.wrap);
33272 renderElements : function(n, a, targetNode, bulkRender)
33274 // add some indent caching, this helps performance when rendering a large tree
33275 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33276 var t = n.getOwnerTree();
33277 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33278 if (typeof(n.attributes.html) != 'undefined') {
33279 txt = n.attributes.html;
33281 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33282 var cb = typeof a.checked == 'boolean';
33283 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33284 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33285 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33286 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33287 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33288 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33289 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33290 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33291 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33292 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33295 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33296 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33297 n.nextSibling.ui.getEl(), buf.join(""));
33299 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33302 this.elNode = this.wrap.childNodes[0];
33303 this.ctNode = this.wrap.childNodes[1];
33304 var cs = this.elNode.childNodes;
33305 this.indentNode = cs[0];
33306 this.ecNode = cs[1];
33307 this.iconNode = cs[2];
33310 this.checkbox = cs[3];
33313 this.anchor = cs[index];
33314 this.textNode = cs[index].firstChild;
33317 getAnchor : function(){
33318 return this.anchor;
33321 getTextEl : function(){
33322 return this.textNode;
33325 getIconEl : function(){
33326 return this.iconNode;
33329 isChecked : function(){
33330 return this.checkbox ? this.checkbox.checked : false;
33333 updateExpandIcon : function(){
33335 var n = this.node, c1, c2;
33336 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33337 var hasChild = n.hasChildNodes();
33341 c1 = "x-tree-node-collapsed";
33342 c2 = "x-tree-node-expanded";
33345 c1 = "x-tree-node-expanded";
33346 c2 = "x-tree-node-collapsed";
33349 this.removeClass("x-tree-node-leaf");
33350 this.wasLeaf = false;
33352 if(this.c1 != c1 || this.c2 != c2){
33353 Roo.fly(this.elNode).replaceClass(c1, c2);
33354 this.c1 = c1; this.c2 = c2;
33357 // this changes non-leafs into leafs if they have no children.
33358 // it's not very rational behaviour..
33360 if(!this.wasLeaf && this.node.leaf){
33361 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33364 this.wasLeaf = true;
33367 var ecc = "x-tree-ec-icon "+cls;
33368 if(this.ecc != ecc){
33369 this.ecNode.className = ecc;
33375 getChildIndent : function(){
33376 if(!this.childIndent){
33380 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33382 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33384 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33389 this.childIndent = buf.join("");
33391 return this.childIndent;
33394 renderIndent : function(){
33397 var p = this.node.parentNode;
33399 indent = p.ui.getChildIndent();
33401 if(this.indentMarkup != indent){ // don't rerender if not required
33402 this.indentNode.innerHTML = indent;
33403 this.indentMarkup = indent;
33405 this.updateExpandIcon();
33410 Roo.tree.RootTreeNodeUI = function(){
33411 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33413 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33414 render : function(){
33415 if(!this.rendered){
33416 var targetNode = this.node.ownerTree.innerCt.dom;
33417 this.node.expanded = true;
33418 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33419 this.wrap = this.ctNode = targetNode.firstChild;
33422 collapse : function(){
33424 expand : function(){
33428 * Ext JS Library 1.1.1
33429 * Copyright(c) 2006-2007, Ext JS, LLC.
33431 * Originally Released Under LGPL - original licence link has changed is not relivant.
33434 * <script type="text/javascript">
33437 * @class Roo.tree.TreeLoader
33438 * @extends Roo.util.Observable
33439 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33440 * nodes from a specified URL. The response must be a javascript Array definition
33441 * who's elements are node definition objects. eg:
33446 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33447 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33454 * The old style respose with just an array is still supported, but not recommended.
33457 * A server request is sent, and child nodes are loaded only when a node is expanded.
33458 * The loading node's id is passed to the server under the parameter name "node" to
33459 * enable the server to produce the correct child nodes.
33461 * To pass extra parameters, an event handler may be attached to the "beforeload"
33462 * event, and the parameters specified in the TreeLoader's baseParams property:
33464 myTreeLoader.on("beforeload", function(treeLoader, node) {
33465 this.baseParams.category = node.attributes.category;
33468 * This would pass an HTTP parameter called "category" to the server containing
33469 * the value of the Node's "category" attribute.
33471 * Creates a new Treeloader.
33472 * @param {Object} config A config object containing config properties.
33474 Roo.tree.TreeLoader = function(config){
33475 this.baseParams = {};
33476 this.requestMethod = "POST";
33477 Roo.apply(this, config);
33482 * @event beforeload
33483 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33484 * @param {Object} This TreeLoader object.
33485 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33486 * @param {Object} callback The callback function specified in the {@link #load} call.
33491 * Fires when the node has been successfuly loaded.
33492 * @param {Object} This TreeLoader object.
33493 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33494 * @param {Object} response The response object containing the data from the server.
33498 * @event loadexception
33499 * Fires if the network request failed.
33500 * @param {Object} This TreeLoader object.
33501 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33502 * @param {Object} response The response object containing the data from the server.
33504 loadexception : true,
33507 * Fires before a node is created, enabling you to return custom Node types
33508 * @param {Object} This TreeLoader object.
33509 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33514 Roo.tree.TreeLoader.superclass.constructor.call(this);
33517 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33519 * @cfg {String} dataUrl The URL from which to request a Json string which
33520 * specifies an array of node definition object representing the child nodes
33524 * @cfg {String} requestMethod either GET or POST
33525 * defaults to POST (due to BC)
33529 * @cfg {Object} baseParams (optional) An object containing properties which
33530 * specify HTTP parameters to be passed to each request for child nodes.
33533 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33534 * created by this loader. If the attributes sent by the server have an attribute in this object,
33535 * they take priority.
33538 * @cfg {Object} uiProviders (optional) An object containing properties which
33540 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33541 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33542 * <i>uiProvider</i> attribute of a returned child node is a string rather
33543 * than a reference to a TreeNodeUI implementation, this that string value
33544 * is used as a property name in the uiProviders object. You can define the provider named
33545 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33550 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33551 * child nodes before loading.
33553 clearOnLoad : true,
33556 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33557 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33558 * Grid query { data : [ .....] }
33563 * @cfg {String} queryParam (optional)
33564 * Name of the query as it will be passed on the querystring (defaults to 'node')
33565 * eg. the request will be ?node=[id]
33572 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33573 * This is called automatically when a node is expanded, but may be used to reload
33574 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33575 * @param {Roo.tree.TreeNode} node
33576 * @param {Function} callback
33578 load : function(node, callback){
33579 if(this.clearOnLoad){
33580 while(node.firstChild){
33581 node.removeChild(node.firstChild);
33584 if(node.attributes.children){ // preloaded json children
33585 var cs = node.attributes.children;
33586 for(var i = 0, len = cs.length; i < len; i++){
33587 node.appendChild(this.createNode(cs[i]));
33589 if(typeof callback == "function"){
33592 }else if(this.dataUrl){
33593 this.requestData(node, callback);
33597 getParams: function(node){
33598 var buf = [], bp = this.baseParams;
33599 for(var key in bp){
33600 if(typeof bp[key] != "function"){
33601 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33604 var n = this.queryParam === false ? 'node' : this.queryParam;
33605 buf.push(n + "=", encodeURIComponent(node.id));
33606 return buf.join("");
33609 requestData : function(node, callback){
33610 if(this.fireEvent("beforeload", this, node, callback) !== false){
33611 this.transId = Roo.Ajax.request({
33612 method:this.requestMethod,
33613 url: this.dataUrl||this.url,
33614 success: this.handleResponse,
33615 failure: this.handleFailure,
33617 argument: {callback: callback, node: node},
33618 params: this.getParams(node)
33621 // if the load is cancelled, make sure we notify
33622 // the node that we are done
33623 if(typeof callback == "function"){
33629 isLoading : function(){
33630 return this.transId ? true : false;
33633 abort : function(){
33634 if(this.isLoading()){
33635 Roo.Ajax.abort(this.transId);
33640 createNode : function(attr)
33642 // apply baseAttrs, nice idea Corey!
33643 if(this.baseAttrs){
33644 Roo.applyIf(attr, this.baseAttrs);
33646 if(this.applyLoader !== false){
33647 attr.loader = this;
33649 // uiProvider = depreciated..
33651 if(typeof(attr.uiProvider) == 'string'){
33652 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33653 /** eval:var:attr */ eval(attr.uiProvider);
33655 if(typeof(this.uiProviders['default']) != 'undefined') {
33656 attr.uiProvider = this.uiProviders['default'];
33659 this.fireEvent('create', this, attr);
33661 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33663 new Roo.tree.TreeNode(attr) :
33664 new Roo.tree.AsyncTreeNode(attr));
33667 processResponse : function(response, node, callback)
33669 var json = response.responseText;
33672 var o = Roo.decode(json);
33674 if (this.root === false && typeof(o.success) != undefined) {
33675 this.root = 'data'; // the default behaviour for list like data..
33678 if (this.root !== false && !o.success) {
33679 // it's a failure condition.
33680 var a = response.argument;
33681 this.fireEvent("loadexception", this, a.node, response);
33682 Roo.log("Load failed - should have a handler really");
33688 if (this.root !== false) {
33692 for(var i = 0, len = o.length; i < len; i++){
33693 var n = this.createNode(o[i]);
33695 node.appendChild(n);
33698 if(typeof callback == "function"){
33699 callback(this, node);
33702 this.handleFailure(response);
33706 handleResponse : function(response){
33707 this.transId = false;
33708 var a = response.argument;
33709 this.processResponse(response, a.node, a.callback);
33710 this.fireEvent("load", this, a.node, response);
33713 handleFailure : function(response)
33715 // should handle failure better..
33716 this.transId = false;
33717 var a = response.argument;
33718 this.fireEvent("loadexception", this, a.node, response);
33719 if(typeof a.callback == "function"){
33720 a.callback(this, a.node);
33725 * Ext JS Library 1.1.1
33726 * Copyright(c) 2006-2007, Ext JS, LLC.
33728 * Originally Released Under LGPL - original licence link has changed is not relivant.
33731 * <script type="text/javascript">
33735 * @class Roo.tree.TreeFilter
33736 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33737 * @param {TreePanel} tree
33738 * @param {Object} config (optional)
33740 Roo.tree.TreeFilter = function(tree, config){
33742 this.filtered = {};
33743 Roo.apply(this, config);
33746 Roo.tree.TreeFilter.prototype = {
33753 * Filter the data by a specific attribute.
33754 * @param {String/RegExp} value Either string that the attribute value
33755 * should start with or a RegExp to test against the attribute
33756 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33757 * @param {TreeNode} startNode (optional) The node to start the filter at.
33759 filter : function(value, attr, startNode){
33760 attr = attr || "text";
33762 if(typeof value == "string"){
33763 var vlen = value.length;
33764 // auto clear empty filter
33765 if(vlen == 0 && this.clearBlank){
33769 value = value.toLowerCase();
33771 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33773 }else if(value.exec){ // regex?
33775 return value.test(n.attributes[attr]);
33778 throw 'Illegal filter type, must be string or regex';
33780 this.filterBy(f, null, startNode);
33784 * Filter by a function. The passed function will be called with each
33785 * node in the tree (or from the startNode). If the function returns true, the node is kept
33786 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33787 * @param {Function} fn The filter function
33788 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33790 filterBy : function(fn, scope, startNode){
33791 startNode = startNode || this.tree.root;
33792 if(this.autoClear){
33795 var af = this.filtered, rv = this.reverse;
33796 var f = function(n){
33797 if(n == startNode){
33803 var m = fn.call(scope || n, n);
33811 startNode.cascade(f);
33814 if(typeof id != "function"){
33816 if(n && n.parentNode){
33817 n.parentNode.removeChild(n);
33825 * Clears the current filter. Note: with the "remove" option
33826 * set a filter cannot be cleared.
33828 clear : function(){
33830 var af = this.filtered;
33832 if(typeof id != "function"){
33839 this.filtered = {};
33844 * Ext JS Library 1.1.1
33845 * Copyright(c) 2006-2007, Ext JS, LLC.
33847 * Originally Released Under LGPL - original licence link has changed is not relivant.
33850 * <script type="text/javascript">
33855 * @class Roo.tree.TreeSorter
33856 * Provides sorting of nodes in a TreePanel
33858 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33859 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33860 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33861 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33862 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33863 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33865 * @param {TreePanel} tree
33866 * @param {Object} config
33868 Roo.tree.TreeSorter = function(tree, config){
33869 Roo.apply(this, config);
33870 tree.on("beforechildrenrendered", this.doSort, this);
33871 tree.on("append", this.updateSort, this);
33872 tree.on("insert", this.updateSort, this);
33874 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33875 var p = this.property || "text";
33876 var sortType = this.sortType;
33877 var fs = this.folderSort;
33878 var cs = this.caseSensitive === true;
33879 var leafAttr = this.leafAttr || 'leaf';
33881 this.sortFn = function(n1, n2){
33883 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33886 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33890 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33891 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33893 return dsc ? +1 : -1;
33895 return dsc ? -1 : +1;
33902 Roo.tree.TreeSorter.prototype = {
33903 doSort : function(node){
33904 node.sort(this.sortFn);
33907 compareNodes : function(n1, n2){
33908 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33911 updateSort : function(tree, node){
33912 if(node.childrenRendered){
33913 this.doSort.defer(1, this, [node]);
33918 * Ext JS Library 1.1.1
33919 * Copyright(c) 2006-2007, Ext JS, LLC.
33921 * Originally Released Under LGPL - original licence link has changed is not relivant.
33924 * <script type="text/javascript">
33927 if(Roo.dd.DropZone){
33929 Roo.tree.TreeDropZone = function(tree, config){
33930 this.allowParentInsert = false;
33931 this.allowContainerDrop = false;
33932 this.appendOnly = false;
33933 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33935 this.lastInsertClass = "x-tree-no-status";
33936 this.dragOverData = {};
33939 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33940 ddGroup : "TreeDD",
33943 expandDelay : 1000,
33945 expandNode : function(node){
33946 if(node.hasChildNodes() && !node.isExpanded()){
33947 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33951 queueExpand : function(node){
33952 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33955 cancelExpand : function(){
33956 if(this.expandProcId){
33957 clearTimeout(this.expandProcId);
33958 this.expandProcId = false;
33962 isValidDropPoint : function(n, pt, dd, e, data){
33963 if(!n || !data){ return false; }
33964 var targetNode = n.node;
33965 var dropNode = data.node;
33966 // default drop rules
33967 if(!(targetNode && targetNode.isTarget && pt)){
33970 if(pt == "append" && targetNode.allowChildren === false){
33973 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33976 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33979 // reuse the object
33980 var overEvent = this.dragOverData;
33981 overEvent.tree = this.tree;
33982 overEvent.target = targetNode;
33983 overEvent.data = data;
33984 overEvent.point = pt;
33985 overEvent.source = dd;
33986 overEvent.rawEvent = e;
33987 overEvent.dropNode = dropNode;
33988 overEvent.cancel = false;
33989 var result = this.tree.fireEvent("nodedragover", overEvent);
33990 return overEvent.cancel === false && result !== false;
33993 getDropPoint : function(e, n, dd)
33997 return tn.allowChildren !== false ? "append" : false; // always append for root
33999 var dragEl = n.ddel;
34000 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34001 var y = Roo.lib.Event.getPageY(e);
34002 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34004 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34005 var noAppend = tn.allowChildren === false;
34006 if(this.appendOnly || tn.parentNode.allowChildren === false){
34007 return noAppend ? false : "append";
34009 var noBelow = false;
34010 if(!this.allowParentInsert){
34011 noBelow = tn.hasChildNodes() && tn.isExpanded();
34013 var q = (b - t) / (noAppend ? 2 : 3);
34014 if(y >= t && y < (t + q)){
34016 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34023 onNodeEnter : function(n, dd, e, data)
34025 this.cancelExpand();
34028 onNodeOver : function(n, dd, e, data)
34031 var pt = this.getDropPoint(e, n, dd);
34034 // auto node expand check
34035 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34036 this.queueExpand(node);
34037 }else if(pt != "append"){
34038 this.cancelExpand();
34041 // set the insert point style on the target node
34042 var returnCls = this.dropNotAllowed;
34043 if(this.isValidDropPoint(n, pt, dd, e, data)){
34048 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34049 cls = "x-tree-drag-insert-above";
34050 }else if(pt == "below"){
34051 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34052 cls = "x-tree-drag-insert-below";
34054 returnCls = "x-tree-drop-ok-append";
34055 cls = "x-tree-drag-append";
34057 if(this.lastInsertClass != cls){
34058 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34059 this.lastInsertClass = cls;
34066 onNodeOut : function(n, dd, e, data){
34068 this.cancelExpand();
34069 this.removeDropIndicators(n);
34072 onNodeDrop : function(n, dd, e, data){
34073 var point = this.getDropPoint(e, n, dd);
34074 var targetNode = n.node;
34075 targetNode.ui.startDrop();
34076 if(!this.isValidDropPoint(n, point, dd, e, data)){
34077 targetNode.ui.endDrop();
34080 // first try to find the drop node
34081 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34084 target: targetNode,
34089 dropNode: dropNode,
34092 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34093 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34094 targetNode.ui.endDrop();
34097 // allow target changing
34098 targetNode = dropEvent.target;
34099 if(point == "append" && !targetNode.isExpanded()){
34100 targetNode.expand(false, null, function(){
34101 this.completeDrop(dropEvent);
34102 }.createDelegate(this));
34104 this.completeDrop(dropEvent);
34109 completeDrop : function(de){
34110 var ns = de.dropNode, p = de.point, t = de.target;
34111 if(!(ns instanceof Array)){
34115 for(var i = 0, len = ns.length; i < len; i++){
34118 t.parentNode.insertBefore(n, t);
34119 }else if(p == "below"){
34120 t.parentNode.insertBefore(n, t.nextSibling);
34126 if(this.tree.hlDrop){
34130 this.tree.fireEvent("nodedrop", de);
34133 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34134 if(this.tree.hlDrop){
34135 dropNode.ui.focus();
34136 dropNode.ui.highlight();
34138 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34141 getTree : function(){
34145 removeDropIndicators : function(n){
34148 Roo.fly(el).removeClass([
34149 "x-tree-drag-insert-above",
34150 "x-tree-drag-insert-below",
34151 "x-tree-drag-append"]);
34152 this.lastInsertClass = "_noclass";
34156 beforeDragDrop : function(target, e, id){
34157 this.cancelExpand();
34161 afterRepair : function(data){
34162 if(data && Roo.enableFx){
34163 data.node.ui.highlight();
34173 * Ext JS Library 1.1.1
34174 * Copyright(c) 2006-2007, Ext JS, LLC.
34176 * Originally Released Under LGPL - original licence link has changed is not relivant.
34179 * <script type="text/javascript">
34183 if(Roo.dd.DragZone){
34184 Roo.tree.TreeDragZone = function(tree, config){
34185 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34189 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34190 ddGroup : "TreeDD",
34192 onBeforeDrag : function(data, e){
34194 return n && n.draggable && !n.disabled;
34198 onInitDrag : function(e){
34199 var data = this.dragData;
34200 this.tree.getSelectionModel().select(data.node);
34201 this.proxy.update("");
34202 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34203 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34206 getRepairXY : function(e, data){
34207 return data.node.ui.getDDRepairXY();
34210 onEndDrag : function(data, e){
34211 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34216 onValidDrop : function(dd, e, id){
34217 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34221 beforeInvalidDrop : function(e, id){
34222 // this scrolls the original position back into view
34223 var sm = this.tree.getSelectionModel();
34224 sm.clearSelections();
34225 sm.select(this.dragData.node);
34230 * Ext JS Library 1.1.1
34231 * Copyright(c) 2006-2007, Ext JS, LLC.
34233 * Originally Released Under LGPL - original licence link has changed is not relivant.
34236 * <script type="text/javascript">
34239 * @class Roo.tree.TreeEditor
34240 * @extends Roo.Editor
34241 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34242 * as the editor field.
34244 * @param {Object} config (used to be the tree panel.)
34245 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34247 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34248 * @cfg {Roo.form.TextField|Object} field The field configuration
34252 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34255 if (oldconfig) { // old style..
34256 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34259 tree = config.tree;
34260 config.field = config.field || {};
34261 config.field.xtype = 'TextField';
34262 field = Roo.factory(config.field, Roo.form);
34264 config = config || {};
34269 * @event beforenodeedit
34270 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34271 * false from the handler of this event.
34272 * @param {Editor} this
34273 * @param {Roo.tree.Node} node
34275 "beforenodeedit" : true
34279 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34283 tree.on('beforeclick', this.beforeNodeClick, this);
34284 tree.getTreeEl().on('mousedown', this.hide, this);
34285 this.on('complete', this.updateNode, this);
34286 this.on('beforestartedit', this.fitToTree, this);
34287 this.on('startedit', this.bindScroll, this, {delay:10});
34288 this.on('specialkey', this.onSpecialKey, this);
34291 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34293 * @cfg {String} alignment
34294 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34300 * @cfg {Boolean} hideEl
34301 * True to hide the bound element while the editor is displayed (defaults to false)
34305 * @cfg {String} cls
34306 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34308 cls: "x-small-editor x-tree-editor",
34310 * @cfg {Boolean} shim
34311 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34317 * @cfg {Number} maxWidth
34318 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34319 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34320 * scroll and client offsets into account prior to each edit.
34327 fitToTree : function(ed, el){
34328 var td = this.tree.getTreeEl().dom, nd = el.dom;
34329 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34330 td.scrollLeft = nd.offsetLeft;
34334 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34335 this.setSize(w, '');
34337 return this.fireEvent('beforenodeedit', this, this.editNode);
34342 triggerEdit : function(node){
34343 this.completeEdit();
34344 this.editNode = node;
34345 this.startEdit(node.ui.textNode, node.text);
34349 bindScroll : function(){
34350 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34354 beforeNodeClick : function(node, e){
34355 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34356 this.lastClick = new Date();
34357 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34359 this.triggerEdit(node);
34366 updateNode : function(ed, value){
34367 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34368 this.editNode.setText(value);
34372 onHide : function(){
34373 Roo.tree.TreeEditor.superclass.onHide.call(this);
34375 this.editNode.ui.focus();
34380 onSpecialKey : function(field, e){
34381 var k = e.getKey();
34385 }else if(k == e.ENTER && !e.hasModifier()){
34387 this.completeEdit();
34390 });//<Script type="text/javascript">
34393 * Ext JS Library 1.1.1
34394 * Copyright(c) 2006-2007, Ext JS, LLC.
34396 * Originally Released Under LGPL - original licence link has changed is not relivant.
34399 * <script type="text/javascript">
34403 * Not documented??? - probably should be...
34406 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34407 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34409 renderElements : function(n, a, targetNode, bulkRender){
34410 //consel.log("renderElements?");
34411 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34413 var t = n.getOwnerTree();
34414 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34416 var cols = t.columns;
34417 var bw = t.borderWidth;
34419 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34420 var cb = typeof a.checked == "boolean";
34421 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34422 var colcls = 'x-t-' + tid + '-c0';
34424 '<li class="x-tree-node">',
34427 '<div class="x-tree-node-el ', a.cls,'">',
34429 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34432 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34433 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34434 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34435 (a.icon ? ' x-tree-node-inline-icon' : ''),
34436 (a.iconCls ? ' '+a.iconCls : ''),
34437 '" unselectable="on" />',
34438 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34439 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34441 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34442 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34443 '<span unselectable="on" qtip="' + tx + '">',
34447 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34448 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34450 for(var i = 1, len = cols.length; i < len; i++){
34452 colcls = 'x-t-' + tid + '-c' +i;
34453 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34454 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34455 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34461 '<div class="x-clear"></div></div>',
34462 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34465 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34466 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34467 n.nextSibling.ui.getEl(), buf.join(""));
34469 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34471 var el = this.wrap.firstChild;
34473 this.elNode = el.firstChild;
34474 this.ranchor = el.childNodes[1];
34475 this.ctNode = this.wrap.childNodes[1];
34476 var cs = el.firstChild.childNodes;
34477 this.indentNode = cs[0];
34478 this.ecNode = cs[1];
34479 this.iconNode = cs[2];
34482 this.checkbox = cs[3];
34485 this.anchor = cs[index];
34487 this.textNode = cs[index].firstChild;
34489 //el.on("click", this.onClick, this);
34490 //el.on("dblclick", this.onDblClick, this);
34493 // console.log(this);
34495 initEvents : function(){
34496 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34499 var a = this.ranchor;
34501 var el = Roo.get(a);
34503 if(Roo.isOpera){ // opera render bug ignores the CSS
34504 el.setStyle("text-decoration", "none");
34507 el.on("click", this.onClick, this);
34508 el.on("dblclick", this.onDblClick, this);
34509 el.on("contextmenu", this.onContextMenu, this);
34513 /*onSelectedChange : function(state){
34516 this.addClass("x-tree-selected");
34519 this.removeClass("x-tree-selected");
34522 addClass : function(cls){
34524 Roo.fly(this.elRow).addClass(cls);
34530 removeClass : function(cls){
34532 Roo.fly(this.elRow).removeClass(cls);
34538 });//<Script type="text/javascript">
34542 * Ext JS Library 1.1.1
34543 * Copyright(c) 2006-2007, Ext JS, LLC.
34545 * Originally Released Under LGPL - original licence link has changed is not relivant.
34548 * <script type="text/javascript">
34553 * @class Roo.tree.ColumnTree
34554 * @extends Roo.data.TreePanel
34555 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34556 * @cfg {int} borderWidth compined right/left border allowance
34558 * @param {String/HTMLElement/Element} el The container element
34559 * @param {Object} config
34561 Roo.tree.ColumnTree = function(el, config)
34563 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34567 * Fire this event on a container when it resizes
34568 * @param {int} w Width
34569 * @param {int} h Height
34573 this.on('resize', this.onResize, this);
34576 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34580 borderWidth: Roo.isBorderBox ? 0 : 2,
34583 render : function(){
34584 // add the header.....
34586 Roo.tree.ColumnTree.superclass.render.apply(this);
34588 this.el.addClass('x-column-tree');
34590 this.headers = this.el.createChild(
34591 {cls:'x-tree-headers'},this.innerCt.dom);
34593 var cols = this.columns, c;
34594 var totalWidth = 0;
34596 var len = cols.length;
34597 for(var i = 0; i < len; i++){
34599 totalWidth += c.width;
34600 this.headEls.push(this.headers.createChild({
34601 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34603 cls:'x-tree-hd-text',
34606 style:'width:'+(c.width-this.borderWidth)+'px;'
34609 this.headers.createChild({cls:'x-clear'});
34610 // prevent floats from wrapping when clipped
34611 this.headers.setWidth(totalWidth);
34612 //this.innerCt.setWidth(totalWidth);
34613 this.innerCt.setStyle({ overflow: 'auto' });
34614 this.onResize(this.width, this.height);
34618 onResize : function(w,h)
34623 this.innerCt.setWidth(this.width);
34624 this.innerCt.setHeight(this.height-20);
34627 var cols = this.columns, c;
34628 var totalWidth = 0;
34630 var len = cols.length;
34631 for(var i = 0; i < len; i++){
34633 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34634 // it's the expander..
34635 expEl = this.headEls[i];
34638 totalWidth += c.width;
34642 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34644 this.headers.setWidth(w-20);
34653 * Ext JS Library 1.1.1
34654 * Copyright(c) 2006-2007, Ext JS, LLC.
34656 * Originally Released Under LGPL - original licence link has changed is not relivant.
34659 * <script type="text/javascript">
34663 * @class Roo.menu.Menu
34664 * @extends Roo.util.Observable
34665 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34666 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34668 * Creates a new Menu
34669 * @param {Object} config Configuration options
34671 Roo.menu.Menu = function(config){
34672 Roo.apply(this, config);
34673 this.id = this.id || Roo.id();
34676 * @event beforeshow
34677 * Fires before this menu is displayed
34678 * @param {Roo.menu.Menu} this
34682 * @event beforehide
34683 * Fires before this menu is hidden
34684 * @param {Roo.menu.Menu} this
34689 * Fires after this menu is displayed
34690 * @param {Roo.menu.Menu} this
34695 * Fires after this menu is hidden
34696 * @param {Roo.menu.Menu} this
34701 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34702 * @param {Roo.menu.Menu} this
34703 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34704 * @param {Roo.EventObject} e
34709 * Fires when the mouse is hovering over this menu
34710 * @param {Roo.menu.Menu} this
34711 * @param {Roo.EventObject} e
34712 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34717 * Fires when the mouse exits this menu
34718 * @param {Roo.menu.Menu} this
34719 * @param {Roo.EventObject} e
34720 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34725 * Fires when a menu item contained in this menu is clicked
34726 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34727 * @param {Roo.EventObject} e
34731 if (this.registerMenu) {
34732 Roo.menu.MenuMgr.register(this);
34735 var mis = this.items;
34736 this.items = new Roo.util.MixedCollection();
34738 this.add.apply(this, mis);
34742 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34744 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34748 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34749 * for bottom-right shadow (defaults to "sides")
34753 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34754 * this menu (defaults to "tl-tr?")
34756 subMenuAlign : "tl-tr?",
34758 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34759 * relative to its element of origin (defaults to "tl-bl?")
34761 defaultAlign : "tl-bl?",
34763 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34765 allowOtherMenus : false,
34767 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34769 registerMenu : true,
34774 render : function(){
34778 var el = this.el = new Roo.Layer({
34780 shadow:this.shadow,
34782 parentEl: this.parentEl || document.body,
34786 this.keyNav = new Roo.menu.MenuNav(this);
34789 el.addClass("x-menu-plain");
34792 el.addClass(this.cls);
34794 // generic focus element
34795 this.focusEl = el.createChild({
34796 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34798 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34799 ul.on("click", this.onClick, this);
34800 ul.on("mouseover", this.onMouseOver, this);
34801 ul.on("mouseout", this.onMouseOut, this);
34802 this.items.each(function(item){
34807 var li = document.createElement("li");
34808 li.className = "x-menu-list-item";
34809 ul.dom.appendChild(li);
34810 item.render(li, this);
34817 autoWidth : function(){
34818 var el = this.el, ul = this.ul;
34822 var w = this.width;
34825 }else if(Roo.isIE){
34826 el.setWidth(this.minWidth);
34827 var t = el.dom.offsetWidth; // force recalc
34828 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34833 delayAutoWidth : function(){
34836 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34838 this.awTask.delay(20);
34843 findTargetItem : function(e){
34844 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34845 if(t && t.menuItemId){
34846 return this.items.get(t.menuItemId);
34851 onClick : function(e){
34853 if(t = this.findTargetItem(e)){
34855 this.fireEvent("click", this, t, e);
34860 setActiveItem : function(item, autoExpand){
34861 if(item != this.activeItem){
34862 if(this.activeItem){
34863 this.activeItem.deactivate();
34865 this.activeItem = item;
34866 item.activate(autoExpand);
34867 }else if(autoExpand){
34873 tryActivate : function(start, step){
34874 var items = this.items;
34875 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34876 var item = items.get(i);
34877 if(!item.disabled && item.canActivate){
34878 this.setActiveItem(item, false);
34886 onMouseOver : function(e){
34888 if(t = this.findTargetItem(e)){
34889 if(t.canActivate && !t.disabled){
34890 this.setActiveItem(t, true);
34893 this.fireEvent("mouseover", this, e, t);
34897 onMouseOut : function(e){
34899 if(t = this.findTargetItem(e)){
34900 if(t == this.activeItem && t.shouldDeactivate(e)){
34901 this.activeItem.deactivate();
34902 delete this.activeItem;
34905 this.fireEvent("mouseout", this, e, t);
34909 * Read-only. Returns true if the menu is currently displayed, else false.
34912 isVisible : function(){
34913 return this.el && !this.hidden;
34917 * Displays this menu relative to another element
34918 * @param {String/HTMLElement/Roo.Element} element The element to align to
34919 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34920 * the element (defaults to this.defaultAlign)
34921 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34923 show : function(el, pos, parentMenu){
34924 this.parentMenu = parentMenu;
34928 this.fireEvent("beforeshow", this);
34929 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34933 * Displays this menu at a specific xy position
34934 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34935 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34937 showAt : function(xy, parentMenu, /* private: */_e){
34938 this.parentMenu = parentMenu;
34943 this.fireEvent("beforeshow", this);
34944 xy = this.el.adjustForConstraints(xy);
34948 this.hidden = false;
34950 this.fireEvent("show", this);
34953 focus : function(){
34955 this.doFocus.defer(50, this);
34959 doFocus : function(){
34961 this.focusEl.focus();
34966 * Hides this menu and optionally all parent menus
34967 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34969 hide : function(deep){
34970 if(this.el && this.isVisible()){
34971 this.fireEvent("beforehide", this);
34972 if(this.activeItem){
34973 this.activeItem.deactivate();
34974 this.activeItem = null;
34977 this.hidden = true;
34978 this.fireEvent("hide", this);
34980 if(deep === true && this.parentMenu){
34981 this.parentMenu.hide(true);
34986 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34987 * Any of the following are valid:
34989 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34990 * <li>An HTMLElement object which will be converted to a menu item</li>
34991 * <li>A menu item config object that will be created as a new menu item</li>
34992 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34993 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34998 var menu = new Roo.menu.Menu();
35000 // Create a menu item to add by reference
35001 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35003 // Add a bunch of items at once using different methods.
35004 // Only the last item added will be returned.
35005 var item = menu.add(
35006 menuItem, // add existing item by ref
35007 'Dynamic Item', // new TextItem
35008 '-', // new separator
35009 { text: 'Config Item' } // new item by config
35012 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35013 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35016 var a = arguments, l = a.length, item;
35017 for(var i = 0; i < l; i++){
35019 if ((typeof(el) == "object") && el.xtype && el.xns) {
35020 el = Roo.factory(el, Roo.menu);
35023 if(el.render){ // some kind of Item
35024 item = this.addItem(el);
35025 }else if(typeof el == "string"){ // string
35026 if(el == "separator" || el == "-"){
35027 item = this.addSeparator();
35029 item = this.addText(el);
35031 }else if(el.tagName || el.el){ // element
35032 item = this.addElement(el);
35033 }else if(typeof el == "object"){ // must be menu item config?
35034 item = this.addMenuItem(el);
35041 * Returns this menu's underlying {@link Roo.Element} object
35042 * @return {Roo.Element} The element
35044 getEl : function(){
35052 * Adds a separator bar to the menu
35053 * @return {Roo.menu.Item} The menu item that was added
35055 addSeparator : function(){
35056 return this.addItem(new Roo.menu.Separator());
35060 * Adds an {@link Roo.Element} object to the menu
35061 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35062 * @return {Roo.menu.Item} The menu item that was added
35064 addElement : function(el){
35065 return this.addItem(new Roo.menu.BaseItem(el));
35069 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35070 * @param {Roo.menu.Item} item The menu item to add
35071 * @return {Roo.menu.Item} The menu item that was added
35073 addItem : function(item){
35074 this.items.add(item);
35076 var li = document.createElement("li");
35077 li.className = "x-menu-list-item";
35078 this.ul.dom.appendChild(li);
35079 item.render(li, this);
35080 this.delayAutoWidth();
35086 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35087 * @param {Object} config A MenuItem config object
35088 * @return {Roo.menu.Item} The menu item that was added
35090 addMenuItem : function(config){
35091 if(!(config instanceof Roo.menu.Item)){
35092 if(typeof config.checked == "boolean"){ // must be check menu item config?
35093 config = new Roo.menu.CheckItem(config);
35095 config = new Roo.menu.Item(config);
35098 return this.addItem(config);
35102 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35103 * @param {String} text The text to display in the menu item
35104 * @return {Roo.menu.Item} The menu item that was added
35106 addText : function(text){
35107 return this.addItem(new Roo.menu.TextItem({ text : text }));
35111 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35112 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35113 * @param {Roo.menu.Item} item The menu item to add
35114 * @return {Roo.menu.Item} The menu item that was added
35116 insert : function(index, item){
35117 this.items.insert(index, item);
35119 var li = document.createElement("li");
35120 li.className = "x-menu-list-item";
35121 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35122 item.render(li, this);
35123 this.delayAutoWidth();
35129 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35130 * @param {Roo.menu.Item} item The menu item to remove
35132 remove : function(item){
35133 this.items.removeKey(item.id);
35138 * Removes and destroys all items in the menu
35140 removeAll : function(){
35142 while(f = this.items.first()){
35148 // MenuNav is a private utility class used internally by the Menu
35149 Roo.menu.MenuNav = function(menu){
35150 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35151 this.scope = this.menu = menu;
35154 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35155 doRelay : function(e, h){
35156 var k = e.getKey();
35157 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35158 this.menu.tryActivate(0, 1);
35161 return h.call(this.scope || this, e, this.menu);
35164 up : function(e, m){
35165 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35166 m.tryActivate(m.items.length-1, -1);
35170 down : function(e, m){
35171 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35172 m.tryActivate(0, 1);
35176 right : function(e, m){
35178 m.activeItem.expandMenu(true);
35182 left : function(e, m){
35184 if(m.parentMenu && m.parentMenu.activeItem){
35185 m.parentMenu.activeItem.activate();
35189 enter : function(e, m){
35191 e.stopPropagation();
35192 m.activeItem.onClick(e);
35193 m.fireEvent("click", this, m.activeItem);
35199 * Ext JS Library 1.1.1
35200 * Copyright(c) 2006-2007, Ext JS, LLC.
35202 * Originally Released Under LGPL - original licence link has changed is not relivant.
35205 * <script type="text/javascript">
35209 * @class Roo.menu.MenuMgr
35210 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35213 Roo.menu.MenuMgr = function(){
35214 var menus, active, groups = {}, attached = false, lastShow = new Date();
35216 // private - called when first menu is created
35219 active = new Roo.util.MixedCollection();
35220 Roo.get(document).addKeyListener(27, function(){
35221 if(active.length > 0){
35228 function hideAll(){
35229 if(active && active.length > 0){
35230 var c = active.clone();
35231 c.each(function(m){
35238 function onHide(m){
35240 if(active.length < 1){
35241 Roo.get(document).un("mousedown", onMouseDown);
35247 function onShow(m){
35248 var last = active.last();
35249 lastShow = new Date();
35252 Roo.get(document).on("mousedown", onMouseDown);
35256 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35257 m.parentMenu.activeChild = m;
35258 }else if(last && last.isVisible()){
35259 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35264 function onBeforeHide(m){
35266 m.activeChild.hide();
35268 if(m.autoHideTimer){
35269 clearTimeout(m.autoHideTimer);
35270 delete m.autoHideTimer;
35275 function onBeforeShow(m){
35276 var pm = m.parentMenu;
35277 if(!pm && !m.allowOtherMenus){
35279 }else if(pm && pm.activeChild && active != m){
35280 pm.activeChild.hide();
35285 function onMouseDown(e){
35286 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35292 function onBeforeCheck(mi, state){
35294 var g = groups[mi.group];
35295 for(var i = 0, l = g.length; i < l; i++){
35297 g[i].setChecked(false);
35306 * Hides all menus that are currently visible
35308 hideAll : function(){
35313 register : function(menu){
35317 menus[menu.id] = menu;
35318 menu.on("beforehide", onBeforeHide);
35319 menu.on("hide", onHide);
35320 menu.on("beforeshow", onBeforeShow);
35321 menu.on("show", onShow);
35322 var g = menu.group;
35323 if(g && menu.events["checkchange"]){
35327 groups[g].push(menu);
35328 menu.on("checkchange", onCheck);
35333 * Returns a {@link Roo.menu.Menu} object
35334 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35335 * be used to generate and return a new Menu instance.
35337 get : function(menu){
35338 if(typeof menu == "string"){ // menu id
35339 return menus[menu];
35340 }else if(menu.events){ // menu instance
35342 }else if(typeof menu.length == 'number'){ // array of menu items?
35343 return new Roo.menu.Menu({items:menu});
35344 }else{ // otherwise, must be a config
35345 return new Roo.menu.Menu(menu);
35350 unregister : function(menu){
35351 delete menus[menu.id];
35352 menu.un("beforehide", onBeforeHide);
35353 menu.un("hide", onHide);
35354 menu.un("beforeshow", onBeforeShow);
35355 menu.un("show", onShow);
35356 var g = menu.group;
35357 if(g && menu.events["checkchange"]){
35358 groups[g].remove(menu);
35359 menu.un("checkchange", onCheck);
35364 registerCheckable : function(menuItem){
35365 var g = menuItem.group;
35370 groups[g].push(menuItem);
35371 menuItem.on("beforecheckchange", onBeforeCheck);
35376 unregisterCheckable : function(menuItem){
35377 var g = menuItem.group;
35379 groups[g].remove(menuItem);
35380 menuItem.un("beforecheckchange", onBeforeCheck);
35386 * Ext JS Library 1.1.1
35387 * Copyright(c) 2006-2007, Ext JS, LLC.
35389 * Originally Released Under LGPL - original licence link has changed is not relivant.
35392 * <script type="text/javascript">
35397 * @class Roo.menu.BaseItem
35398 * @extends Roo.Component
35399 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35400 * management and base configuration options shared by all menu components.
35402 * Creates a new BaseItem
35403 * @param {Object} config Configuration options
35405 Roo.menu.BaseItem = function(config){
35406 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35411 * Fires when this item is clicked
35412 * @param {Roo.menu.BaseItem} this
35413 * @param {Roo.EventObject} e
35418 * Fires when this item is activated
35419 * @param {Roo.menu.BaseItem} this
35423 * @event deactivate
35424 * Fires when this item is deactivated
35425 * @param {Roo.menu.BaseItem} this
35431 this.on("click", this.handler, this.scope, true);
35435 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35437 * @cfg {Function} handler
35438 * A function that will handle the click event of this menu item (defaults to undefined)
35441 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35443 canActivate : false,
35446 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
35451 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35453 activeClass : "x-menu-item-active",
35455 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35457 hideOnClick : true,
35459 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35464 ctype: "Roo.menu.BaseItem",
35467 actionMode : "container",
35470 render : function(container, parentMenu){
35471 this.parentMenu = parentMenu;
35472 Roo.menu.BaseItem.superclass.render.call(this, container);
35473 this.container.menuItemId = this.id;
35477 onRender : function(container, position){
35478 this.el = Roo.get(this.el);
35479 container.dom.appendChild(this.el.dom);
35483 onClick : function(e){
35484 if(!this.disabled && this.fireEvent("click", this, e) !== false
35485 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35486 this.handleClick(e);
35493 activate : function(){
35497 var li = this.container;
35498 li.addClass(this.activeClass);
35499 this.region = li.getRegion().adjust(2, 2, -2, -2);
35500 this.fireEvent("activate", this);
35505 deactivate : function(){
35506 this.container.removeClass(this.activeClass);
35507 this.fireEvent("deactivate", this);
35511 shouldDeactivate : function(e){
35512 return !this.region || !this.region.contains(e.getPoint());
35516 handleClick : function(e){
35517 if(this.hideOnClick){
35518 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35523 expandMenu : function(autoActivate){
35528 hideMenu : function(){
35533 * Ext JS Library 1.1.1
35534 * Copyright(c) 2006-2007, Ext JS, LLC.
35536 * Originally Released Under LGPL - original licence link has changed is not relivant.
35539 * <script type="text/javascript">
35543 * @class Roo.menu.Adapter
35544 * @extends Roo.menu.BaseItem
35545 * 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.
35546 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35548 * Creates a new Adapter
35549 * @param {Object} config Configuration options
35551 Roo.menu.Adapter = function(component, config){
35552 Roo.menu.Adapter.superclass.constructor.call(this, config);
35553 this.component = component;
35555 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35557 canActivate : true,
35560 onRender : function(container, position){
35561 this.component.render(container);
35562 this.el = this.component.getEl();
35566 activate : function(){
35570 this.component.focus();
35571 this.fireEvent("activate", this);
35576 deactivate : function(){
35577 this.fireEvent("deactivate", this);
35581 disable : function(){
35582 this.component.disable();
35583 Roo.menu.Adapter.superclass.disable.call(this);
35587 enable : function(){
35588 this.component.enable();
35589 Roo.menu.Adapter.superclass.enable.call(this);
35593 * Ext JS Library 1.1.1
35594 * Copyright(c) 2006-2007, Ext JS, LLC.
35596 * Originally Released Under LGPL - original licence link has changed is not relivant.
35599 * <script type="text/javascript">
35603 * @class Roo.menu.TextItem
35604 * @extends Roo.menu.BaseItem
35605 * Adds a static text string to a menu, usually used as either a heading or group separator.
35606 * Note: old style constructor with text is still supported.
35609 * Creates a new TextItem
35610 * @param {Object} cfg Configuration
35612 Roo.menu.TextItem = function(cfg){
35613 if (typeof(cfg) == 'string') {
35616 Roo.apply(this,cfg);
35619 Roo.menu.TextItem.superclass.constructor.call(this);
35622 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35624 * @cfg {Boolean} text Text to show on item.
35629 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35631 hideOnClick : false,
35633 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35635 itemCls : "x-menu-text",
35638 onRender : function(){
35639 var s = document.createElement("span");
35640 s.className = this.itemCls;
35641 s.innerHTML = this.text;
35643 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35647 * Ext JS Library 1.1.1
35648 * Copyright(c) 2006-2007, Ext JS, LLC.
35650 * Originally Released Under LGPL - original licence link has changed is not relivant.
35653 * <script type="text/javascript">
35657 * @class Roo.menu.Separator
35658 * @extends Roo.menu.BaseItem
35659 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35660 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35662 * @param {Object} config Configuration options
35664 Roo.menu.Separator = function(config){
35665 Roo.menu.Separator.superclass.constructor.call(this, config);
35668 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35670 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35672 itemCls : "x-menu-sep",
35674 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35676 hideOnClick : false,
35679 onRender : function(li){
35680 var s = document.createElement("span");
35681 s.className = this.itemCls;
35682 s.innerHTML = " ";
35684 li.addClass("x-menu-sep-li");
35685 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35689 * Ext JS Library 1.1.1
35690 * Copyright(c) 2006-2007, Ext JS, LLC.
35692 * Originally Released Under LGPL - original licence link has changed is not relivant.
35695 * <script type="text/javascript">
35698 * @class Roo.menu.Item
35699 * @extends Roo.menu.BaseItem
35700 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35701 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35702 * activation and click handling.
35704 * Creates a new Item
35705 * @param {Object} config Configuration options
35707 Roo.menu.Item = function(config){
35708 Roo.menu.Item.superclass.constructor.call(this, config);
35710 this.menu = Roo.menu.MenuMgr.get(this.menu);
35713 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35716 * @cfg {String} text
35717 * The text to show on the menu item.
35721 * @cfg {String} HTML to render in menu
35722 * The text to show on the menu item (HTML version).
35726 * @cfg {String} icon
35727 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35731 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35733 itemCls : "x-menu-item",
35735 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35737 canActivate : true,
35739 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35742 // doc'd in BaseItem
35746 ctype: "Roo.menu.Item",
35749 onRender : function(container, position){
35750 var el = document.createElement("a");
35751 el.hideFocus = true;
35752 el.unselectable = "on";
35753 el.href = this.href || "#";
35754 if(this.hrefTarget){
35755 el.target = this.hrefTarget;
35757 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35759 var html = this.html.length ? this.html : String.format('{0}',this.text);
35761 el.innerHTML = String.format(
35762 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35763 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35765 Roo.menu.Item.superclass.onRender.call(this, container, position);
35769 * Sets the text to display in this menu item
35770 * @param {String} text The text to display
35771 * @param {Boolean} isHTML true to indicate text is pure html.
35773 setText : function(text, isHTML){
35781 var html = this.html.length ? this.html : String.format('{0}',this.text);
35783 this.el.update(String.format(
35784 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35785 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35786 this.parentMenu.autoWidth();
35791 handleClick : function(e){
35792 if(!this.href){ // if no link defined, stop the event automatically
35795 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35799 activate : function(autoExpand){
35800 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35810 shouldDeactivate : function(e){
35811 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35812 if(this.menu && this.menu.isVisible()){
35813 return !this.menu.getEl().getRegion().contains(e.getPoint());
35821 deactivate : function(){
35822 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35827 expandMenu : function(autoActivate){
35828 if(!this.disabled && this.menu){
35829 clearTimeout(this.hideTimer);
35830 delete this.hideTimer;
35831 if(!this.menu.isVisible() && !this.showTimer){
35832 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35833 }else if (this.menu.isVisible() && autoActivate){
35834 this.menu.tryActivate(0, 1);
35840 deferExpand : function(autoActivate){
35841 delete this.showTimer;
35842 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35844 this.menu.tryActivate(0, 1);
35849 hideMenu : function(){
35850 clearTimeout(this.showTimer);
35851 delete this.showTimer;
35852 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35853 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35858 deferHide : function(){
35859 delete this.hideTimer;
35864 * Ext JS Library 1.1.1
35865 * Copyright(c) 2006-2007, Ext JS, LLC.
35867 * Originally Released Under LGPL - original licence link has changed is not relivant.
35870 * <script type="text/javascript">
35874 * @class Roo.menu.CheckItem
35875 * @extends Roo.menu.Item
35876 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35878 * Creates a new CheckItem
35879 * @param {Object} config Configuration options
35881 Roo.menu.CheckItem = function(config){
35882 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35885 * @event beforecheckchange
35886 * Fires before the checked value is set, providing an opportunity to cancel if needed
35887 * @param {Roo.menu.CheckItem} this
35888 * @param {Boolean} checked The new checked value that will be set
35890 "beforecheckchange" : true,
35892 * @event checkchange
35893 * Fires after the checked value has been set
35894 * @param {Roo.menu.CheckItem} this
35895 * @param {Boolean} checked The checked value that was set
35897 "checkchange" : true
35899 if(this.checkHandler){
35900 this.on('checkchange', this.checkHandler, this.scope);
35903 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35905 * @cfg {String} group
35906 * All check items with the same group name will automatically be grouped into a single-select
35907 * radio button group (defaults to '')
35910 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35912 itemCls : "x-menu-item x-menu-check-item",
35914 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35916 groupClass : "x-menu-group-item",
35919 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35920 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35921 * initialized with checked = true will be rendered as checked.
35926 ctype: "Roo.menu.CheckItem",
35929 onRender : function(c){
35930 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35932 this.el.addClass(this.groupClass);
35934 Roo.menu.MenuMgr.registerCheckable(this);
35936 this.checked = false;
35937 this.setChecked(true, true);
35942 destroy : function(){
35944 Roo.menu.MenuMgr.unregisterCheckable(this);
35946 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35950 * Set the checked state of this item
35951 * @param {Boolean} checked The new checked value
35952 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35954 setChecked : function(state, suppressEvent){
35955 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35956 if(this.container){
35957 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35959 this.checked = state;
35960 if(suppressEvent !== true){
35961 this.fireEvent("checkchange", this, state);
35967 handleClick : function(e){
35968 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35969 this.setChecked(!this.checked);
35971 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35975 * Ext JS Library 1.1.1
35976 * Copyright(c) 2006-2007, Ext JS, LLC.
35978 * Originally Released Under LGPL - original licence link has changed is not relivant.
35981 * <script type="text/javascript">
35985 * @class Roo.menu.DateItem
35986 * @extends Roo.menu.Adapter
35987 * A menu item that wraps the {@link Roo.DatPicker} component.
35989 * Creates a new DateItem
35990 * @param {Object} config Configuration options
35992 Roo.menu.DateItem = function(config){
35993 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35994 /** The Roo.DatePicker object @type Roo.DatePicker */
35995 this.picker = this.component;
35996 this.addEvents({select: true});
35998 this.picker.on("render", function(picker){
35999 picker.getEl().swallowEvent("click");
36000 picker.container.addClass("x-menu-date-item");
36003 this.picker.on("select", this.onSelect, this);
36006 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36008 onSelect : function(picker, date){
36009 this.fireEvent("select", this, date, picker);
36010 Roo.menu.DateItem.superclass.handleClick.call(this);
36014 * Ext JS Library 1.1.1
36015 * Copyright(c) 2006-2007, Ext JS, LLC.
36017 * Originally Released Under LGPL - original licence link has changed is not relivant.
36020 * <script type="text/javascript">
36024 * @class Roo.menu.ColorItem
36025 * @extends Roo.menu.Adapter
36026 * A menu item that wraps the {@link Roo.ColorPalette} component.
36028 * Creates a new ColorItem
36029 * @param {Object} config Configuration options
36031 Roo.menu.ColorItem = function(config){
36032 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36033 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36034 this.palette = this.component;
36035 this.relayEvents(this.palette, ["select"]);
36036 if(this.selectHandler){
36037 this.on('select', this.selectHandler, this.scope);
36040 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36042 * Ext JS Library 1.1.1
36043 * Copyright(c) 2006-2007, Ext JS, LLC.
36045 * Originally Released Under LGPL - original licence link has changed is not relivant.
36048 * <script type="text/javascript">
36053 * @class Roo.menu.DateMenu
36054 * @extends Roo.menu.Menu
36055 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36057 * Creates a new DateMenu
36058 * @param {Object} config Configuration options
36060 Roo.menu.DateMenu = function(config){
36061 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36063 var di = new Roo.menu.DateItem(config);
36066 * The {@link Roo.DatePicker} instance for this DateMenu
36069 this.picker = di.picker;
36072 * @param {DatePicker} picker
36073 * @param {Date} date
36075 this.relayEvents(di, ["select"]);
36076 this.on('beforeshow', function(){
36078 this.picker.hideMonthPicker(false);
36082 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36086 * Ext JS Library 1.1.1
36087 * Copyright(c) 2006-2007, Ext JS, LLC.
36089 * Originally Released Under LGPL - original licence link has changed is not relivant.
36092 * <script type="text/javascript">
36097 * @class Roo.menu.ColorMenu
36098 * @extends Roo.menu.Menu
36099 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36101 * Creates a new ColorMenu
36102 * @param {Object} config Configuration options
36104 Roo.menu.ColorMenu = function(config){
36105 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36107 var ci = new Roo.menu.ColorItem(config);
36110 * The {@link Roo.ColorPalette} instance for this ColorMenu
36111 * @type ColorPalette
36113 this.palette = ci.palette;
36116 * @param {ColorPalette} palette
36117 * @param {String} color
36119 this.relayEvents(ci, ["select"]);
36121 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36123 * Ext JS Library 1.1.1
36124 * Copyright(c) 2006-2007, Ext JS, LLC.
36126 * Originally Released Under LGPL - original licence link has changed is not relivant.
36129 * <script type="text/javascript">
36133 * @class Roo.form.Field
36134 * @extends Roo.BoxComponent
36135 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36137 * Creates a new Field
36138 * @param {Object} config Configuration options
36140 Roo.form.Field = function(config){
36141 Roo.form.Field.superclass.constructor.call(this, config);
36144 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36146 * @cfg {String} fieldLabel Label to use when rendering a form.
36149 * @cfg {String} qtip Mouse over tip
36153 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36155 invalidClass : "x-form-invalid",
36157 * @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")
36159 invalidText : "The value in this field is invalid",
36161 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36163 focusClass : "x-form-focus",
36165 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36166 automatic validation (defaults to "keyup").
36168 validationEvent : "keyup",
36170 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36172 validateOnBlur : true,
36174 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36176 validationDelay : 250,
36178 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36179 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36181 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36183 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36185 fieldClass : "x-form-field",
36187 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36190 ----------- ----------------------------------------------------------------------
36191 qtip Display a quick tip when the user hovers over the field
36192 title Display a default browser title attribute popup
36193 under Add a block div beneath the field containing the error text
36194 side Add an error icon to the right of the field with a popup on hover
36195 [element id] Add the error text directly to the innerHTML of the specified element
36198 msgTarget : 'qtip',
36200 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36205 * @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.
36210 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36215 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36217 inputType : undefined,
36220 * @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).
36222 tabIndex : undefined,
36225 isFormField : true,
36230 * @property {Roo.Element} fieldEl
36231 * Element Containing the rendered Field (with label etc.)
36234 * @cfg {Mixed} value A value to initialize this field with.
36239 * @cfg {String} name The field's HTML name attribute.
36242 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36246 initComponent : function(){
36247 Roo.form.Field.superclass.initComponent.call(this);
36251 * Fires when this field receives input focus.
36252 * @param {Roo.form.Field} this
36257 * Fires when this field loses input focus.
36258 * @param {Roo.form.Field} this
36262 * @event specialkey
36263 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36264 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36265 * @param {Roo.form.Field} this
36266 * @param {Roo.EventObject} e The event object
36271 * Fires just before the field blurs if the field value has changed.
36272 * @param {Roo.form.Field} this
36273 * @param {Mixed} newValue The new value
36274 * @param {Mixed} oldValue The original value
36279 * Fires after the field has been marked as invalid.
36280 * @param {Roo.form.Field} this
36281 * @param {String} msg The validation message
36286 * Fires after the field has been validated with no errors.
36287 * @param {Roo.form.Field} this
36292 * Fires after the key up
36293 * @param {Roo.form.Field} this
36294 * @param {Roo.EventObject} e The event Object
36301 * Returns the name attribute of the field if available
36302 * @return {String} name The field name
36304 getName: function(){
36305 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36309 onRender : function(ct, position){
36310 Roo.form.Field.superclass.onRender.call(this, ct, position);
36312 var cfg = this.getAutoCreate();
36314 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36316 if (!cfg.name.length) {
36319 if(this.inputType){
36320 cfg.type = this.inputType;
36322 this.el = ct.createChild(cfg, position);
36324 var type = this.el.dom.type;
36326 if(type == 'password'){
36329 this.el.addClass('x-form-'+type);
36332 this.el.dom.readOnly = true;
36334 if(this.tabIndex !== undefined){
36335 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36338 this.el.addClass([this.fieldClass, this.cls]);
36343 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36344 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36345 * @return {Roo.form.Field} this
36347 applyTo : function(target){
36348 this.allowDomMove = false;
36349 this.el = Roo.get(target);
36350 this.render(this.el.dom.parentNode);
36355 initValue : function(){
36356 if(this.value !== undefined){
36357 this.setValue(this.value);
36358 }else if(this.el.dom.value.length > 0){
36359 this.setValue(this.el.dom.value);
36364 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36366 isDirty : function() {
36367 if(this.disabled) {
36370 return String(this.getValue()) !== String(this.originalValue);
36374 afterRender : function(){
36375 Roo.form.Field.superclass.afterRender.call(this);
36380 fireKey : function(e){
36381 //Roo.log('field ' + e.getKey());
36382 if(e.isNavKeyPress()){
36383 this.fireEvent("specialkey", this, e);
36388 * Resets the current field value to the originally loaded value and clears any validation messages
36390 reset : function(){
36391 this.setValue(this.originalValue);
36392 this.clearInvalid();
36396 initEvents : function(){
36397 // safari killled keypress - so keydown is now used..
36398 this.el.on("keydown" , this.fireKey, this);
36399 this.el.on("focus", this.onFocus, this);
36400 this.el.on("blur", this.onBlur, this);
36401 this.el.relayEvent('keyup', this);
36403 // reference to original value for reset
36404 this.originalValue = this.getValue();
36408 onFocus : function(){
36409 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36410 this.el.addClass(this.focusClass);
36412 if(!this.hasFocus){
36413 this.hasFocus = true;
36414 this.startValue = this.getValue();
36415 this.fireEvent("focus", this);
36419 beforeBlur : Roo.emptyFn,
36422 onBlur : function(){
36424 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36425 this.el.removeClass(this.focusClass);
36427 this.hasFocus = false;
36428 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36431 var v = this.getValue();
36432 if(String(v) !== String(this.startValue)){
36433 this.fireEvent('change', this, v, this.startValue);
36435 this.fireEvent("blur", this);
36439 * Returns whether or not the field value is currently valid
36440 * @param {Boolean} preventMark True to disable marking the field invalid
36441 * @return {Boolean} True if the value is valid, else false
36443 isValid : function(preventMark){
36447 var restore = this.preventMark;
36448 this.preventMark = preventMark === true;
36449 var v = this.validateValue(this.processValue(this.getRawValue()));
36450 this.preventMark = restore;
36455 * Validates the field value
36456 * @return {Boolean} True if the value is valid, else false
36458 validate : function(){
36459 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36460 this.clearInvalid();
36466 processValue : function(value){
36471 // Subclasses should provide the validation implementation by overriding this
36472 validateValue : function(value){
36477 * Mark this field as invalid
36478 * @param {String} msg The validation message
36480 markInvalid : function(msg){
36481 if(!this.rendered || this.preventMark){ // not rendered
36484 this.el.addClass(this.invalidClass);
36485 msg = msg || this.invalidText;
36486 switch(this.msgTarget){
36488 this.el.dom.qtip = msg;
36489 this.el.dom.qclass = 'x-form-invalid-tip';
36490 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36491 Roo.QuickTips.enable();
36495 this.el.dom.title = msg;
36499 var elp = this.el.findParent('.x-form-element', 5, true);
36500 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36501 this.errorEl.setWidth(elp.getWidth(true)-20);
36503 this.errorEl.update(msg);
36504 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36507 if(!this.errorIcon){
36508 var elp = this.el.findParent('.x-form-element', 5, true);
36509 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36511 this.alignErrorIcon();
36512 this.errorIcon.dom.qtip = msg;
36513 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36514 this.errorIcon.show();
36515 this.on('resize', this.alignErrorIcon, this);
36518 var t = Roo.getDom(this.msgTarget);
36520 t.style.display = this.msgDisplay;
36523 this.fireEvent('invalid', this, msg);
36527 alignErrorIcon : function(){
36528 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36532 * Clear any invalid styles/messages for this field
36534 clearInvalid : function(){
36535 if(!this.rendered || this.preventMark){ // not rendered
36538 this.el.removeClass(this.invalidClass);
36539 switch(this.msgTarget){
36541 this.el.dom.qtip = '';
36544 this.el.dom.title = '';
36548 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36552 if(this.errorIcon){
36553 this.errorIcon.dom.qtip = '';
36554 this.errorIcon.hide();
36555 this.un('resize', this.alignErrorIcon, this);
36559 var t = Roo.getDom(this.msgTarget);
36561 t.style.display = 'none';
36564 this.fireEvent('valid', this);
36568 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36569 * @return {Mixed} value The field value
36571 getRawValue : function(){
36572 var v = this.el.getValue();
36578 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36579 * @return {Mixed} value The field value
36581 getValue : function(){
36582 var v = this.el.getValue();
36588 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36589 * @param {Mixed} value The value to set
36591 setRawValue : function(v){
36592 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36596 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36597 * @param {Mixed} value The value to set
36599 setValue : function(v){
36602 this.el.dom.value = (v === null || v === undefined ? '' : v);
36607 adjustSize : function(w, h){
36608 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36609 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36613 adjustWidth : function(tag, w){
36614 tag = tag.toLowerCase();
36615 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36616 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36617 if(tag == 'input'){
36620 if(tag = 'textarea'){
36623 }else if(Roo.isOpera){
36624 if(tag == 'input'){
36627 if(tag = 'textarea'){
36637 // anything other than normal should be considered experimental
36638 Roo.form.Field.msgFx = {
36640 show: function(msgEl, f){
36641 msgEl.setDisplayed('block');
36644 hide : function(msgEl, f){
36645 msgEl.setDisplayed(false).update('');
36650 show: function(msgEl, f){
36651 msgEl.slideIn('t', {stopFx:true});
36654 hide : function(msgEl, f){
36655 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36660 show: function(msgEl, f){
36661 msgEl.fixDisplay();
36662 msgEl.alignTo(f.el, 'tl-tr');
36663 msgEl.slideIn('l', {stopFx:true});
36666 hide : function(msgEl, f){
36667 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36672 * Ext JS Library 1.1.1
36673 * Copyright(c) 2006-2007, Ext JS, LLC.
36675 * Originally Released Under LGPL - original licence link has changed is not relivant.
36678 * <script type="text/javascript">
36683 * @class Roo.form.TextField
36684 * @extends Roo.form.Field
36685 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36686 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36688 * Creates a new TextField
36689 * @param {Object} config Configuration options
36691 Roo.form.TextField = function(config){
36692 Roo.form.TextField.superclass.constructor.call(this, config);
36696 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36697 * according to the default logic, but this event provides a hook for the developer to apply additional
36698 * logic at runtime to resize the field if needed.
36699 * @param {Roo.form.Field} this This text field
36700 * @param {Number} width The new field width
36706 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36708 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36712 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36716 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36720 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36724 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36728 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36730 disableKeyFilter : false,
36732 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36736 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36740 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36742 maxLength : Number.MAX_VALUE,
36744 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36746 minLengthText : "The minimum length for this field is {0}",
36748 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36750 maxLengthText : "The maximum length for this field is {0}",
36752 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36754 selectOnFocus : false,
36756 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36758 blankText : "This field is required",
36760 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36761 * If available, this function will be called only after the basic validators all return true, and will be passed the
36762 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36766 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36767 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36768 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36772 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36776 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
36782 initEvents : function()
36784 if (this.emptyText) {
36785 this.el.attr('placeholder', this.emptyText);
36788 Roo.form.TextField.superclass.initEvents.call(this);
36789 if(this.validationEvent == 'keyup'){
36790 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36791 this.el.on('keyup', this.filterValidation, this);
36793 else if(this.validationEvent !== false){
36794 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36797 if(this.selectOnFocus){
36798 this.on("focus", this.preFocus, this);
36801 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36802 this.el.on("keypress", this.filterKeys, this);
36805 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36806 this.el.on("click", this.autoSize, this);
36808 if(this.el.is('input[type=password]') && Roo.isSafari){
36809 this.el.on('keydown', this.SafariOnKeyDown, this);
36813 processValue : function(value){
36814 if(this.stripCharsRe){
36815 var newValue = value.replace(this.stripCharsRe, '');
36816 if(newValue !== value){
36817 this.setRawValue(newValue);
36824 filterValidation : function(e){
36825 if(!e.isNavKeyPress()){
36826 this.validationTask.delay(this.validationDelay);
36831 onKeyUp : function(e){
36832 if(!e.isNavKeyPress()){
36838 * Resets the current field value to the originally-loaded value and clears any validation messages.
36841 reset : function(){
36842 Roo.form.TextField.superclass.reset.call(this);
36848 preFocus : function(){
36850 if(this.selectOnFocus){
36851 this.el.dom.select();
36857 filterKeys : function(e){
36858 var k = e.getKey();
36859 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36862 var c = e.getCharCode(), cc = String.fromCharCode(c);
36863 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36866 if(!this.maskRe.test(cc)){
36871 setValue : function(v){
36873 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36879 * Validates a value according to the field's validation rules and marks the field as invalid
36880 * if the validation fails
36881 * @param {Mixed} value The value to validate
36882 * @return {Boolean} True if the value is valid, else false
36884 validateValue : function(value){
36885 if(value.length < 1) { // if it's blank
36886 if(this.allowBlank){
36887 this.clearInvalid();
36890 this.markInvalid(this.blankText);
36894 if(value.length < this.minLength){
36895 this.markInvalid(String.format(this.minLengthText, this.minLength));
36898 if(value.length > this.maxLength){
36899 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36903 var vt = Roo.form.VTypes;
36904 if(!vt[this.vtype](value, this)){
36905 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36909 if(typeof this.validator == "function"){
36910 var msg = this.validator(value);
36912 this.markInvalid(msg);
36916 if(this.regex && !this.regex.test(value)){
36917 this.markInvalid(this.regexText);
36924 * Selects text in this field
36925 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36926 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36928 selectText : function(start, end){
36929 var v = this.getRawValue();
36931 start = start === undefined ? 0 : start;
36932 end = end === undefined ? v.length : end;
36933 var d = this.el.dom;
36934 if(d.setSelectionRange){
36935 d.setSelectionRange(start, end);
36936 }else if(d.createTextRange){
36937 var range = d.createTextRange();
36938 range.moveStart("character", start);
36939 range.moveEnd("character", v.length-end);
36946 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36947 * This only takes effect if grow = true, and fires the autosize event.
36949 autoSize : function(){
36950 if(!this.grow || !this.rendered){
36954 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36957 var v = el.dom.value;
36958 var d = document.createElement('div');
36959 d.appendChild(document.createTextNode(v));
36963 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36964 this.el.setWidth(w);
36965 this.fireEvent("autosize", this, w);
36969 SafariOnKeyDown : function(event)
36971 // this is a workaround for a password hang bug on chrome/ webkit.
36973 var isSelectAll = false;
36975 if(this.el.dom.selectionEnd > 0){
36976 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
36978 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
36979 event.preventDefault();
36984 if(isSelectAll){ // backspace and delete key
36986 event.preventDefault();
36987 // this is very hacky as keydown always get's upper case.
36989 var cc = String.fromCharCode(event.getCharCode());
36990 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
36998 * Ext JS Library 1.1.1
36999 * Copyright(c) 2006-2007, Ext JS, LLC.
37001 * Originally Released Under LGPL - original licence link has changed is not relivant.
37004 * <script type="text/javascript">
37008 * @class Roo.form.Hidden
37009 * @extends Roo.form.TextField
37010 * Simple Hidden element used on forms
37012 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37015 * Creates a new Hidden form element.
37016 * @param {Object} config Configuration options
37021 // easy hidden field...
37022 Roo.form.Hidden = function(config){
37023 Roo.form.Hidden.superclass.constructor.call(this, config);
37026 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37028 inputType: 'hidden',
37031 labelSeparator: '',
37033 itemCls : 'x-form-item-display-none'
37041 * Ext JS Library 1.1.1
37042 * Copyright(c) 2006-2007, Ext JS, LLC.
37044 * Originally Released Under LGPL - original licence link has changed is not relivant.
37047 * <script type="text/javascript">
37051 * @class Roo.form.TriggerField
37052 * @extends Roo.form.TextField
37053 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37054 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37055 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37056 * for which you can provide a custom implementation. For example:
37058 var trigger = new Roo.form.TriggerField();
37059 trigger.onTriggerClick = myTriggerFn;
37060 trigger.applyTo('my-field');
37063 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37064 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37065 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37066 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37068 * Create a new TriggerField.
37069 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37070 * to the base TextField)
37072 Roo.form.TriggerField = function(config){
37073 this.mimicing = false;
37074 Roo.form.TriggerField.superclass.constructor.call(this, config);
37077 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37079 * @cfg {String} triggerClass A CSS class to apply to the trigger
37082 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37083 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37085 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37087 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37091 /** @cfg {Boolean} grow @hide */
37092 /** @cfg {Number} growMin @hide */
37093 /** @cfg {Number} growMax @hide */
37099 autoSize: Roo.emptyFn,
37103 deferHeight : true,
37106 actionMode : 'wrap',
37108 onResize : function(w, h){
37109 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37110 if(typeof w == 'number'){
37111 var x = w - this.trigger.getWidth();
37112 this.el.setWidth(this.adjustWidth('input', x));
37113 this.trigger.setStyle('left', x+'px');
37118 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37121 getResizeEl : function(){
37126 getPositionEl : function(){
37131 alignErrorIcon : function(){
37132 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37136 onRender : function(ct, position){
37137 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37138 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37139 this.trigger = this.wrap.createChild(this.triggerConfig ||
37140 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37141 if(this.hideTrigger){
37142 this.trigger.setDisplayed(false);
37144 this.initTrigger();
37146 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37151 initTrigger : function(){
37152 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37153 this.trigger.addClassOnOver('x-form-trigger-over');
37154 this.trigger.addClassOnClick('x-form-trigger-click');
37158 onDestroy : function(){
37160 this.trigger.removeAllListeners();
37161 this.trigger.remove();
37164 this.wrap.remove();
37166 Roo.form.TriggerField.superclass.onDestroy.call(this);
37170 onFocus : function(){
37171 Roo.form.TriggerField.superclass.onFocus.call(this);
37172 if(!this.mimicing){
37173 this.wrap.addClass('x-trigger-wrap-focus');
37174 this.mimicing = true;
37175 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37176 if(this.monitorTab){
37177 this.el.on("keydown", this.checkTab, this);
37183 checkTab : function(e){
37184 if(e.getKey() == e.TAB){
37185 this.triggerBlur();
37190 onBlur : function(){
37195 mimicBlur : function(e, t){
37196 if(!this.wrap.contains(t) && this.validateBlur()){
37197 this.triggerBlur();
37202 triggerBlur : function(){
37203 this.mimicing = false;
37204 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37205 if(this.monitorTab){
37206 this.el.un("keydown", this.checkTab, this);
37208 this.wrap.removeClass('x-trigger-wrap-focus');
37209 Roo.form.TriggerField.superclass.onBlur.call(this);
37213 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37214 validateBlur : function(e, t){
37219 onDisable : function(){
37220 Roo.form.TriggerField.superclass.onDisable.call(this);
37222 this.wrap.addClass('x-item-disabled');
37227 onEnable : function(){
37228 Roo.form.TriggerField.superclass.onEnable.call(this);
37230 this.wrap.removeClass('x-item-disabled');
37235 onShow : function(){
37236 var ae = this.getActionEl();
37239 ae.dom.style.display = '';
37240 ae.dom.style.visibility = 'visible';
37246 onHide : function(){
37247 var ae = this.getActionEl();
37248 ae.dom.style.display = 'none';
37252 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37253 * by an implementing function.
37255 * @param {EventObject} e
37257 onTriggerClick : Roo.emptyFn
37260 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37261 // to be extended by an implementing class. For an example of implementing this class, see the custom
37262 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37263 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37264 initComponent : function(){
37265 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37267 this.triggerConfig = {
37268 tag:'span', cls:'x-form-twin-triggers', cn:[
37269 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37270 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37274 getTrigger : function(index){
37275 return this.triggers[index];
37278 initTrigger : function(){
37279 var ts = this.trigger.select('.x-form-trigger', true);
37280 this.wrap.setStyle('overflow', 'hidden');
37281 var triggerField = this;
37282 ts.each(function(t, all, index){
37283 t.hide = function(){
37284 var w = triggerField.wrap.getWidth();
37285 this.dom.style.display = 'none';
37286 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37288 t.show = function(){
37289 var w = triggerField.wrap.getWidth();
37290 this.dom.style.display = '';
37291 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37293 var triggerIndex = 'Trigger'+(index+1);
37295 if(this['hide'+triggerIndex]){
37296 t.dom.style.display = 'none';
37298 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37299 t.addClassOnOver('x-form-trigger-over');
37300 t.addClassOnClick('x-form-trigger-click');
37302 this.triggers = ts.elements;
37305 onTrigger1Click : Roo.emptyFn,
37306 onTrigger2Click : Roo.emptyFn
37309 * Ext JS Library 1.1.1
37310 * Copyright(c) 2006-2007, Ext JS, LLC.
37312 * Originally Released Under LGPL - original licence link has changed is not relivant.
37315 * <script type="text/javascript">
37319 * @class Roo.form.TextArea
37320 * @extends Roo.form.TextField
37321 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37322 * support for auto-sizing.
37324 * Creates a new TextArea
37325 * @param {Object} config Configuration options
37327 Roo.form.TextArea = function(config){
37328 Roo.form.TextArea.superclass.constructor.call(this, config);
37329 // these are provided exchanges for backwards compat
37330 // minHeight/maxHeight were replaced by growMin/growMax to be
37331 // compatible with TextField growing config values
37332 if(this.minHeight !== undefined){
37333 this.growMin = this.minHeight;
37335 if(this.maxHeight !== undefined){
37336 this.growMax = this.maxHeight;
37340 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37342 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37346 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37350 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37351 * in the field (equivalent to setting overflow: hidden, defaults to false)
37353 preventScrollbars: false,
37355 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37356 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37360 onRender : function(ct, position){
37362 this.defaultAutoCreate = {
37364 style:"width:300px;height:60px;",
37365 autocomplete: "off"
37368 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37370 this.textSizeEl = Roo.DomHelper.append(document.body, {
37371 tag: "pre", cls: "x-form-grow-sizer"
37373 if(this.preventScrollbars){
37374 this.el.setStyle("overflow", "hidden");
37376 this.el.setHeight(this.growMin);
37380 onDestroy : function(){
37381 if(this.textSizeEl){
37382 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37384 Roo.form.TextArea.superclass.onDestroy.call(this);
37388 onKeyUp : function(e){
37389 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37395 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37396 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37398 autoSize : function(){
37399 if(!this.grow || !this.textSizeEl){
37403 var v = el.dom.value;
37404 var ts = this.textSizeEl;
37407 ts.appendChild(document.createTextNode(v));
37410 Roo.fly(ts).setWidth(this.el.getWidth());
37412 v = "  ";
37415 v = v.replace(/\n/g, '<p> </p>');
37417 v += " \n ";
37420 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37421 if(h != this.lastHeight){
37422 this.lastHeight = h;
37423 this.el.setHeight(h);
37424 this.fireEvent("autosize", this, h);
37429 * Ext JS Library 1.1.1
37430 * Copyright(c) 2006-2007, Ext JS, LLC.
37432 * Originally Released Under LGPL - original licence link has changed is not relivant.
37435 * <script type="text/javascript">
37440 * @class Roo.form.NumberField
37441 * @extends Roo.form.TextField
37442 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37444 * Creates a new NumberField
37445 * @param {Object} config Configuration options
37447 Roo.form.NumberField = function(config){
37448 Roo.form.NumberField.superclass.constructor.call(this, config);
37451 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37453 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37455 fieldClass: "x-form-field x-form-num-field",
37457 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37459 allowDecimals : true,
37461 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37463 decimalSeparator : ".",
37465 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37467 decimalPrecision : 2,
37469 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37471 allowNegative : true,
37473 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37475 minValue : Number.NEGATIVE_INFINITY,
37477 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37479 maxValue : Number.MAX_VALUE,
37481 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37483 minText : "The minimum value for this field is {0}",
37485 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37487 maxText : "The maximum value for this field is {0}",
37489 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37490 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37492 nanText : "{0} is not a valid number",
37495 initEvents : function(){
37496 Roo.form.NumberField.superclass.initEvents.call(this);
37497 var allowed = "0123456789";
37498 if(this.allowDecimals){
37499 allowed += this.decimalSeparator;
37501 if(this.allowNegative){
37504 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37505 var keyPress = function(e){
37506 var k = e.getKey();
37507 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37510 var c = e.getCharCode();
37511 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37515 this.el.on("keypress", keyPress, this);
37519 validateValue : function(value){
37520 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37523 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37526 var num = this.parseValue(value);
37528 this.markInvalid(String.format(this.nanText, value));
37531 if(num < this.minValue){
37532 this.markInvalid(String.format(this.minText, this.minValue));
37535 if(num > this.maxValue){
37536 this.markInvalid(String.format(this.maxText, this.maxValue));
37542 getValue : function(){
37543 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37547 parseValue : function(value){
37548 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37549 return isNaN(value) ? '' : value;
37553 fixPrecision : function(value){
37554 var nan = isNaN(value);
37555 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37556 return nan ? '' : value;
37558 return parseFloat(value).toFixed(this.decimalPrecision);
37561 setValue : function(v){
37562 v = this.fixPrecision(v);
37563 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37567 decimalPrecisionFcn : function(v){
37568 return Math.floor(v);
37571 beforeBlur : function(){
37572 var v = this.parseValue(this.getRawValue());
37579 * Ext JS Library 1.1.1
37580 * Copyright(c) 2006-2007, Ext JS, LLC.
37582 * Originally Released Under LGPL - original licence link has changed is not relivant.
37585 * <script type="text/javascript">
37589 * @class Roo.form.DateField
37590 * @extends Roo.form.TriggerField
37591 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37593 * Create a new DateField
37594 * @param {Object} config
37596 Roo.form.DateField = function(config){
37597 Roo.form.DateField.superclass.constructor.call(this, config);
37603 * Fires when a date is selected
37604 * @param {Roo.form.DateField} combo This combo box
37605 * @param {Date} date The date selected
37612 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37613 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37614 this.ddMatch = null;
37615 if(this.disabledDates){
37616 var dd = this.disabledDates;
37618 for(var i = 0; i < dd.length; i++){
37620 if(i != dd.length-1) re += "|";
37622 this.ddMatch = new RegExp(re + ")");
37626 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37628 * @cfg {String} format
37629 * The default date format string which can be overriden for localization support. The format must be
37630 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37634 * @cfg {String} altFormats
37635 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37636 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37638 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37640 * @cfg {Array} disabledDays
37641 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37643 disabledDays : null,
37645 * @cfg {String} disabledDaysText
37646 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37648 disabledDaysText : "Disabled",
37650 * @cfg {Array} disabledDates
37651 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37652 * expression so they are very powerful. Some examples:
37654 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37655 * <li>["03/08", "09/16"] would disable those days for every year</li>
37656 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37657 * <li>["03/../2006"] would disable every day in March 2006</li>
37658 * <li>["^03"] would disable every day in every March</li>
37660 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37661 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37663 disabledDates : null,
37665 * @cfg {String} disabledDatesText
37666 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37668 disabledDatesText : "Disabled",
37670 * @cfg {Date/String} minValue
37671 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37672 * valid format (defaults to null).
37676 * @cfg {Date/String} maxValue
37677 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37678 * valid format (defaults to null).
37682 * @cfg {String} minText
37683 * The error text to display when the date in the cell is before minValue (defaults to
37684 * 'The date in this field must be after {minValue}').
37686 minText : "The date in this field must be equal to or after {0}",
37688 * @cfg {String} maxText
37689 * The error text to display when the date in the cell is after maxValue (defaults to
37690 * 'The date in this field must be before {maxValue}').
37692 maxText : "The date in this field must be equal to or before {0}",
37694 * @cfg {String} invalidText
37695 * The error text to display when the date in the field is invalid (defaults to
37696 * '{value} is not a valid date - it must be in the format {format}').
37698 invalidText : "{0} is not a valid date - it must be in the format {1}",
37700 * @cfg {String} triggerClass
37701 * An additional CSS class used to style the trigger button. The trigger will always get the
37702 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37703 * which displays a calendar icon).
37705 triggerClass : 'x-form-date-trigger',
37709 * @cfg {Boolean} useIso
37710 * if enabled, then the date field will use a hidden field to store the
37711 * real value as iso formated date. default (false)
37715 * @cfg {String/Object} autoCreate
37716 * A DomHelper element spec, or true for a default element spec (defaults to
37717 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37720 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37723 hiddenField: false,
37725 onRender : function(ct, position)
37727 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37729 //this.el.dom.removeAttribute('name');
37730 Roo.log("Changing name?");
37731 this.el.dom.setAttribute('name', this.name + '____hidden___' );
37732 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37734 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37735 // prevent input submission
37736 this.hiddenName = this.name;
37743 validateValue : function(value)
37745 value = this.formatDate(value);
37746 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37747 Roo.log('super failed');
37750 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37753 var svalue = value;
37754 value = this.parseDate(value);
37756 Roo.log('parse date failed' + svalue);
37757 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37760 var time = value.getTime();
37761 if(this.minValue && time < this.minValue.getTime()){
37762 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37765 if(this.maxValue && time > this.maxValue.getTime()){
37766 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37769 if(this.disabledDays){
37770 var day = value.getDay();
37771 for(var i = 0; i < this.disabledDays.length; i++) {
37772 if(day === this.disabledDays[i]){
37773 this.markInvalid(this.disabledDaysText);
37778 var fvalue = this.formatDate(value);
37779 if(this.ddMatch && this.ddMatch.test(fvalue)){
37780 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37787 // Provides logic to override the default TriggerField.validateBlur which just returns true
37788 validateBlur : function(){
37789 return !this.menu || !this.menu.isVisible();
37792 getName: function()
37794 // returns hidden if it's set..
37795 if (!this.rendered) {return ''};
37796 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37801 * Returns the current date value of the date field.
37802 * @return {Date} The date value
37804 getValue : function(){
37806 return this.hiddenField ?
37807 this.hiddenField.value :
37808 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37812 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37813 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37814 * (the default format used is "m/d/y").
37817 //All of these calls set the same date value (May 4, 2006)
37819 //Pass a date object:
37820 var dt = new Date('5/4/06');
37821 dateField.setValue(dt);
37823 //Pass a date string (default format):
37824 dateField.setValue('5/4/06');
37826 //Pass a date string (custom format):
37827 dateField.format = 'Y-m-d';
37828 dateField.setValue('2006-5-4');
37830 * @param {String/Date} date The date or valid date string
37832 setValue : function(date){
37833 if (this.hiddenField) {
37834 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37836 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37837 // make sure the value field is always stored as a date..
37838 this.value = this.parseDate(date);
37844 parseDate : function(value){
37845 if(!value || value instanceof Date){
37848 var v = Date.parseDate(value, this.format);
37849 if (!v && this.useIso) {
37850 v = Date.parseDate(value, 'Y-m-d');
37852 if(!v && this.altFormats){
37853 if(!this.altFormatsArray){
37854 this.altFormatsArray = this.altFormats.split("|");
37856 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37857 v = Date.parseDate(value, this.altFormatsArray[i]);
37864 formatDate : function(date, fmt){
37865 return (!date || !(date instanceof Date)) ?
37866 date : date.dateFormat(fmt || this.format);
37871 select: function(m, d){
37874 this.fireEvent('select', this, d);
37876 show : function(){ // retain focus styling
37880 this.focus.defer(10, this);
37881 var ml = this.menuListeners;
37882 this.menu.un("select", ml.select, this);
37883 this.menu.un("show", ml.show, this);
37884 this.menu.un("hide", ml.hide, this);
37889 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37890 onTriggerClick : function(){
37894 if(this.menu == null){
37895 this.menu = new Roo.menu.DateMenu();
37897 Roo.apply(this.menu.picker, {
37898 showClear: this.allowBlank,
37899 minDate : this.minValue,
37900 maxDate : this.maxValue,
37901 disabledDatesRE : this.ddMatch,
37902 disabledDatesText : this.disabledDatesText,
37903 disabledDays : this.disabledDays,
37904 disabledDaysText : this.disabledDaysText,
37905 format : this.useIso ? 'Y-m-d' : this.format,
37906 minText : String.format(this.minText, this.formatDate(this.minValue)),
37907 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37909 this.menu.on(Roo.apply({}, this.menuListeners, {
37912 this.menu.picker.setValue(this.getValue() || new Date());
37913 this.menu.show(this.el, "tl-bl?");
37916 beforeBlur : function(){
37917 var v = this.parseDate(this.getRawValue());
37923 /** @cfg {Boolean} grow @hide */
37924 /** @cfg {Number} growMin @hide */
37925 /** @cfg {Number} growMax @hide */
37932 * Ext JS Library 1.1.1
37933 * Copyright(c) 2006-2007, Ext JS, LLC.
37935 * Originally Released Under LGPL - original licence link has changed is not relivant.
37938 * <script type="text/javascript">
37942 * @class Roo.form.MonthField
37943 * @extends Roo.form.TriggerField
37944 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37946 * Create a new MonthField
37947 * @param {Object} config
37949 Roo.form.MonthField = function(config){
37951 Roo.form.MonthField.superclass.constructor.call(this, config);
37957 * Fires when a date is selected
37958 * @param {Roo.form.MonthFieeld} combo This combo box
37959 * @param {Date} date The date selected
37966 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37967 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37968 this.ddMatch = null;
37969 if(this.disabledDates){
37970 var dd = this.disabledDates;
37972 for(var i = 0; i < dd.length; i++){
37974 if(i != dd.length-1) re += "|";
37976 this.ddMatch = new RegExp(re + ")");
37980 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
37982 * @cfg {String} format
37983 * The default date format string which can be overriden for localization support. The format must be
37984 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37988 * @cfg {String} altFormats
37989 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37990 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37992 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
37994 * @cfg {Array} disabledDays
37995 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37997 disabledDays : [0,1,2,3,4,5,6],
37999 * @cfg {String} disabledDaysText
38000 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38002 disabledDaysText : "Disabled",
38004 * @cfg {Array} disabledDates
38005 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38006 * expression so they are very powerful. Some examples:
38008 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38009 * <li>["03/08", "09/16"] would disable those days for every year</li>
38010 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38011 * <li>["03/../2006"] would disable every day in March 2006</li>
38012 * <li>["^03"] would disable every day in every March</li>
38014 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38015 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38017 disabledDates : null,
38019 * @cfg {String} disabledDatesText
38020 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38022 disabledDatesText : "Disabled",
38024 * @cfg {Date/String} minValue
38025 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38026 * valid format (defaults to null).
38030 * @cfg {Date/String} maxValue
38031 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38032 * valid format (defaults to null).
38036 * @cfg {String} minText
38037 * The error text to display when the date in the cell is before minValue (defaults to
38038 * 'The date in this field must be after {minValue}').
38040 minText : "The date in this field must be equal to or after {0}",
38042 * @cfg {String} maxTextf
38043 * The error text to display when the date in the cell is after maxValue (defaults to
38044 * 'The date in this field must be before {maxValue}').
38046 maxText : "The date in this field must be equal to or before {0}",
38048 * @cfg {String} invalidText
38049 * The error text to display when the date in the field is invalid (defaults to
38050 * '{value} is not a valid date - it must be in the format {format}').
38052 invalidText : "{0} is not a valid date - it must be in the format {1}",
38054 * @cfg {String} triggerClass
38055 * An additional CSS class used to style the trigger button. The trigger will always get the
38056 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38057 * which displays a calendar icon).
38059 triggerClass : 'x-form-date-trigger',
38063 * @cfg {Boolean} useIso
38064 * if enabled, then the date field will use a hidden field to store the
38065 * real value as iso formated date. default (true)
38069 * @cfg {String/Object} autoCreate
38070 * A DomHelper element spec, or true for a default element spec (defaults to
38071 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38074 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38077 hiddenField: false,
38079 hideMonthPicker : false,
38081 onRender : function(ct, position)
38083 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38085 this.el.dom.removeAttribute('name');
38086 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38088 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38089 // prevent input submission
38090 this.hiddenName = this.name;
38097 validateValue : function(value)
38099 value = this.formatDate(value);
38100 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38103 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38106 var svalue = value;
38107 value = this.parseDate(value);
38109 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38112 var time = value.getTime();
38113 if(this.minValue && time < this.minValue.getTime()){
38114 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38117 if(this.maxValue && time > this.maxValue.getTime()){
38118 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38121 /*if(this.disabledDays){
38122 var day = value.getDay();
38123 for(var i = 0; i < this.disabledDays.length; i++) {
38124 if(day === this.disabledDays[i]){
38125 this.markInvalid(this.disabledDaysText);
38131 var fvalue = this.formatDate(value);
38132 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38133 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38141 // Provides logic to override the default TriggerField.validateBlur which just returns true
38142 validateBlur : function(){
38143 return !this.menu || !this.menu.isVisible();
38147 * Returns the current date value of the date field.
38148 * @return {Date} The date value
38150 getValue : function(){
38154 return this.hiddenField ?
38155 this.hiddenField.value :
38156 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38160 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38161 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38162 * (the default format used is "m/d/y").
38165 //All of these calls set the same date value (May 4, 2006)
38167 //Pass a date object:
38168 var dt = new Date('5/4/06');
38169 monthField.setValue(dt);
38171 //Pass a date string (default format):
38172 monthField.setValue('5/4/06');
38174 //Pass a date string (custom format):
38175 monthField.format = 'Y-m-d';
38176 monthField.setValue('2006-5-4');
38178 * @param {String/Date} date The date or valid date string
38180 setValue : function(date){
38181 Roo.log('month setValue' + date);
38182 // can only be first of month..
38184 var val = this.parseDate(date);
38186 if (this.hiddenField) {
38187 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38189 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38190 this.value = this.parseDate(date);
38194 parseDate : function(value){
38195 if(!value || value instanceof Date){
38196 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38199 var v = Date.parseDate(value, this.format);
38200 if (!v && this.useIso) {
38201 v = Date.parseDate(value, 'Y-m-d');
38205 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38209 if(!v && this.altFormats){
38210 if(!this.altFormatsArray){
38211 this.altFormatsArray = this.altFormats.split("|");
38213 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38214 v = Date.parseDate(value, this.altFormatsArray[i]);
38221 formatDate : function(date, fmt){
38222 return (!date || !(date instanceof Date)) ?
38223 date : date.dateFormat(fmt || this.format);
38228 select: function(m, d){
38230 this.fireEvent('select', this, d);
38232 show : function(){ // retain focus styling
38236 this.focus.defer(10, this);
38237 var ml = this.menuListeners;
38238 this.menu.un("select", ml.select, this);
38239 this.menu.un("show", ml.show, this);
38240 this.menu.un("hide", ml.hide, this);
38244 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38245 onTriggerClick : function(){
38249 if(this.menu == null){
38250 this.menu = new Roo.menu.DateMenu();
38254 Roo.apply(this.menu.picker, {
38256 showClear: this.allowBlank,
38257 minDate : this.minValue,
38258 maxDate : this.maxValue,
38259 disabledDatesRE : this.ddMatch,
38260 disabledDatesText : this.disabledDatesText,
38262 format : this.useIso ? 'Y-m-d' : this.format,
38263 minText : String.format(this.minText, this.formatDate(this.minValue)),
38264 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38267 this.menu.on(Roo.apply({}, this.menuListeners, {
38275 // hide month picker get's called when we called by 'before hide';
38277 var ignorehide = true;
38278 p.hideMonthPicker = function(disableAnim){
38282 if(this.monthPicker){
38283 Roo.log("hideMonthPicker called");
38284 if(disableAnim === true){
38285 this.monthPicker.hide();
38287 this.monthPicker.slideOut('t', {duration:.2});
38288 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38289 p.fireEvent("select", this, this.value);
38295 Roo.log('picker set value');
38296 Roo.log(this.getValue());
38297 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38298 m.show(this.el, 'tl-bl?');
38299 ignorehide = false;
38300 // this will trigger hideMonthPicker..
38303 // hidden the day picker
38304 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38310 p.showMonthPicker.defer(100, p);
38316 beforeBlur : function(){
38317 var v = this.parseDate(this.getRawValue());
38323 /** @cfg {Boolean} grow @hide */
38324 /** @cfg {Number} growMin @hide */
38325 /** @cfg {Number} growMax @hide */
38332 * Ext JS Library 1.1.1
38333 * Copyright(c) 2006-2007, Ext JS, LLC.
38335 * Originally Released Under LGPL - original licence link has changed is not relivant.
38338 * <script type="text/javascript">
38343 * @class Roo.form.ComboBox
38344 * @extends Roo.form.TriggerField
38345 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38347 * Create a new ComboBox.
38348 * @param {Object} config Configuration options
38350 Roo.form.ComboBox = function(config){
38351 Roo.form.ComboBox.superclass.constructor.call(this, config);
38355 * Fires when the dropdown list is expanded
38356 * @param {Roo.form.ComboBox} combo This combo box
38361 * Fires when the dropdown list is collapsed
38362 * @param {Roo.form.ComboBox} combo This combo box
38366 * @event beforeselect
38367 * Fires before a list item is selected. Return false to cancel the selection.
38368 * @param {Roo.form.ComboBox} combo This combo box
38369 * @param {Roo.data.Record} record The data record returned from the underlying store
38370 * @param {Number} index The index of the selected item in the dropdown list
38372 'beforeselect' : true,
38375 * Fires when a list item is selected
38376 * @param {Roo.form.ComboBox} combo This combo box
38377 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
38378 * @param {Number} index The index of the selected item in the dropdown list
38382 * @event beforequery
38383 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
38384 * The event object passed has these properties:
38385 * @param {Roo.form.ComboBox} combo This combo box
38386 * @param {String} query The query
38387 * @param {Boolean} forceAll true to force "all" query
38388 * @param {Boolean} cancel true to cancel the query
38389 * @param {Object} e The query event object
38391 'beforequery': true,
38394 * Fires when the 'add' icon is pressed (add a listener to enable add button)
38395 * @param {Roo.form.ComboBox} combo This combo box
38400 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
38401 * @param {Roo.form.ComboBox} combo This combo box
38402 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
38408 if(this.transform){
38409 this.allowDomMove = false;
38410 var s = Roo.getDom(this.transform);
38411 if(!this.hiddenName){
38412 this.hiddenName = s.name;
38415 this.mode = 'local';
38416 var d = [], opts = s.options;
38417 for(var i = 0, len = opts.length;i < len; i++){
38419 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
38421 this.value = value;
38423 d.push([value, o.text]);
38425 this.store = new Roo.data.SimpleStore({
38427 fields: ['value', 'text'],
38430 this.valueField = 'value';
38431 this.displayField = 'text';
38433 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
38434 if(!this.lazyRender){
38435 this.target = true;
38436 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
38437 s.parentNode.removeChild(s); // remove it
38438 this.render(this.el.parentNode);
38440 s.parentNode.removeChild(s); // remove it
38445 this.store = Roo.factory(this.store, Roo.data);
38448 this.selectedIndex = -1;
38449 if(this.mode == 'local'){
38450 if(config.queryDelay === undefined){
38451 this.queryDelay = 10;
38453 if(config.minChars === undefined){
38459 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38461 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38464 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38465 * rendering into an Roo.Editor, defaults to false)
38468 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38469 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38472 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38475 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38476 * the dropdown list (defaults to undefined, with no header element)
38480 * @cfg {String/Roo.Template} tpl The template to use to render the output
38484 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38486 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38488 listWidth: undefined,
38490 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38491 * mode = 'remote' or 'text' if mode = 'local')
38493 displayField: undefined,
38495 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38496 * mode = 'remote' or 'value' if mode = 'local').
38497 * Note: use of a valueField requires the user make a selection
38498 * in order for a value to be mapped.
38500 valueField: undefined,
38504 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38505 * field's data value (defaults to the underlying DOM element's name)
38507 hiddenName: undefined,
38509 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38513 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38515 selectedClass: 'x-combo-selected',
38517 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38518 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38519 * which displays a downward arrow icon).
38521 triggerClass : 'x-form-arrow-trigger',
38523 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38527 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38528 * anchor positions (defaults to 'tl-bl')
38530 listAlign: 'tl-bl?',
38532 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38536 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38537 * query specified by the allQuery config option (defaults to 'query')
38539 triggerAction: 'query',
38541 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38542 * (defaults to 4, does not apply if editable = false)
38546 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38547 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38551 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38552 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38556 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38557 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38561 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38562 * when editable = true (defaults to false)
38564 selectOnFocus:false,
38566 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38568 queryParam: 'query',
38570 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38571 * when mode = 'remote' (defaults to 'Loading...')
38573 loadingText: 'Loading...',
38575 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38579 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38583 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38584 * traditional select (defaults to true)
38588 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38592 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38596 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38597 * listWidth has a higher value)
38601 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38602 * allow the user to set arbitrary text into the field (defaults to false)
38604 forceSelection:false,
38606 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38607 * if typeAhead = true (defaults to 250)
38609 typeAheadDelay : 250,
38611 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38612 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38614 valueNotFoundText : undefined,
38616 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38618 blockFocus : false,
38621 * @cfg {Boolean} disableClear Disable showing of clear button.
38623 disableClear : false,
38625 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38627 alwaysQuery : false,
38633 // element that contains real text value.. (when hidden is used..)
38636 onRender : function(ct, position){
38637 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38638 if(this.hiddenName){
38639 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38641 this.hiddenField.value =
38642 this.hiddenValue !== undefined ? this.hiddenValue :
38643 this.value !== undefined ? this.value : '';
38645 // prevent input submission
38646 this.el.dom.removeAttribute('name');
38651 this.el.dom.setAttribute('autocomplete', 'off');
38654 var cls = 'x-combo-list';
38656 this.list = new Roo.Layer({
38657 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38660 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38661 this.list.setWidth(lw);
38662 this.list.swallowEvent('mousewheel');
38663 this.assetHeight = 0;
38666 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38667 this.assetHeight += this.header.getHeight();
38670 this.innerList = this.list.createChild({cls:cls+'-inner'});
38671 this.innerList.on('mouseover', this.onViewOver, this);
38672 this.innerList.on('mousemove', this.onViewMove, this);
38673 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38675 if(this.allowBlank && !this.pageSize && !this.disableClear){
38676 this.footer = this.list.createChild({cls:cls+'-ft'});
38677 this.pageTb = new Roo.Toolbar(this.footer);
38681 this.footer = this.list.createChild({cls:cls+'-ft'});
38682 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38683 {pageSize: this.pageSize});
38687 if (this.pageTb && this.allowBlank && !this.disableClear) {
38689 this.pageTb.add(new Roo.Toolbar.Fill(), {
38690 cls: 'x-btn-icon x-btn-clear',
38692 handler: function()
38695 _this.clearValue();
38696 _this.onSelect(false, -1);
38701 this.assetHeight += this.footer.getHeight();
38706 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38709 this.view = new Roo.View(this.innerList, this.tpl, {
38710 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38713 this.view.on('click', this.onViewClick, this);
38715 this.store.on('beforeload', this.onBeforeLoad, this);
38716 this.store.on('load', this.onLoad, this);
38717 this.store.on('loadexception', this.onLoadException, this);
38719 if(this.resizable){
38720 this.resizer = new Roo.Resizable(this.list, {
38721 pinned:true, handles:'se'
38723 this.resizer.on('resize', function(r, w, h){
38724 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38725 this.listWidth = w;
38726 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38727 this.restrictHeight();
38729 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38731 if(!this.editable){
38732 this.editable = true;
38733 this.setEditable(false);
38737 if (typeof(this.events.add.listeners) != 'undefined') {
38739 this.addicon = this.wrap.createChild(
38740 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38742 this.addicon.on('click', function(e) {
38743 this.fireEvent('add', this);
38746 if (typeof(this.events.edit.listeners) != 'undefined') {
38748 this.editicon = this.wrap.createChild(
38749 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38750 if (this.addicon) {
38751 this.editicon.setStyle('margin-left', '40px');
38753 this.editicon.on('click', function(e) {
38755 // we fire even if inothing is selected..
38756 this.fireEvent('edit', this, this.lastData );
38766 initEvents : function(){
38767 Roo.form.ComboBox.superclass.initEvents.call(this);
38769 this.keyNav = new Roo.KeyNav(this.el, {
38770 "up" : function(e){
38771 this.inKeyMode = true;
38775 "down" : function(e){
38776 if(!this.isExpanded()){
38777 this.onTriggerClick();
38779 this.inKeyMode = true;
38784 "enter" : function(e){
38785 this.onViewClick();
38789 "esc" : function(e){
38793 "tab" : function(e){
38794 this.onViewClick(false);
38795 this.fireEvent("specialkey", this, e);
38801 doRelay : function(foo, bar, hname){
38802 if(hname == 'down' || this.scope.isExpanded()){
38803 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38810 this.queryDelay = Math.max(this.queryDelay || 10,
38811 this.mode == 'local' ? 10 : 250);
38812 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38813 if(this.typeAhead){
38814 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38816 if(this.editable !== false){
38817 this.el.on("keyup", this.onKeyUp, this);
38819 if(this.forceSelection){
38820 this.on('blur', this.doForce, this);
38824 onDestroy : function(){
38826 this.view.setStore(null);
38827 this.view.el.removeAllListeners();
38828 this.view.el.remove();
38829 this.view.purgeListeners();
38832 this.list.destroy();
38835 this.store.un('beforeload', this.onBeforeLoad, this);
38836 this.store.un('load', this.onLoad, this);
38837 this.store.un('loadexception', this.onLoadException, this);
38839 Roo.form.ComboBox.superclass.onDestroy.call(this);
38843 fireKey : function(e){
38844 if(e.isNavKeyPress() && !this.list.isVisible()){
38845 this.fireEvent("specialkey", this, e);
38850 onResize: function(w, h){
38851 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
38853 if(typeof w != 'number'){
38854 // we do not handle it!?!?
38857 var tw = this.trigger.getWidth();
38858 tw += this.addicon ? this.addicon.getWidth() : 0;
38859 tw += this.editicon ? this.editicon.getWidth() : 0;
38861 this.el.setWidth( this.adjustWidth('input', x));
38863 this.trigger.setStyle('left', x+'px');
38865 if(this.list && this.listWidth === undefined){
38866 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
38867 this.list.setWidth(lw);
38868 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38876 * Allow or prevent the user from directly editing the field text. If false is passed,
38877 * the user will only be able to select from the items defined in the dropdown list. This method
38878 * is the runtime equivalent of setting the 'editable' config option at config time.
38879 * @param {Boolean} value True to allow the user to directly edit the field text
38881 setEditable : function(value){
38882 if(value == this.editable){
38885 this.editable = value;
38887 this.el.dom.setAttribute('readOnly', true);
38888 this.el.on('mousedown', this.onTriggerClick, this);
38889 this.el.addClass('x-combo-noedit');
38891 this.el.dom.setAttribute('readOnly', false);
38892 this.el.un('mousedown', this.onTriggerClick, this);
38893 this.el.removeClass('x-combo-noedit');
38898 onBeforeLoad : function(){
38899 if(!this.hasFocus){
38902 this.innerList.update(this.loadingText ?
38903 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
38904 this.restrictHeight();
38905 this.selectedIndex = -1;
38909 onLoad : function(){
38910 if(!this.hasFocus){
38913 if(this.store.getCount() > 0){
38915 this.restrictHeight();
38916 if(this.lastQuery == this.allQuery){
38918 this.el.dom.select();
38920 if(!this.selectByValue(this.value, true)){
38921 this.select(0, true);
38925 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
38926 this.taTask.delay(this.typeAheadDelay);
38930 this.onEmptyResults();
38935 onLoadException : function()
38938 Roo.log(this.store.reader.jsonData);
38939 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
38940 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
38946 onTypeAhead : function(){
38947 if(this.store.getCount() > 0){
38948 var r = this.store.getAt(0);
38949 var newValue = r.data[this.displayField];
38950 var len = newValue.length;
38951 var selStart = this.getRawValue().length;
38952 if(selStart != len){
38953 this.setRawValue(newValue);
38954 this.selectText(selStart, newValue.length);
38960 onSelect : function(record, index){
38961 if(this.fireEvent('beforeselect', this, record, index) !== false){
38962 this.setFromData(index > -1 ? record.data : false);
38964 this.fireEvent('select', this, record, index);
38969 * Returns the currently selected field value or empty string if no value is set.
38970 * @return {String} value The selected value
38972 getValue : function(){
38973 if(this.valueField){
38974 return typeof this.value != 'undefined' ? this.value : '';
38976 return Roo.form.ComboBox.superclass.getValue.call(this);
38981 * Clears any text/value currently set in the field
38983 clearValue : function(){
38984 if(this.hiddenField){
38985 this.hiddenField.value = '';
38988 this.setRawValue('');
38989 this.lastSelectionText = '';
38994 * Sets the specified value into the field. If the value finds a match, the corresponding record text
38995 * will be displayed in the field. If the value does not match the data value of an existing item,
38996 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
38997 * Otherwise the field will be blank (although the value will still be set).
38998 * @param {String} value The value to match
39000 setValue : function(v){
39002 if(this.valueField){
39003 var r = this.findRecord(this.valueField, v);
39005 text = r.data[this.displayField];
39006 }else if(this.valueNotFoundText !== undefined){
39007 text = this.valueNotFoundText;
39010 this.lastSelectionText = text;
39011 if(this.hiddenField){
39012 this.hiddenField.value = v;
39014 Roo.form.ComboBox.superclass.setValue.call(this, text);
39018 * @property {Object} the last set data for the element
39023 * Sets the value of the field based on a object which is related to the record format for the store.
39024 * @param {Object} value the value to set as. or false on reset?
39026 setFromData : function(o){
39027 var dv = ''; // display value
39028 var vv = ''; // value value..
39030 if (this.displayField) {
39031 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39033 // this is an error condition!!!
39034 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39037 if(this.valueField){
39038 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39040 if(this.hiddenField){
39041 this.hiddenField.value = vv;
39043 this.lastSelectionText = dv;
39044 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39048 // no hidden field.. - we store the value in 'value', but still display
39049 // display field!!!!
39050 this.lastSelectionText = dv;
39051 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39057 reset : function(){
39058 // overridden so that last data is reset..
39059 this.setValue(this.originalValue);
39060 this.clearInvalid();
39061 this.lastData = false;
39063 this.view.clearSelections();
39067 findRecord : function(prop, value){
39069 if(this.store.getCount() > 0){
39070 this.store.each(function(r){
39071 if(r.data[prop] == value){
39081 getName: function()
39083 // returns hidden if it's set..
39084 if (!this.rendered) {return ''};
39085 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39089 onViewMove : function(e, t){
39090 this.inKeyMode = false;
39094 onViewOver : function(e, t){
39095 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39098 var item = this.view.findItemFromChild(t);
39100 var index = this.view.indexOf(item);
39101 this.select(index, false);
39106 onViewClick : function(doFocus)
39108 var index = this.view.getSelectedIndexes()[0];
39109 var r = this.store.getAt(index);
39111 this.onSelect(r, index);
39113 if(doFocus !== false && !this.blockFocus){
39119 restrictHeight : function(){
39120 this.innerList.dom.style.height = '';
39121 var inner = this.innerList.dom;
39122 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39123 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39124 this.list.beginUpdate();
39125 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39126 this.list.alignTo(this.el, this.listAlign);
39127 this.list.endUpdate();
39131 onEmptyResults : function(){
39136 * Returns true if the dropdown list is expanded, else false.
39138 isExpanded : function(){
39139 return this.list.isVisible();
39143 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39144 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39145 * @param {String} value The data value of the item to select
39146 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39147 * selected item if it is not currently in view (defaults to true)
39148 * @return {Boolean} True if the value matched an item in the list, else false
39150 selectByValue : function(v, scrollIntoView){
39151 if(v !== undefined && v !== null){
39152 var r = this.findRecord(this.valueField || this.displayField, v);
39154 this.select(this.store.indexOf(r), scrollIntoView);
39162 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39163 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39164 * @param {Number} index The zero-based index of the list item to select
39165 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39166 * selected item if it is not currently in view (defaults to true)
39168 select : function(index, scrollIntoView){
39169 this.selectedIndex = index;
39170 this.view.select(index);
39171 if(scrollIntoView !== false){
39172 var el = this.view.getNode(index);
39174 this.innerList.scrollChildIntoView(el, false);
39180 selectNext : function(){
39181 var ct = this.store.getCount();
39183 if(this.selectedIndex == -1){
39185 }else if(this.selectedIndex < ct-1){
39186 this.select(this.selectedIndex+1);
39192 selectPrev : function(){
39193 var ct = this.store.getCount();
39195 if(this.selectedIndex == -1){
39197 }else if(this.selectedIndex != 0){
39198 this.select(this.selectedIndex-1);
39204 onKeyUp : function(e){
39205 if(this.editable !== false && !e.isSpecialKey()){
39206 this.lastKey = e.getKey();
39207 this.dqTask.delay(this.queryDelay);
39212 validateBlur : function(){
39213 return !this.list || !this.list.isVisible();
39217 initQuery : function(){
39218 this.doQuery(this.getRawValue());
39222 doForce : function(){
39223 if(this.el.dom.value.length > 0){
39224 this.el.dom.value =
39225 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39231 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39232 * query allowing the query action to be canceled if needed.
39233 * @param {String} query The SQL query to execute
39234 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39235 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39236 * saved in the current store (defaults to false)
39238 doQuery : function(q, forceAll){
39239 if(q === undefined || q === null){
39244 forceAll: forceAll,
39248 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39252 forceAll = qe.forceAll;
39253 if(forceAll === true || (q.length >= this.minChars)){
39254 if(this.lastQuery != q || this.alwaysQuery){
39255 this.lastQuery = q;
39256 if(this.mode == 'local'){
39257 this.selectedIndex = -1;
39259 this.store.clearFilter();
39261 this.store.filter(this.displayField, q);
39265 this.store.baseParams[this.queryParam] = q;
39267 params: this.getParams(q)
39272 this.selectedIndex = -1;
39279 getParams : function(q){
39281 //p[this.queryParam] = q;
39284 p.limit = this.pageSize;
39290 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39292 collapse : function(){
39293 if(!this.isExpanded()){
39297 Roo.get(document).un('mousedown', this.collapseIf, this);
39298 Roo.get(document).un('mousewheel', this.collapseIf, this);
39299 if (!this.editable) {
39300 Roo.get(document).un('keydown', this.listKeyPress, this);
39302 this.fireEvent('collapse', this);
39306 collapseIf : function(e){
39307 if(!e.within(this.wrap) && !e.within(this.list)){
39313 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39315 expand : function(){
39316 if(this.isExpanded() || !this.hasFocus){
39319 this.list.alignTo(this.el, this.listAlign);
39321 Roo.get(document).on('mousedown', this.collapseIf, this);
39322 Roo.get(document).on('mousewheel', this.collapseIf, this);
39323 if (!this.editable) {
39324 Roo.get(document).on('keydown', this.listKeyPress, this);
39327 this.fireEvent('expand', this);
39331 // Implements the default empty TriggerField.onTriggerClick function
39332 onTriggerClick : function(){
39336 if(this.isExpanded()){
39338 if (!this.blockFocus) {
39343 this.hasFocus = true;
39344 if(this.triggerAction == 'all') {
39345 this.doQuery(this.allQuery, true);
39347 this.doQuery(this.getRawValue());
39349 if (!this.blockFocus) {
39354 listKeyPress : function(e)
39356 //Roo.log('listkeypress');
39357 // scroll to first matching element based on key pres..
39358 if (e.isSpecialKey()) {
39361 var k = String.fromCharCode(e.getKey()).toUpperCase();
39364 var csel = this.view.getSelectedNodes();
39365 var cselitem = false;
39367 var ix = this.view.indexOf(csel[0]);
39368 cselitem = this.store.getAt(ix);
39369 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39375 this.store.each(function(v) {
39377 // start at existing selection.
39378 if (cselitem.id == v.id) {
39384 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39385 match = this.store.indexOf(v);
39390 if (match === false) {
39391 return true; // no more action?
39394 this.view.select(match);
39395 var sn = Roo.get(this.view.getSelectedNodes()[0])
39396 sn.scrollIntoView(sn.dom.parentNode, false);
39400 * @cfg {Boolean} grow
39404 * @cfg {Number} growMin
39408 * @cfg {Number} growMax
39416 * Copyright(c) 2010-2012, Roo J Solutions Limited
39423 * @class Roo.form.ComboBoxArray
39424 * @extends Roo.form.TextField
39425 * A facebook style adder... for lists of email / people / countries etc...
39426 * pick multiple items from a combo box, and shows each one.
39428 * Fred [x] Brian [x] [Pick another |v]
39431 * For this to work: it needs various extra information
39432 * - normal combo problay has
39434 * + displayField, valueField
39436 * For our purpose...
39439 * If we change from 'extends' to wrapping...
39446 * Create a new ComboBoxArray.
39447 * @param {Object} config Configuration options
39451 Roo.form.ComboBoxArray = function(config)
39454 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
39456 this.items = new Roo.util.MixedCollection(false);
39458 // construct the child combo...
39468 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39471 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39476 // behavies liek a hiddne field
39477 inputType: 'hidden',
39479 * @cfg {Number} width The width of the box that displays the selected element
39486 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39490 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39492 hiddenName : false,
39495 // private the array of items that are displayed..
39497 // private - the hidden field el.
39499 // private - the filed el..
39502 //validateValue : function() { return true; }, // all values are ok!
39503 //onAddClick: function() { },
39505 onRender : function(ct, position)
39508 // create the standard hidden element
39509 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39512 // give fake names to child combo;
39513 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39514 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39516 this.combo = Roo.factory(this.combo, Roo.form);
39517 this.combo.onRender(ct, position);
39518 if (typeof(this.combo.width) != 'undefined') {
39519 this.combo.onResize(this.combo.width,0);
39522 this.combo.initEvents();
39524 // assigned so form know we need to do this..
39525 this.store = this.combo.store;
39526 this.valueField = this.combo.valueField;
39527 this.displayField = this.combo.displayField ;
39530 this.combo.wrap.addClass('x-cbarray-grp');
39532 var cbwrap = this.combo.wrap.createChild(
39533 {tag: 'div', cls: 'x-cbarray-cb'},
39538 this.hiddenEl = this.combo.wrap.createChild({
39539 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39541 this.el = this.combo.wrap.createChild({
39542 tag: 'input', type:'hidden' , name: this.name, value : ''
39544 // this.el.dom.removeAttribute("name");
39547 this.outerWrap = this.combo.wrap;
39548 this.wrap = cbwrap;
39550 this.outerWrap.setWidth(this.width);
39551 this.outerWrap.dom.removeChild(this.el.dom);
39553 this.wrap.dom.appendChild(this.el.dom);
39554 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39555 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39557 this.combo.trigger.setStyle('position','relative');
39558 this.combo.trigger.setStyle('left', '0px');
39559 this.combo.trigger.setStyle('top', '2px');
39561 this.combo.el.setStyle('vertical-align', 'text-bottom');
39563 //this.trigger.setStyle('vertical-align', 'top');
39565 // this should use the code from combo really... on('add' ....)
39569 this.adder = this.outerWrap.createChild(
39570 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39572 this.adder.on('click', function(e) {
39573 _t.fireEvent('adderclick', this, e);
39577 //this.adder.on('click', this.onAddClick, _t);
39580 this.combo.on('select', function(cb, rec, ix) {
39581 this.addItem(rec.data);
39584 cb.el.dom.value = '';
39585 //cb.lastData = rec.data;
39594 getName: function()
39596 // returns hidden if it's set..
39597 if (!this.rendered) {return ''};
39598 return this.hiddenName ? this.hiddenName : this.name;
39603 onResize: function(w, h){
39606 // not sure if this is needed..
39607 //this.combo.onResize(w,h);
39609 if(typeof w != 'number'){
39610 // we do not handle it!?!?
39613 var tw = this.combo.trigger.getWidth();
39614 tw += this.addicon ? this.addicon.getWidth() : 0;
39615 tw += this.editicon ? this.editicon.getWidth() : 0;
39617 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39619 this.combo.trigger.setStyle('left', '0px');
39621 if(this.list && this.listWidth === undefined){
39622 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39623 this.list.setWidth(lw);
39624 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39631 addItem: function(rec)
39633 var valueField = this.combo.valueField;
39634 var displayField = this.combo.displayField;
39635 if (this.items.indexOfKey(rec[valueField]) > -1) {
39636 //console.log("GOT " + rec.data.id);
39640 var x = new Roo.form.ComboBoxArray.Item({
39641 //id : rec[this.idField],
39643 displayField : displayField ,
39644 tipField : displayField ,
39648 this.items.add(rec[valueField],x);
39649 // add it before the element..
39650 this.updateHiddenEl();
39651 x.render(this.outerWrap, this.wrap.dom);
39652 // add the image handler..
39655 updateHiddenEl : function()
39658 if (!this.hiddenEl) {
39662 var idField = this.combo.valueField;
39664 this.items.each(function(f) {
39665 ar.push(f.data[idField]);
39668 this.hiddenEl.dom.value = ar.join(',');
39674 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39675 this.items.each(function(f) {
39678 this.el.dom.value = '';
39679 if (this.hiddenEl) {
39680 this.hiddenEl.dom.value = '';
39684 getValue: function()
39686 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39688 setValue: function(v) // not a valid action - must use addItems..
39695 if (this.store.isLocal && (typeof(v) == 'string')) {
39696 // then we can use the store to find the values..
39697 // comma seperated at present.. this needs to allow JSON based encoding..
39698 this.hiddenEl.value = v;
39700 Roo.each(v.split(','), function(k) {
39701 Roo.log("CHECK " + this.valueField + ',' + k);
39702 var li = this.store.query(this.valueField, k);
39707 add[this.valueField] = k;
39708 add[this.displayField] = li.item(0).data[this.displayField];
39714 if (typeof(v) == 'object') {
39715 // then let's assume it's an array of objects..
39716 Roo.each(v, function(l) {
39724 setFromData: function(v)
39726 // this recieves an object, if setValues is called.
39728 this.el.dom.value = v[this.displayField];
39729 this.hiddenEl.dom.value = v[this.valueField];
39730 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39733 var kv = v[this.valueField];
39734 var dv = v[this.displayField];
39735 kv = typeof(kv) != 'string' ? '' : kv;
39736 dv = typeof(dv) != 'string' ? '' : dv;
39739 var keys = kv.split(',');
39740 var display = dv.split(',');
39741 for (var i = 0 ; i < keys.length; i++) {
39744 add[this.valueField] = keys[i];
39745 add[this.displayField] = display[i];
39753 validateValue : function(value){
39754 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39763 * @class Roo.form.ComboBoxArray.Item
39764 * @extends Roo.BoxComponent
39765 * A selected item in the list
39766 * Fred [x] Brian [x] [Pick another |v]
39769 * Create a new item.
39770 * @param {Object} config Configuration options
39773 Roo.form.ComboBoxArray.Item = function(config) {
39774 config.id = Roo.id();
39775 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39778 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39781 displayField : false,
39785 defaultAutoCreate : {
39787 cls: 'x-cbarray-item',
39794 src : Roo.BLANK_IMAGE_URL ,
39802 onRender : function(ct, position)
39804 Roo.form.Field.superclass.onRender.call(this, ct, position);
39807 var cfg = this.getAutoCreate();
39808 this.el = ct.createChild(cfg, position);
39811 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39813 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39814 this.cb.renderer(this.data) :
39815 String.format('{0}',this.data[this.displayField]);
39818 this.el.child('div').dom.setAttribute('qtip',
39819 String.format('{0}',this.data[this.tipField])
39822 this.el.child('img').on('click', this.remove, this);
39826 remove : function()
39829 this.cb.items.remove(this);
39830 this.el.child('img').un('click', this.remove, this);
39832 this.cb.updateHiddenEl();
39838 * Ext JS Library 1.1.1
39839 * Copyright(c) 2006-2007, Ext JS, LLC.
39841 * Originally Released Under LGPL - original licence link has changed is not relivant.
39844 * <script type="text/javascript">
39847 * @class Roo.form.Checkbox
39848 * @extends Roo.form.Field
39849 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
39851 * Creates a new Checkbox
39852 * @param {Object} config Configuration options
39854 Roo.form.Checkbox = function(config){
39855 Roo.form.Checkbox.superclass.constructor.call(this, config);
39859 * Fires when the checkbox is checked or unchecked.
39860 * @param {Roo.form.Checkbox} this This checkbox
39861 * @param {Boolean} checked The new checked value
39867 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
39869 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
39871 focusClass : undefined,
39873 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
39875 fieldClass: "x-form-field",
39877 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
39881 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39882 * {tag: "input", type: "checkbox", autocomplete: "off"})
39884 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
39886 * @cfg {String} boxLabel The text that appears beside the checkbox
39890 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
39894 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
39896 valueOff: '0', // value when not checked..
39898 actionMode : 'viewEl',
39901 itemCls : 'x-menu-check-item x-form-item',
39902 groupClass : 'x-menu-group-item',
39903 inputType : 'hidden',
39906 inSetChecked: false, // check that we are not calling self...
39908 inputElement: false, // real input element?
39909 basedOn: false, // ????
39911 isFormField: true, // not sure where this is needed!!!!
39913 onResize : function(){
39914 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
39915 if(!this.boxLabel){
39916 this.el.alignTo(this.wrap, 'c-c');
39920 initEvents : function(){
39921 Roo.form.Checkbox.superclass.initEvents.call(this);
39922 this.el.on("click", this.onClick, this);
39923 this.el.on("change", this.onClick, this);
39927 getResizeEl : function(){
39931 getPositionEl : function(){
39936 onRender : function(ct, position){
39937 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
39939 if(this.inputValue !== undefined){
39940 this.el.dom.value = this.inputValue;
39943 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
39944 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
39945 var viewEl = this.wrap.createChild({
39946 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
39947 this.viewEl = viewEl;
39948 this.wrap.on('click', this.onClick, this);
39950 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
39951 this.el.on('propertychange', this.setFromHidden, this); //ie
39956 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
39957 // viewEl.on('click', this.onClick, this);
39959 //if(this.checked){
39960 this.setChecked(this.checked);
39962 //this.checked = this.el.dom;
39968 initValue : Roo.emptyFn,
39971 * Returns the checked state of the checkbox.
39972 * @return {Boolean} True if checked, else false
39974 getValue : function(){
39976 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
39978 return this.valueOff;
39983 onClick : function(){
39984 this.setChecked(!this.checked);
39986 //if(this.el.dom.checked != this.checked){
39987 // this.setValue(this.el.dom.checked);
39992 * Sets the checked state of the checkbox.
39993 * On is always based on a string comparison between inputValue and the param.
39994 * @param {Boolean/String} value - the value to set
39995 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
39997 setValue : function(v,suppressEvent){
40000 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40001 //if(this.el && this.el.dom){
40002 // this.el.dom.checked = this.checked;
40003 // this.el.dom.defaultChecked = this.checked;
40005 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40006 //this.fireEvent("check", this, this.checked);
40009 setChecked : function(state,suppressEvent)
40011 if (this.inSetChecked) {
40012 this.checked = state;
40018 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40020 this.checked = state;
40021 if(suppressEvent !== true){
40022 this.fireEvent('check', this, state);
40024 this.inSetChecked = true;
40025 this.el.dom.value = state ? this.inputValue : this.valueOff;
40026 this.inSetChecked = false;
40029 // handle setting of hidden value by some other method!!?!?
40030 setFromHidden: function()
40035 //console.log("SET FROM HIDDEN");
40036 //alert('setFrom hidden');
40037 this.setValue(this.el.dom.value);
40040 onDestroy : function()
40043 Roo.get(this.viewEl).remove();
40046 Roo.form.Checkbox.superclass.onDestroy.call(this);
40051 * Ext JS Library 1.1.1
40052 * Copyright(c) 2006-2007, Ext JS, LLC.
40054 * Originally Released Under LGPL - original licence link has changed is not relivant.
40057 * <script type="text/javascript">
40061 * @class Roo.form.Radio
40062 * @extends Roo.form.Checkbox
40063 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40064 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40066 * Creates a new Radio
40067 * @param {Object} config Configuration options
40069 Roo.form.Radio = function(){
40070 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40072 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40073 inputType: 'radio',
40076 * If this radio is part of a group, it will return the selected value
40079 getGroupValue : function(){
40080 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40082 });//<script type="text/javascript">
40085 * Ext JS Library 1.1.1
40086 * Copyright(c) 2006-2007, Ext JS, LLC.
40087 * licensing@extjs.com
40089 * http://www.extjs.com/license
40095 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40096 * - IE ? - no idea how much works there.
40104 * @class Ext.form.HtmlEditor
40105 * @extends Ext.form.Field
40106 * Provides a lightweight HTML Editor component.
40108 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40110 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40111 * supported by this editor.</b><br/><br/>
40112 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40113 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40115 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40117 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40121 * @cfg {String} createLinkText The default text for the create link prompt
40123 createLinkText : 'Please enter the URL for the link:',
40125 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40127 defaultLinkValue : 'http:/'+'/',
40130 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40135 * @cfg {Number} height (in pixels)
40139 * @cfg {Number} width (in pixels)
40144 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40147 stylesheets: false,
40152 // private properties
40153 validationEvent : false,
40155 initialized : false,
40157 sourceEditMode : false,
40158 onFocus : Roo.emptyFn,
40160 hideMode:'offsets',
40162 defaultAutoCreate : { // modified by initCompnoent..
40164 style:"width:500px;height:300px;",
40165 autocomplete: "off"
40169 initComponent : function(){
40172 * @event initialize
40173 * Fires when the editor is fully initialized (including the iframe)
40174 * @param {HtmlEditor} this
40179 * Fires when the editor is first receives the focus. Any insertion must wait
40180 * until after this event.
40181 * @param {HtmlEditor} this
40185 * @event beforesync
40186 * Fires before the textarea is updated with content from the editor iframe. Return false
40187 * to cancel the sync.
40188 * @param {HtmlEditor} this
40189 * @param {String} html
40193 * @event beforepush
40194 * Fires before the iframe editor is updated with content from the textarea. Return false
40195 * to cancel the push.
40196 * @param {HtmlEditor} this
40197 * @param {String} html
40202 * Fires when the textarea is updated with content from the editor iframe.
40203 * @param {HtmlEditor} this
40204 * @param {String} html
40209 * Fires when the iframe editor is updated with content from the textarea.
40210 * @param {HtmlEditor} this
40211 * @param {String} html
40215 * @event editmodechange
40216 * Fires when the editor switches edit modes
40217 * @param {HtmlEditor} this
40218 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40220 editmodechange: true,
40222 * @event editorevent
40223 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40224 * @param {HtmlEditor} this
40228 this.defaultAutoCreate = {
40230 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40231 autocomplete: "off"
40236 * Protected method that will not generally be called directly. It
40237 * is called when the editor creates its toolbar. Override this method if you need to
40238 * add custom toolbar buttons.
40239 * @param {HtmlEditor} editor
40241 createToolbar : function(editor){
40242 if (!editor.toolbars || !editor.toolbars.length) {
40243 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40246 for (var i =0 ; i < editor.toolbars.length;i++) {
40247 editor.toolbars[i] = Roo.factory(
40248 typeof(editor.toolbars[i]) == 'string' ?
40249 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40250 Roo.form.HtmlEditor);
40251 editor.toolbars[i].init(editor);
40258 * Protected method that will not generally be called directly. It
40259 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40260 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40262 getDocMarkup : function(){
40265 if (this.stylesheets === false) {
40267 Roo.get(document.head).select('style').each(function(node) {
40268 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40271 Roo.get(document.head).select('link').each(function(node) {
40272 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40275 } else if (!this.stylesheets.length) {
40277 st = '<style type="text/css">' +
40278 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40281 Roo.each(this.stylesheets, function(s) {
40282 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40287 st += '<style type="text/css">' +
40288 'IMG { cursor: pointer } ' +
40292 return '<html><head>' + st +
40293 //<style type="text/css">' +
40294 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40296 ' </head><body class="roo-htmleditor-body"></body></html>';
40300 onRender : function(ct, position)
40303 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40304 this.el.dom.style.border = '0 none';
40305 this.el.dom.setAttribute('tabIndex', -1);
40306 this.el.addClass('x-hidden');
40307 if(Roo.isIE){ // fix IE 1px bogus margin
40308 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40310 this.wrap = this.el.wrap({
40311 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40314 if (this.resizable) {
40315 this.resizeEl = new Roo.Resizable(this.wrap, {
40319 minHeight : this.height,
40320 height: this.height,
40321 handles : this.resizable,
40324 resize : function(r, w, h) {
40325 _t.onResize(w,h); // -something
40332 this.frameId = Roo.id();
40334 this.createToolbar(this);
40338 var iframe = this.wrap.createChild({
40341 name: this.frameId,
40342 frameBorder : 'no',
40343 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
40347 // console.log(iframe);
40348 //this.wrap.dom.appendChild(iframe);
40350 this.iframe = iframe.dom;
40352 this.assignDocWin();
40354 this.doc.designMode = 'on';
40357 this.doc.write(this.getDocMarkup());
40361 var task = { // must defer to wait for browser to be ready
40363 //console.log("run task?" + this.doc.readyState);
40364 this.assignDocWin();
40365 if(this.doc.body || this.doc.readyState == 'complete'){
40367 this.doc.designMode="on";
40371 Roo.TaskMgr.stop(task);
40372 this.initEditor.defer(10, this);
40379 Roo.TaskMgr.start(task);
40382 this.setSize(this.wrap.getSize());
40384 if (this.resizeEl) {
40385 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
40386 // should trigger onReize..
40391 onResize : function(w, h)
40393 //Roo.log('resize: ' +w + ',' + h );
40394 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
40395 if(this.el && this.iframe){
40396 if(typeof w == 'number'){
40397 var aw = w - this.wrap.getFrameWidth('lr');
40398 this.el.setWidth(this.adjustWidth('textarea', aw));
40399 this.iframe.style.width = aw + 'px';
40401 if(typeof h == 'number'){
40403 for (var i =0; i < this.toolbars.length;i++) {
40404 // fixme - ask toolbars for heights?
40405 tbh += this.toolbars[i].tb.el.getHeight();
40406 if (this.toolbars[i].footer) {
40407 tbh += this.toolbars[i].footer.el.getHeight();
40414 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
40415 ah -= 5; // knock a few pixes off for look..
40416 this.el.setHeight(this.adjustWidth('textarea', ah));
40417 this.iframe.style.height = ah + 'px';
40419 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
40426 * Toggles the editor between standard and source edit mode.
40427 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
40429 toggleSourceEdit : function(sourceEditMode){
40431 this.sourceEditMode = sourceEditMode === true;
40433 if(this.sourceEditMode){
40435 // Roo.log(this.syncValue());
40437 this.iframe.className = 'x-hidden';
40438 this.el.removeClass('x-hidden');
40439 this.el.dom.removeAttribute('tabIndex');
40443 // Roo.log(this.pushValue());
40445 this.iframe.className = '';
40446 this.el.addClass('x-hidden');
40447 this.el.dom.setAttribute('tabIndex', -1);
40450 this.setSize(this.wrap.getSize());
40451 this.fireEvent('editmodechange', this, this.sourceEditMode);
40454 // private used internally
40455 createLink : function(){
40456 var url = prompt(this.createLinkText, this.defaultLinkValue);
40457 if(url && url != 'http:/'+'/'){
40458 this.relayCmd('createlink', url);
40462 // private (for BoxComponent)
40463 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40465 // private (for BoxComponent)
40466 getResizeEl : function(){
40470 // private (for BoxComponent)
40471 getPositionEl : function(){
40476 initEvents : function(){
40477 this.originalValue = this.getValue();
40481 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40484 markInvalid : Roo.emptyFn,
40486 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40489 clearInvalid : Roo.emptyFn,
40491 setValue : function(v){
40492 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40497 * Protected method that will not generally be called directly. If you need/want
40498 * custom HTML cleanup, this is the method you should override.
40499 * @param {String} html The HTML to be cleaned
40500 * return {String} The cleaned HTML
40502 cleanHtml : function(html){
40503 html = String(html);
40504 if(html.length > 5){
40505 if(Roo.isSafari){ // strip safari nonsense
40506 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40509 if(html == ' '){
40516 * Protected method that will not generally be called directly. Syncs the contents
40517 * of the editor iframe with the textarea.
40519 syncValue : function(){
40520 if(this.initialized){
40521 var bd = (this.doc.body || this.doc.documentElement);
40522 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40523 var html = bd.innerHTML;
40525 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40526 var m = bs.match(/text-align:(.*?);/i);
40528 html = '<div style="'+m[0]+'">' + html + '</div>';
40531 html = this.cleanHtml(html);
40532 // fix up the special chars.. normaly like back quotes in word...
40533 // however we do not want to do this with chinese..
40534 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40535 var cc = b.charCodeAt();
40537 (cc >= 0x4E00 && cc < 0xA000 ) ||
40538 (cc >= 0x3400 && cc < 0x4E00 ) ||
40539 (cc >= 0xf900 && cc < 0xfb00 )
40545 if(this.fireEvent('beforesync', this, html) !== false){
40546 this.el.dom.value = html;
40547 this.fireEvent('sync', this, html);
40553 * Protected method that will not generally be called directly. Pushes the value of the textarea
40554 * into the iframe editor.
40556 pushValue : function(){
40557 if(this.initialized){
40558 var v = this.el.dom.value;
40564 if(this.fireEvent('beforepush', this, v) !== false){
40565 var d = (this.doc.body || this.doc.documentElement);
40567 this.cleanUpPaste();
40568 this.el.dom.value = d.innerHTML;
40569 this.fireEvent('push', this, v);
40575 deferFocus : function(){
40576 this.focus.defer(10, this);
40580 focus : function(){
40581 if(this.win && !this.sourceEditMode){
40588 assignDocWin: function()
40590 var iframe = this.iframe;
40593 this.doc = iframe.contentWindow.document;
40594 this.win = iframe.contentWindow;
40596 if (!Roo.get(this.frameId)) {
40599 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40600 this.win = Roo.get(this.frameId).dom.contentWindow;
40605 initEditor : function(){
40606 //console.log("INIT EDITOR");
40607 this.assignDocWin();
40611 this.doc.designMode="on";
40613 this.doc.write(this.getDocMarkup());
40616 var dbody = (this.doc.body || this.doc.documentElement);
40617 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40618 // this copies styles from the containing element into thsi one..
40619 // not sure why we need all of this..
40620 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40621 ss['background-attachment'] = 'fixed'; // w3c
40622 dbody.bgProperties = 'fixed'; // ie
40623 Roo.DomHelper.applyStyles(dbody, ss);
40624 Roo.EventManager.on(this.doc, {
40625 //'mousedown': this.onEditorEvent,
40626 'mouseup': this.onEditorEvent,
40627 'dblclick': this.onEditorEvent,
40628 'click': this.onEditorEvent,
40629 'keyup': this.onEditorEvent,
40634 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40636 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40637 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40639 this.initialized = true;
40641 this.fireEvent('initialize', this);
40646 onDestroy : function(){
40652 for (var i =0; i < this.toolbars.length;i++) {
40653 // fixme - ask toolbars for heights?
40654 this.toolbars[i].onDestroy();
40657 this.wrap.dom.innerHTML = '';
40658 this.wrap.remove();
40663 onFirstFocus : function(){
40665 this.assignDocWin();
40668 this.activated = true;
40669 for (var i =0; i < this.toolbars.length;i++) {
40670 this.toolbars[i].onFirstFocus();
40673 if(Roo.isGecko){ // prevent silly gecko errors
40675 var s = this.win.getSelection();
40676 if(!s.focusNode || s.focusNode.nodeType != 3){
40677 var r = s.getRangeAt(0);
40678 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40683 this.execCmd('useCSS', true);
40684 this.execCmd('styleWithCSS', false);
40687 this.fireEvent('activate', this);
40691 adjustFont: function(btn){
40692 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40693 //if(Roo.isSafari){ // safari
40696 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40697 if(Roo.isSafari){ // safari
40698 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40699 v = (v < 10) ? 10 : v;
40700 v = (v > 48) ? 48 : v;
40701 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40706 v = Math.max(1, v+adjust);
40708 this.execCmd('FontSize', v );
40711 onEditorEvent : function(e){
40712 this.fireEvent('editorevent', this, e);
40713 // this.updateToolbar();
40714 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40717 insertTag : function(tg)
40719 // could be a bit smarter... -> wrap the current selected tRoo..
40720 if (tg.toLowerCase() == 'span') {
40722 range = this.createRange(this.getSelection());
40723 var wrappingNode = this.doc.createElement("span");
40724 wrappingNode.appendChild(range.extractContents());
40725 range.insertNode(wrappingNode);
40732 this.execCmd("formatblock", tg);
40736 insertText : function(txt)
40740 var range = this.createRange();
40741 range.deleteContents();
40742 //alert(Sender.getAttribute('label'));
40744 range.insertNode(this.doc.createTextNode(txt));
40748 relayBtnCmd : function(btn){
40749 this.relayCmd(btn.cmd);
40753 * Executes a Midas editor command on the editor document and performs necessary focus and
40754 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40755 * @param {String} cmd The Midas command
40756 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40758 relayCmd : function(cmd, value){
40760 this.execCmd(cmd, value);
40761 this.fireEvent('editorevent', this);
40762 //this.updateToolbar();
40767 * Executes a Midas editor command directly on the editor document.
40768 * For visual commands, you should use {@link #relayCmd} instead.
40769 * <b>This should only be called after the editor is initialized.</b>
40770 * @param {String} cmd The Midas command
40771 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40773 execCmd : function(cmd, value){
40774 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40781 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40783 * @param {String} text | dom node..
40785 insertAtCursor : function(text)
40790 if(!this.activated){
40796 var r = this.doc.selection.createRange();
40807 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40811 // from jquery ui (MIT licenced)
40813 var win = this.win;
40815 if (win.getSelection && win.getSelection().getRangeAt) {
40816 range = win.getSelection().getRangeAt(0);
40817 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
40818 range.insertNode(node);
40819 } else if (win.document.selection && win.document.selection.createRange) {
40820 // no firefox support
40821 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40822 win.document.selection.createRange().pasteHTML(txt);
40824 // no firefox support
40825 var txt = typeof(text) == 'string' ? text : text.outerHTML;
40826 this.execCmd('InsertHTML', txt);
40835 mozKeyPress : function(e){
40837 var c = e.getCharCode(), cmd;
40840 c = String.fromCharCode(c).toLowerCase();
40854 this.cleanUpPaste.defer(100, this);
40862 e.preventDefault();
40870 fixKeys : function(){ // load time branching for fastest keydown performance
40872 return function(e){
40873 var k = e.getKey(), r;
40876 r = this.doc.selection.createRange();
40879 r.pasteHTML('    ');
40886 r = this.doc.selection.createRange();
40888 var target = r.parentElement();
40889 if(!target || target.tagName.toLowerCase() != 'li'){
40891 r.pasteHTML('<br />');
40897 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40898 this.cleanUpPaste.defer(100, this);
40904 }else if(Roo.isOpera){
40905 return function(e){
40906 var k = e.getKey();
40910 this.execCmd('InsertHTML','    ');
40913 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40914 this.cleanUpPaste.defer(100, this);
40919 }else if(Roo.isSafari){
40920 return function(e){
40921 var k = e.getKey();
40925 this.execCmd('InsertText','\t');
40929 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
40930 this.cleanUpPaste.defer(100, this);
40938 getAllAncestors: function()
40940 var p = this.getSelectedNode();
40943 a.push(p); // push blank onto stack..
40944 p = this.getParentElement();
40948 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
40952 a.push(this.doc.body);
40956 lastSelNode : false,
40959 getSelection : function()
40961 this.assignDocWin();
40962 return Roo.isIE ? this.doc.selection : this.win.getSelection();
40965 getSelectedNode: function()
40967 // this may only work on Gecko!!!
40969 // should we cache this!!!!
40974 var range = this.createRange(this.getSelection()).cloneRange();
40977 var parent = range.parentElement();
40979 var testRange = range.duplicate();
40980 testRange.moveToElementText(parent);
40981 if (testRange.inRange(range)) {
40984 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
40987 parent = parent.parentElement;
40992 // is ancestor a text element.
40993 var ac = range.commonAncestorContainer;
40994 if (ac.nodeType == 3) {
40995 ac = ac.parentNode;
40998 var ar = ac.childNodes;
41001 var other_nodes = [];
41002 var has_other_nodes = false;
41003 for (var i=0;i<ar.length;i++) {
41004 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41007 // fullly contained node.
41009 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41014 // probably selected..
41015 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41016 other_nodes.push(ar[i]);
41020 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41025 has_other_nodes = true;
41027 if (!nodes.length && other_nodes.length) {
41028 nodes= other_nodes;
41030 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41036 createRange: function(sel)
41038 // this has strange effects when using with
41039 // top toolbar - not sure if it's a great idea.
41040 //this.editor.contentWindow.focus();
41041 if (typeof sel != "undefined") {
41043 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41045 return this.doc.createRange();
41048 return this.doc.createRange();
41051 getParentElement: function()
41054 this.assignDocWin();
41055 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41057 var range = this.createRange(sel);
41060 var p = range.commonAncestorContainer;
41061 while (p.nodeType == 3) { // text node
41072 * Range intersection.. the hard stuff...
41076 * [ -- selected range --- ]
41080 * if end is before start or hits it. fail.
41081 * if start is after end or hits it fail.
41083 * if either hits (but other is outside. - then it's not
41089 // @see http://www.thismuchiknow.co.uk/?p=64.
41090 rangeIntersectsNode : function(range, node)
41092 var nodeRange = node.ownerDocument.createRange();
41094 nodeRange.selectNode(node);
41096 nodeRange.selectNodeContents(node);
41099 var rangeStartRange = range.cloneRange();
41100 rangeStartRange.collapse(true);
41102 var rangeEndRange = range.cloneRange();
41103 rangeEndRange.collapse(false);
41105 var nodeStartRange = nodeRange.cloneRange();
41106 nodeStartRange.collapse(true);
41108 var nodeEndRange = nodeRange.cloneRange();
41109 nodeEndRange.collapse(false);
41111 return rangeStartRange.compareBoundaryPoints(
41112 Range.START_TO_START, nodeEndRange) == -1 &&
41113 rangeEndRange.compareBoundaryPoints(
41114 Range.START_TO_START, nodeStartRange) == 1;
41118 rangeCompareNode : function(range, node)
41120 var nodeRange = node.ownerDocument.createRange();
41122 nodeRange.selectNode(node);
41124 nodeRange.selectNodeContents(node);
41128 range.collapse(true);
41130 nodeRange.collapse(true);
41132 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41133 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41135 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41137 var nodeIsBefore = ss == 1;
41138 var nodeIsAfter = ee == -1;
41140 if (nodeIsBefore && nodeIsAfter)
41142 if (!nodeIsBefore && nodeIsAfter)
41143 return 1; //right trailed.
41145 if (nodeIsBefore && !nodeIsAfter)
41146 return 2; // left trailed.
41151 // private? - in a new class?
41152 cleanUpPaste : function()
41154 // cleans up the whole document..
41155 Roo.log('cleanuppaste');
41156 this.cleanUpChildren(this.doc.body);
41157 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41158 if (clean != this.doc.body.innerHTML) {
41159 this.doc.body.innerHTML = clean;
41164 cleanWordChars : function(input) {// change the chars to hex code
41165 var he = Roo.form.HtmlEditor;
41167 var output = input;
41168 Roo.each(he.swapCodes, function(sw) {
41169 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41171 output = output.replace(swapper, sw[1]);
41178 cleanUpChildren : function (n)
41180 if (!n.childNodes.length) {
41183 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41184 this.cleanUpChild(n.childNodes[i]);
41191 cleanUpChild : function (node)
41194 //console.log(node);
41195 if (node.nodeName == "#text") {
41196 // clean up silly Windows -- stuff?
41199 if (node.nodeName == "#comment") {
41200 node.parentNode.removeChild(node);
41201 // clean up silly Windows -- stuff?
41205 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41207 node.parentNode.removeChild(node);
41212 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41214 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41215 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41217 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41218 // remove_keep_children = true;
41221 if (remove_keep_children) {
41222 this.cleanUpChildren(node);
41223 // inserts everything just before this node...
41224 while (node.childNodes.length) {
41225 var cn = node.childNodes[0];
41226 node.removeChild(cn);
41227 node.parentNode.insertBefore(cn, node);
41229 node.parentNode.removeChild(node);
41233 if (!node.attributes || !node.attributes.length) {
41234 this.cleanUpChildren(node);
41238 function cleanAttr(n,v)
41241 if (v.match(/^\./) || v.match(/^\//)) {
41244 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41247 if (v.match(/^#/)) {
41250 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41251 node.removeAttribute(n);
41255 function cleanStyle(n,v)
41257 if (v.match(/expression/)) { //XSS?? should we even bother..
41258 node.removeAttribute(n);
41261 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
41262 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
41265 var parts = v.split(/;/);
41268 Roo.each(parts, function(p) {
41269 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41273 var l = p.split(':').shift().replace(/\s+/g,'');
41274 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41277 if ( cblack.indexOf(l) > -1) {
41278 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41279 //node.removeAttribute(n);
41283 // only allow 'c whitelisted system attributes'
41284 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41285 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41286 //node.removeAttribute(n);
41296 if (clean.length) {
41297 node.setAttribute(n, clean.join(';'));
41299 node.removeAttribute(n);
41305 for (var i = node.attributes.length-1; i > -1 ; i--) {
41306 var a = node.attributes[i];
41309 if (a.name.toLowerCase().substr(0,2)=='on') {
41310 node.removeAttribute(a.name);
41313 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41314 node.removeAttribute(a.name);
41317 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41318 cleanAttr(a.name,a.value); // fixme..
41321 if (a.name == 'style') {
41322 cleanStyle(a.name,a.value);
41325 /// clean up MS crap..
41326 // tecnically this should be a list of valid class'es..
41329 if (a.name == 'class') {
41330 if (a.value.match(/^Mso/)) {
41331 node.className = '';
41334 if (a.value.match(/body/)) {
41335 node.className = '';
41346 this.cleanUpChildren(node);
41352 // hide stuff that is not compatible
41366 * @event specialkey
41370 * @cfg {String} fieldClass @hide
41373 * @cfg {String} focusClass @hide
41376 * @cfg {String} autoCreate @hide
41379 * @cfg {String} inputType @hide
41382 * @cfg {String} invalidClass @hide
41385 * @cfg {String} invalidText @hide
41388 * @cfg {String} msgFx @hide
41391 * @cfg {String} validateOnBlur @hide
41395 Roo.form.HtmlEditor.white = [
41396 'area', 'br', 'img', 'input', 'hr', 'wbr',
41398 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
41399 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
41400 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
41401 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
41402 'table', 'ul', 'xmp',
41404 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
41407 'dir', 'menu', 'ol', 'ul', 'dl',
41413 Roo.form.HtmlEditor.black = [
41414 // 'embed', 'object', // enable - backend responsiblity to clean thiese
41416 'base', 'basefont', 'bgsound', 'blink', 'body',
41417 'frame', 'frameset', 'head', 'html', 'ilayer',
41418 'iframe', 'layer', 'link', 'meta', 'object',
41419 'script', 'style' ,'title', 'xml' // clean later..
41421 Roo.form.HtmlEditor.clean = [
41422 'script', 'style', 'title', 'xml'
41424 Roo.form.HtmlEditor.remove = [
41429 Roo.form.HtmlEditor.ablack = [
41433 Roo.form.HtmlEditor.aclean = [
41434 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
41438 Roo.form.HtmlEditor.pwhite= [
41439 'http', 'https', 'mailto'
41442 // white listed style attributes.
41443 Roo.form.HtmlEditor.cwhite= [
41444 // 'text-align', /// default is to allow most things..
41450 // black listed style attributes.
41451 Roo.form.HtmlEditor.cblack= [
41452 // 'font-size' -- this can be set by the project
41456 Roo.form.HtmlEditor.swapCodes =[
41467 // <script type="text/javascript">
41470 * Ext JS Library 1.1.1
41471 * Copyright(c) 2006-2007, Ext JS, LLC.
41477 * @class Roo.form.HtmlEditorToolbar1
41482 new Roo.form.HtmlEditor({
41485 new Roo.form.HtmlEditorToolbar1({
41486 disable : { fonts: 1 , format: 1, ..., ... , ...],
41492 * @cfg {Object} disable List of elements to disable..
41493 * @cfg {Array} btns List of additional buttons.
41497 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
41500 Roo.form.HtmlEditor.ToolbarStandard = function(config)
41503 Roo.apply(this, config);
41505 // default disabled, based on 'good practice'..
41506 this.disable = this.disable || {};
41507 Roo.applyIf(this.disable, {
41510 specialElements : true
41514 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41515 // dont call parent... till later.
41518 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41526 * @cfg {Object} disable List of toolbar elements to disable
41531 * @cfg {Array} fontFamilies An array of available font families
41549 // "á" , ?? a acute?
41554 "°" // , // degrees
41556 // "é" , // e ecute
41557 // "ú" , // u ecute?
41560 specialElements : [
41562 text: "Insert Table",
41565 ihtml : '<table><tr><td>Cell</td></tr></table>'
41569 text: "Insert Image",
41572 ihtml : '<img src="about:blank"/>'
41581 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41582 "input:submit", "input:button", "select", "textarea", "label" ],
41585 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41587 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
41591 * @cfg {String} defaultFont default font to use.
41593 defaultFont: 'tahoma',
41595 fontSelect : false,
41598 formatCombo : false,
41600 init : function(editor)
41602 this.editor = editor;
41605 var fid = editor.frameId;
41607 function btn(id, toggle, handler){
41608 var xid = fid + '-'+ id ;
41612 cls : 'x-btn-icon x-edit-'+id,
41613 enableToggle:toggle !== false,
41614 scope: editor, // was editor...
41615 handler:handler||editor.relayBtnCmd,
41616 clickEvent:'mousedown',
41617 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41624 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41626 // stop form submits
41627 tb.el.on('click', function(e){
41628 e.preventDefault(); // what does this do?
41631 if(!this.disable.font) { // && !Roo.isSafari){
41632 /* why no safari for fonts
41633 editor.fontSelect = tb.el.createChild({
41636 cls:'x-font-select',
41637 html: this.createFontOptions()
41640 editor.fontSelect.on('change', function(){
41641 var font = editor.fontSelect.dom.value;
41642 editor.relayCmd('fontname', font);
41643 editor.deferFocus();
41647 editor.fontSelect.dom,
41653 if(!this.disable.formats){
41654 this.formatCombo = new Roo.form.ComboBox({
41655 store: new Roo.data.SimpleStore({
41658 data : this.formats // from states.js
41662 //autoCreate : {tag: "div", size: "20"},
41663 displayField:'tag',
41667 triggerAction: 'all',
41668 emptyText:'Add tag',
41669 selectOnFocus:true,
41672 'select': function(c, r, i) {
41673 editor.insertTag(r.get('tag'));
41679 tb.addField(this.formatCombo);
41683 if(!this.disable.format){
41690 if(!this.disable.fontSize){
41695 btn('increasefontsize', false, editor.adjustFont),
41696 btn('decreasefontsize', false, editor.adjustFont)
41701 if(!this.disable.colors){
41704 id:editor.frameId +'-forecolor',
41705 cls:'x-btn-icon x-edit-forecolor',
41706 clickEvent:'mousedown',
41707 tooltip: this.buttonTips['forecolor'] || undefined,
41709 menu : new Roo.menu.ColorMenu({
41710 allowReselect: true,
41711 focus: Roo.emptyFn,
41714 selectHandler: function(cp, color){
41715 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41716 editor.deferFocus();
41719 clickEvent:'mousedown'
41722 id:editor.frameId +'backcolor',
41723 cls:'x-btn-icon x-edit-backcolor',
41724 clickEvent:'mousedown',
41725 tooltip: this.buttonTips['backcolor'] || undefined,
41727 menu : new Roo.menu.ColorMenu({
41728 focus: Roo.emptyFn,
41731 allowReselect: true,
41732 selectHandler: function(cp, color){
41734 editor.execCmd('useCSS', false);
41735 editor.execCmd('hilitecolor', color);
41736 editor.execCmd('useCSS', true);
41737 editor.deferFocus();
41739 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41740 Roo.isSafari || Roo.isIE ? '#'+color : color);
41741 editor.deferFocus();
41745 clickEvent:'mousedown'
41750 // now add all the items...
41753 if(!this.disable.alignments){
41756 btn('justifyleft'),
41757 btn('justifycenter'),
41758 btn('justifyright')
41762 //if(!Roo.isSafari){
41763 if(!this.disable.links){
41766 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41770 if(!this.disable.lists){
41773 btn('insertorderedlist'),
41774 btn('insertunorderedlist')
41777 if(!this.disable.sourceEdit){
41780 btn('sourceedit', true, function(btn){
41781 this.toggleSourceEdit(btn.pressed);
41788 // special menu.. - needs to be tidied up..
41789 if (!this.disable.special) {
41792 cls: 'x-edit-none',
41798 for (var i =0; i < this.specialChars.length; i++) {
41799 smenu.menu.items.push({
41801 html: this.specialChars[i],
41802 handler: function(a,b) {
41803 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41804 //editor.insertAtCursor(a.html);
41817 if (!this.disable.specialElements) {
41820 cls: 'x-edit-none',
41825 for (var i =0; i < this.specialElements.length; i++) {
41826 semenu.menu.items.push(
41828 handler: function(a,b) {
41829 editor.insertAtCursor(this.ihtml);
41831 }, this.specialElements[i])
41843 for(var i =0; i< this.btns.length;i++) {
41844 var b = Roo.factory(this.btns[i],Roo.form);
41845 b.cls = 'x-edit-none';
41854 // disable everything...
41856 this.tb.items.each(function(item){
41857 if(item.id != editor.frameId+ '-sourceedit'){
41861 this.rendered = true;
41863 // the all the btns;
41864 editor.on('editorevent', this.updateToolbar, this);
41865 // other toolbars need to implement this..
41866 //editor.on('editmodechange', this.updateToolbar, this);
41872 * Protected method that will not generally be called directly. It triggers
41873 * a toolbar update by reading the markup state of the current selection in the editor.
41875 updateToolbar: function(){
41877 if(!this.editor.activated){
41878 this.editor.onFirstFocus();
41882 var btns = this.tb.items.map,
41883 doc = this.editor.doc,
41884 frameId = this.editor.frameId;
41886 if(!this.disable.font && !Roo.isSafari){
41888 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
41889 if(name != this.fontSelect.dom.value){
41890 this.fontSelect.dom.value = name;
41894 if(!this.disable.format){
41895 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
41896 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
41897 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
41899 if(!this.disable.alignments){
41900 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
41901 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
41902 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
41904 if(!Roo.isSafari && !this.disable.lists){
41905 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
41906 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
41909 var ans = this.editor.getAllAncestors();
41910 if (this.formatCombo) {
41913 var store = this.formatCombo.store;
41914 this.formatCombo.setValue("");
41915 for (var i =0; i < ans.length;i++) {
41916 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
41918 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
41926 // hides menus... - so this cant be on a menu...
41927 Roo.menu.MenuMgr.hideAll();
41929 //this.editorsyncValue();
41933 createFontOptions : function(){
41934 var buf = [], fs = this.fontFamilies, ff, lc;
41938 for(var i = 0, len = fs.length; i< len; i++){
41940 lc = ff.toLowerCase();
41942 '<option value="',lc,'" style="font-family:',ff,';"',
41943 (this.defaultFont == lc ? ' selected="true">' : '>'),
41948 return buf.join('');
41951 toggleSourceEdit : function(sourceEditMode){
41952 if(sourceEditMode === undefined){
41953 sourceEditMode = !this.sourceEditMode;
41955 this.sourceEditMode = sourceEditMode === true;
41956 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
41957 // just toggle the button?
41958 if(btn.pressed !== this.editor.sourceEditMode){
41959 btn.toggle(this.editor.sourceEditMode);
41963 if(this.sourceEditMode){
41964 this.tb.items.each(function(item){
41965 if(item.cmd != 'sourceedit'){
41971 if(this.initialized){
41972 this.tb.items.each(function(item){
41978 // tell the editor that it's been pressed..
41979 this.editor.toggleSourceEdit(sourceEditMode);
41983 * Object collection of toolbar tooltips for the buttons in the editor. The key
41984 * is the command id associated with that button and the value is a valid QuickTips object.
41989 title: 'Bold (Ctrl+B)',
41990 text: 'Make the selected text bold.',
41991 cls: 'x-html-editor-tip'
41994 title: 'Italic (Ctrl+I)',
41995 text: 'Make the selected text italic.',
41996 cls: 'x-html-editor-tip'
42004 title: 'Bold (Ctrl+B)',
42005 text: 'Make the selected text bold.',
42006 cls: 'x-html-editor-tip'
42009 title: 'Italic (Ctrl+I)',
42010 text: 'Make the selected text italic.',
42011 cls: 'x-html-editor-tip'
42014 title: 'Underline (Ctrl+U)',
42015 text: 'Underline the selected text.',
42016 cls: 'x-html-editor-tip'
42018 increasefontsize : {
42019 title: 'Grow Text',
42020 text: 'Increase the font size.',
42021 cls: 'x-html-editor-tip'
42023 decreasefontsize : {
42024 title: 'Shrink Text',
42025 text: 'Decrease the font size.',
42026 cls: 'x-html-editor-tip'
42029 title: 'Text Highlight Color',
42030 text: 'Change the background color of the selected text.',
42031 cls: 'x-html-editor-tip'
42034 title: 'Font Color',
42035 text: 'Change the color of the selected text.',
42036 cls: 'x-html-editor-tip'
42039 title: 'Align Text Left',
42040 text: 'Align text to the left.',
42041 cls: 'x-html-editor-tip'
42044 title: 'Center Text',
42045 text: 'Center text in the editor.',
42046 cls: 'x-html-editor-tip'
42049 title: 'Align Text Right',
42050 text: 'Align text to the right.',
42051 cls: 'x-html-editor-tip'
42053 insertunorderedlist : {
42054 title: 'Bullet List',
42055 text: 'Start a bulleted list.',
42056 cls: 'x-html-editor-tip'
42058 insertorderedlist : {
42059 title: 'Numbered List',
42060 text: 'Start a numbered list.',
42061 cls: 'x-html-editor-tip'
42064 title: 'Hyperlink',
42065 text: 'Make the selected text a hyperlink.',
42066 cls: 'x-html-editor-tip'
42069 title: 'Source Edit',
42070 text: 'Switch to source editing mode.',
42071 cls: 'x-html-editor-tip'
42075 onDestroy : function(){
42078 this.tb.items.each(function(item){
42080 item.menu.removeAll();
42082 item.menu.el.destroy();
42090 onFirstFocus: function() {
42091 this.tb.items.each(function(item){
42100 // <script type="text/javascript">
42103 * Ext JS Library 1.1.1
42104 * Copyright(c) 2006-2007, Ext JS, LLC.
42111 * @class Roo.form.HtmlEditor.ToolbarContext
42116 new Roo.form.HtmlEditor({
42119 { xtype: 'ToolbarStandard', styles : {} }
42120 { xtype: 'ToolbarContext', disable : {} }
42126 * @config : {Object} disable List of elements to disable.. (not done yet.)
42127 * @config : {Object} styles Map of styles available.
42131 Roo.form.HtmlEditor.ToolbarContext = function(config)
42134 Roo.apply(this, config);
42135 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42136 // dont call parent... till later.
42137 this.styles = this.styles || {};
42142 Roo.form.HtmlEditor.ToolbarContext.types = {
42154 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42216 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42221 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42231 style : 'fontFamily',
42232 displayField: 'display',
42233 optname : 'font-family',
42282 // should we really allow this??
42283 // should this just be
42294 style : 'fontFamily',
42295 displayField: 'display',
42296 optname : 'font-family',
42303 style : 'fontFamily',
42304 displayField: 'display',
42305 optname : 'font-family',
42312 style : 'fontFamily',
42313 displayField: 'display',
42314 optname : 'font-family',
42325 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
42326 Roo.form.HtmlEditor.ToolbarContext.stores = false;
42328 Roo.form.HtmlEditor.ToolbarContext.options = {
42330 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
42331 [ 'Courier New', 'Courier New'],
42332 [ 'Tahoma', 'Tahoma'],
42333 [ 'Times New Roman,serif', 'Times'],
42334 [ 'Verdana','Verdana' ]
42338 // fixme - these need to be configurable..
42341 Roo.form.HtmlEditor.ToolbarContext.types
42344 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42352 * @cfg {Object} disable List of toolbar elements to disable
42357 * @cfg {Object} styles List of styles
42358 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42360 * These must be defined in the page, so they get rendered correctly..
42371 init : function(editor)
42373 this.editor = editor;
42376 var fid = editor.frameId;
42378 function btn(id, toggle, handler){
42379 var xid = fid + '-'+ id ;
42383 cls : 'x-btn-icon x-edit-'+id,
42384 enableToggle:toggle !== false,
42385 scope: editor, // was editor...
42386 handler:handler||editor.relayBtnCmd,
42387 clickEvent:'mousedown',
42388 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42392 // create a new element.
42393 var wdiv = editor.wrap.createChild({
42395 }, editor.wrap.dom.firstChild.nextSibling, true);
42397 // can we do this more than once??
42399 // stop form submits
42402 // disable everything...
42403 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42404 this.toolbars = {};
42406 for (var i in ty) {
42408 this.toolbars[i] = this.buildToolbar(ty[i],i);
42410 this.tb = this.toolbars.BODY;
42412 this.buildFooter();
42413 this.footer.show();
42414 editor.on('hide', function( ) { this.footer.hide() }, this);
42415 editor.on('show', function( ) { this.footer.show() }, this);
42418 this.rendered = true;
42420 // the all the btns;
42421 editor.on('editorevent', this.updateToolbar, this);
42422 // other toolbars need to implement this..
42423 //editor.on('editmodechange', this.updateToolbar, this);
42429 * Protected method that will not generally be called directly. It triggers
42430 * a toolbar update by reading the markup state of the current selection in the editor.
42432 updateToolbar: function(editor,ev,sel){
42435 // capture mouse up - this is handy for selecting images..
42436 // perhaps should go somewhere else...
42437 if(!this.editor.activated){
42438 this.editor.onFirstFocus();
42442 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42443 // selectNode - might want to handle IE?
42445 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42446 ev.target && ev.target.tagName == 'IMG') {
42447 // they have click on an image...
42448 // let's see if we can change the selection...
42451 var nodeRange = sel.ownerDocument.createRange();
42453 nodeRange.selectNode(sel);
42455 nodeRange.selectNodeContents(sel);
42457 //nodeRange.collapse(true);
42458 var s = editor.win.getSelection();
42459 s.removeAllRanges();
42460 s.addRange(nodeRange);
42464 var updateFooter = sel ? false : true;
42467 var ans = this.editor.getAllAncestors();
42470 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42473 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42474 sel = sel ? sel : this.editor.doc.body;
42475 sel = sel.tagName.length ? sel : this.editor.doc.body;
42478 // pick a menu that exists..
42479 var tn = sel.tagName.toUpperCase();
42480 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42482 tn = sel.tagName.toUpperCase();
42484 var lastSel = this.tb.selectedNode
42486 this.tb.selectedNode = sel;
42488 // if current menu does not match..
42489 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42492 ///console.log("show: " + tn);
42493 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42496 this.tb.items.first().el.innerHTML = tn + ': ';
42499 // update attributes
42500 if (this.tb.fields) {
42501 this.tb.fields.each(function(e) {
42503 e.setValue(sel.style[e.stylename]);
42506 e.setValue(sel.getAttribute(e.attrname));
42510 var hasStyles = false;
42511 for(var i in this.styles) {
42518 var st = this.tb.fields.item(0);
42520 st.store.removeAll();
42523 var cn = sel.className.split(/\s+/);
42526 if (this.styles['*']) {
42528 Roo.each(this.styles['*'], function(v) {
42529 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42532 if (this.styles[tn]) {
42533 Roo.each(this.styles[tn], function(v) {
42534 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42538 st.store.loadData(avs);
42542 // flag our selected Node.
42543 this.tb.selectedNode = sel;
42546 Roo.menu.MenuMgr.hideAll();
42550 if (!updateFooter) {
42551 //this.footDisp.dom.innerHTML = '';
42554 // update the footer
42558 this.footerEls = ans.reverse();
42559 Roo.each(this.footerEls, function(a,i) {
42560 if (!a) { return; }
42561 html += html.length ? ' > ' : '';
42563 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42568 var sz = this.footDisp.up('td').getSize();
42569 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42570 this.footDisp.dom.style.marginLeft = '5px';
42572 this.footDisp.dom.style.overflow = 'hidden';
42574 this.footDisp.dom.innerHTML = html;
42576 //this.editorsyncValue();
42583 onDestroy : function(){
42586 this.tb.items.each(function(item){
42588 item.menu.removeAll();
42590 item.menu.el.destroy();
42598 onFirstFocus: function() {
42599 // need to do this for all the toolbars..
42600 this.tb.items.each(function(item){
42604 buildToolbar: function(tlist, nm)
42606 var editor = this.editor;
42607 // create a new element.
42608 var wdiv = editor.wrap.createChild({
42610 }, editor.wrap.dom.firstChild.nextSibling, true);
42613 var tb = new Roo.Toolbar(wdiv);
42616 tb.add(nm+ ": ");
42619 for(var i in this.styles) {
42624 if (styles && styles.length) {
42626 // this needs a multi-select checkbox...
42627 tb.addField( new Roo.form.ComboBox({
42628 store: new Roo.data.SimpleStore({
42630 fields: ['val', 'selected'],
42633 name : '-roo-edit-className',
42634 attrname : 'className',
42635 displayField: 'val',
42639 triggerAction: 'all',
42640 emptyText:'Select Style',
42641 selectOnFocus:true,
42644 'select': function(c, r, i) {
42645 // initial support only for on class per el..
42646 tb.selectedNode.className = r ? r.get('val') : '';
42647 editor.syncValue();
42654 var tbc = Roo.form.HtmlEditor.ToolbarContext;
42655 var tbops = tbc.options;
42657 for (var i in tlist) {
42659 var item = tlist[i];
42660 tb.add(item.title + ": ");
42663 //optname == used so you can configure the options available..
42664 var opts = item.opts ? item.opts : false;
42665 if (item.optname) {
42666 opts = tbops[item.optname];
42671 // opts == pulldown..
42672 tb.addField( new Roo.form.ComboBox({
42673 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
42675 fields: ['val', 'display'],
42678 name : '-roo-edit-' + i,
42680 stylename : item.style ? item.style : false,
42681 displayField: item.displayField ? item.displayField : 'val',
42682 valueField : 'val',
42684 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
42686 triggerAction: 'all',
42687 emptyText:'Select',
42688 selectOnFocus:true,
42689 width: item.width ? item.width : 130,
42691 'select': function(c, r, i) {
42693 tb.selectedNode.style[c.stylename] = r.get('val');
42696 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42705 tb.addField( new Roo.form.TextField({
42708 //allowBlank:false,
42713 tb.addField( new Roo.form.TextField({
42714 name: '-roo-edit-' + i,
42721 'change' : function(f, nv, ov) {
42722 tb.selectedNode.setAttribute(f.attrname, nv);
42731 text: 'Remove Tag',
42734 click : function ()
42737 // undo does not work.
42739 var sn = tb.selectedNode;
42741 var pn = sn.parentNode;
42743 var stn = sn.childNodes[0];
42744 var en = sn.childNodes[sn.childNodes.length - 1 ];
42745 while (sn.childNodes.length) {
42746 var node = sn.childNodes[0];
42747 sn.removeChild(node);
42749 pn.insertBefore(node, sn);
42752 pn.removeChild(sn);
42753 var range = editor.createRange();
42755 range.setStart(stn,0);
42756 range.setEnd(en,0); //????
42757 //range.selectNode(sel);
42760 var selection = editor.getSelection();
42761 selection.removeAllRanges();
42762 selection.addRange(range);
42766 //_this.updateToolbar(null, null, pn);
42767 _this.updateToolbar(null, null, null);
42768 _this.footDisp.dom.innerHTML = '';
42778 tb.el.on('click', function(e){
42779 e.preventDefault(); // what does this do?
42781 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42784 // dont need to disable them... as they will get hidden
42789 buildFooter : function()
42792 var fel = this.editor.wrap.createChild();
42793 this.footer = new Roo.Toolbar(fel);
42794 // toolbar has scrolly on left / right?
42795 var footDisp= new Roo.Toolbar.Fill();
42801 handler : function() {
42802 _t.footDisp.scrollTo('left',0,true)
42806 this.footer.add( footDisp );
42811 handler : function() {
42813 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
42817 var fel = Roo.get(footDisp.el);
42818 fel.addClass('x-editor-context');
42819 this.footDispWrap = fel;
42820 this.footDispWrap.overflow = 'hidden';
42822 this.footDisp = fel.createChild();
42823 this.footDispWrap.on('click', this.onContextClick, this)
42827 onContextClick : function (ev,dom)
42829 ev.preventDefault();
42830 var cn = dom.className;
42832 if (!cn.match(/x-ed-loc-/)) {
42835 var n = cn.split('-').pop();
42836 var ans = this.footerEls;
42840 var range = this.editor.createRange();
42842 range.selectNodeContents(sel);
42843 //range.selectNode(sel);
42846 var selection = this.editor.getSelection();
42847 selection.removeAllRanges();
42848 selection.addRange(range);
42852 this.updateToolbar(null, null, sel);
42869 * Ext JS Library 1.1.1
42870 * Copyright(c) 2006-2007, Ext JS, LLC.
42872 * Originally Released Under LGPL - original licence link has changed is not relivant.
42875 * <script type="text/javascript">
42879 * @class Roo.form.BasicForm
42880 * @extends Roo.util.Observable
42881 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
42883 * @param {String/HTMLElement/Roo.Element} el The form element or its id
42884 * @param {Object} config Configuration options
42886 Roo.form.BasicForm = function(el, config){
42887 this.allItems = [];
42888 this.childForms = [];
42889 Roo.apply(this, config);
42891 * The Roo.form.Field items in this form.
42892 * @type MixedCollection
42896 this.items = new Roo.util.MixedCollection(false, function(o){
42897 return o.id || (o.id = Roo.id());
42901 * @event beforeaction
42902 * Fires before any action is performed. Return false to cancel the action.
42903 * @param {Form} this
42904 * @param {Action} action The action to be performed
42906 beforeaction: true,
42908 * @event actionfailed
42909 * Fires when an action fails.
42910 * @param {Form} this
42911 * @param {Action} action The action that failed
42913 actionfailed : true,
42915 * @event actioncomplete
42916 * Fires when an action is completed.
42917 * @param {Form} this
42918 * @param {Action} action The action that completed
42920 actioncomplete : true
42925 Roo.form.BasicForm.superclass.constructor.call(this);
42928 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
42930 * @cfg {String} method
42931 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
42934 * @cfg {DataReader} reader
42935 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
42936 * This is optional as there is built-in support for processing JSON.
42939 * @cfg {DataReader} errorReader
42940 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
42941 * This is completely optional as there is built-in support for processing JSON.
42944 * @cfg {String} url
42945 * The URL to use for form actions if one isn't supplied in the action options.
42948 * @cfg {Boolean} fileUpload
42949 * Set to true if this form is a file upload.
42953 * @cfg {Object} baseParams
42954 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
42959 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
42964 activeAction : null,
42967 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
42968 * or setValues() data instead of when the form was first created.
42970 trackResetOnLoad : false,
42974 * childForms - used for multi-tab forms
42977 childForms : false,
42980 * allItems - full list of fields.
42986 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
42987 * element by passing it or its id or mask the form itself by passing in true.
42990 waitMsgTarget : false,
42993 initEl : function(el){
42994 this.el = Roo.get(el);
42995 this.id = this.el.id || Roo.id();
42996 this.el.on('submit', this.onSubmit, this);
42997 this.el.addClass('x-form');
43001 onSubmit : function(e){
43006 * Returns true if client-side validation on the form is successful.
43009 isValid : function(){
43011 this.items.each(function(f){
43020 * Returns true if any fields in this form have changed since their original load.
43023 isDirty : function(){
43025 this.items.each(function(f){
43035 * Performs a predefined action (submit or load) or custom actions you define on this form.
43036 * @param {String} actionName The name of the action type
43037 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43038 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43039 * accept other config options):
43041 Property Type Description
43042 ---------------- --------------- ----------------------------------------------------------------------------------
43043 url String The url for the action (defaults to the form's url)
43044 method String The form method to use (defaults to the form's method, or POST if not defined)
43045 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43046 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43047 validate the form on the client (defaults to false)
43049 * @return {BasicForm} this
43051 doAction : function(action, options){
43052 if(typeof action == 'string'){
43053 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43055 if(this.fireEvent('beforeaction', this, action) !== false){
43056 this.beforeAction(action);
43057 action.run.defer(100, action);
43063 * Shortcut to do a submit action.
43064 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43065 * @return {BasicForm} this
43067 submit : function(options){
43068 this.doAction('submit', options);
43073 * Shortcut to do a load action.
43074 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43075 * @return {BasicForm} this
43077 load : function(options){
43078 this.doAction('load', options);
43083 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43084 * @param {Record} record The record to edit
43085 * @return {BasicForm} this
43087 updateRecord : function(record){
43088 record.beginEdit();
43089 var fs = record.fields;
43090 fs.each(function(f){
43091 var field = this.findField(f.name);
43093 record.set(f.name, field.getValue());
43101 * Loads an Roo.data.Record into this form.
43102 * @param {Record} record The record to load
43103 * @return {BasicForm} this
43105 loadRecord : function(record){
43106 this.setValues(record.data);
43111 beforeAction : function(action){
43112 var o = action.options;
43115 if(this.waitMsgTarget === true){
43116 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43117 }else if(this.waitMsgTarget){
43118 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43119 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43121 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43127 afterAction : function(action, success){
43128 this.activeAction = null;
43129 var o = action.options;
43131 if(this.waitMsgTarget === true){
43133 }else if(this.waitMsgTarget){
43134 this.waitMsgTarget.unmask();
43136 Roo.MessageBox.updateProgress(1);
43137 Roo.MessageBox.hide();
43144 Roo.callback(o.success, o.scope, [this, action]);
43145 this.fireEvent('actioncomplete', this, action);
43149 // failure condition..
43150 // we have a scenario where updates need confirming.
43151 // eg. if a locking scenario exists..
43152 // we look for { errors : { needs_confirm : true }} in the response.
43154 (typeof(action.result) != 'undefined') &&
43155 (typeof(action.result.errors) != 'undefined') &&
43156 (typeof(action.result.errors.needs_confirm) != 'undefined')
43159 Roo.MessageBox.confirm(
43160 "Change requires confirmation",
43161 action.result.errorMsg,
43166 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43176 Roo.callback(o.failure, o.scope, [this, action]);
43177 // show an error message if no failed handler is set..
43178 if (!this.hasListener('actionfailed')) {
43179 Roo.MessageBox.alert("Error",
43180 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43181 action.result.errorMsg :
43182 "Saving Failed, please check your entries or try again"
43186 this.fireEvent('actionfailed', this, action);
43192 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43193 * @param {String} id The value to search for
43196 findField : function(id){
43197 var field = this.items.get(id);
43199 this.items.each(function(f){
43200 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43206 return field || null;
43210 * Add a secondary form to this one,
43211 * Used to provide tabbed forms. One form is primary, with hidden values
43212 * which mirror the elements from the other forms.
43214 * @param {Roo.form.Form} form to add.
43217 addForm : function(form)
43220 if (this.childForms.indexOf(form) > -1) {
43224 this.childForms.push(form);
43226 Roo.each(form.allItems, function (fe) {
43228 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43229 if (this.findField(n)) { // already added..
43232 var add = new Roo.form.Hidden({
43235 add.render(this.el);
43242 * Mark fields in this form invalid in bulk.
43243 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43244 * @return {BasicForm} this
43246 markInvalid : function(errors){
43247 if(errors instanceof Array){
43248 for(var i = 0, len = errors.length; i < len; i++){
43249 var fieldError = errors[i];
43250 var f = this.findField(fieldError.id);
43252 f.markInvalid(fieldError.msg);
43258 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43259 field.markInvalid(errors[id]);
43263 Roo.each(this.childForms || [], function (f) {
43264 f.markInvalid(errors);
43271 * Set values for fields in this form in bulk.
43272 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43273 * @return {BasicForm} this
43275 setValues : function(values){
43276 if(values instanceof Array){ // array of objects
43277 for(var i = 0, len = values.length; i < len; i++){
43279 var f = this.findField(v.id);
43281 f.setValue(v.value);
43282 if(this.trackResetOnLoad){
43283 f.originalValue = f.getValue();
43287 }else{ // object hash
43290 if(typeof values[id] != 'function' && (field = this.findField(id))){
43292 if (field.setFromData &&
43293 field.valueField &&
43294 field.displayField &&
43295 // combos' with local stores can
43296 // be queried via setValue()
43297 // to set their value..
43298 (field.store && !field.store.isLocal)
43302 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43303 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43304 field.setFromData(sd);
43307 field.setValue(values[id]);
43311 if(this.trackResetOnLoad){
43312 field.originalValue = field.getValue();
43318 Roo.each(this.childForms || [], function (f) {
43319 f.setValues(values);
43326 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43327 * they are returned as an array.
43328 * @param {Boolean} asString
43331 getValues : function(asString){
43332 if (this.childForms) {
43333 // copy values from the child forms
43334 Roo.each(this.childForms, function (f) {
43335 this.setValues(f.getValues());
43341 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43342 if(asString === true){
43345 return Roo.urlDecode(fs);
43349 * Returns the fields in this form as an object with key/value pairs.
43350 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43353 getFieldValues : function(with_hidden)
43355 if (this.childForms) {
43356 // copy values from the child forms
43357 // should this call getFieldValues - probably not as we do not currently copy
43358 // hidden fields when we generate..
43359 Roo.each(this.childForms, function (f) {
43360 this.setValues(f.getValues());
43365 this.items.each(function(f){
43366 if (!f.getName()) {
43369 var v = f.getValue();
43370 // not sure if this supported any more..
43371 if ((typeof(v) == 'object') && f.getRawValue) {
43372 v = f.getRawValue() ; // dates..
43374 // combo boxes where name != hiddenName...
43375 if (f.name != f.getName()) {
43376 ret[f.name] = f.getRawValue();
43378 ret[f.getName()] = v;
43385 * Clears all invalid messages in this form.
43386 * @return {BasicForm} this
43388 clearInvalid : function(){
43389 this.items.each(function(f){
43393 Roo.each(this.childForms || [], function (f) {
43402 * Resets this form.
43403 * @return {BasicForm} this
43405 reset : function(){
43406 this.items.each(function(f){
43410 Roo.each(this.childForms || [], function (f) {
43419 * Add Roo.form components to this form.
43420 * @param {Field} field1
43421 * @param {Field} field2 (optional)
43422 * @param {Field} etc (optional)
43423 * @return {BasicForm} this
43426 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43432 * Removes a field from the items collection (does NOT remove its markup).
43433 * @param {Field} field
43434 * @return {BasicForm} this
43436 remove : function(field){
43437 this.items.remove(field);
43442 * Looks at the fields in this form, checks them for an id attribute,
43443 * and calls applyTo on the existing dom element with that id.
43444 * @return {BasicForm} this
43446 render : function(){
43447 this.items.each(function(f){
43448 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43456 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43457 * @param {Object} values
43458 * @return {BasicForm} this
43460 applyToFields : function(o){
43461 this.items.each(function(f){
43468 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43469 * @param {Object} values
43470 * @return {BasicForm} this
43472 applyIfToFields : function(o){
43473 this.items.each(function(f){
43481 Roo.BasicForm = Roo.form.BasicForm;/*
43483 * Ext JS Library 1.1.1
43484 * Copyright(c) 2006-2007, Ext JS, LLC.
43486 * Originally Released Under LGPL - original licence link has changed is not relivant.
43489 * <script type="text/javascript">
43493 * @class Roo.form.Form
43494 * @extends Roo.form.BasicForm
43495 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43497 * @param {Object} config Configuration options
43499 Roo.form.Form = function(config){
43501 if (config.items) {
43502 xitems = config.items;
43503 delete config.items;
43507 Roo.form.Form.superclass.constructor.call(this, null, config);
43508 this.url = this.url || this.action;
43510 this.root = new Roo.form.Layout(Roo.applyIf({
43514 this.active = this.root;
43516 * Array of all the buttons that have been added to this form via {@link addButton}
43520 this.allItems = [];
43523 * @event clientvalidation
43524 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43525 * @param {Form} this
43526 * @param {Boolean} valid true if the form has passed client-side validation
43528 clientvalidation: true,
43531 * Fires when the form is rendered
43532 * @param {Roo.form.Form} form
43537 if (this.progressUrl) {
43538 // push a hidden field onto the list of fields..
43542 name : 'UPLOAD_IDENTIFIER'
43547 Roo.each(xitems, this.addxtype, this);
43553 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43555 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43558 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43561 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43563 buttonAlign:'center',
43566 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43571 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43572 * This property cascades to child containers if not set.
43577 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43578 * fires a looping event with that state. This is required to bind buttons to the valid
43579 * state using the config value formBind:true on the button.
43581 monitorValid : false,
43584 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43589 * @cfg {String} progressUrl - Url to return progress data
43592 progressUrl : false,
43595 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43596 * fields are added and the column is closed. If no fields are passed the column remains open
43597 * until end() is called.
43598 * @param {Object} config The config to pass to the column
43599 * @param {Field} field1 (optional)
43600 * @param {Field} field2 (optional)
43601 * @param {Field} etc (optional)
43602 * @return Column The column container object
43604 column : function(c){
43605 var col = new Roo.form.Column(c);
43607 if(arguments.length > 1){ // duplicate code required because of Opera
43608 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43615 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43616 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43617 * until end() is called.
43618 * @param {Object} config The config to pass to the fieldset
43619 * @param {Field} field1 (optional)
43620 * @param {Field} field2 (optional)
43621 * @param {Field} etc (optional)
43622 * @return FieldSet The fieldset container object
43624 fieldset : function(c){
43625 var fs = new Roo.form.FieldSet(c);
43627 if(arguments.length > 1){ // duplicate code required because of Opera
43628 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43635 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43636 * fields are added and the container is closed. If no fields are passed the container remains open
43637 * until end() is called.
43638 * @param {Object} config The config to pass to the Layout
43639 * @param {Field} field1 (optional)
43640 * @param {Field} field2 (optional)
43641 * @param {Field} etc (optional)
43642 * @return Layout The container object
43644 container : function(c){
43645 var l = new Roo.form.Layout(c);
43647 if(arguments.length > 1){ // duplicate code required because of Opera
43648 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43655 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43656 * @param {Object} container A Roo.form.Layout or subclass of Layout
43657 * @return {Form} this
43659 start : function(c){
43660 // cascade label info
43661 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43662 this.active.stack.push(c);
43663 c.ownerCt = this.active;
43669 * Closes the current open container
43670 * @return {Form} this
43673 if(this.active == this.root){
43676 this.active = this.active.ownerCt;
43681 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43682 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43683 * as the label of the field.
43684 * @param {Field} field1
43685 * @param {Field} field2 (optional)
43686 * @param {Field} etc. (optional)
43687 * @return {Form} this
43690 this.active.stack.push.apply(this.active.stack, arguments);
43691 this.allItems.push.apply(this.allItems,arguments);
43693 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43694 if(a[i].isFormField){
43699 Roo.form.Form.superclass.add.apply(this, r);
43709 * Find any element that has been added to a form, using it's ID or name
43710 * This can include framesets, columns etc. along with regular fields..
43711 * @param {String} id - id or name to find.
43713 * @return {Element} e - or false if nothing found.
43715 findbyId : function(id)
43721 Roo.each(this.allItems, function(f){
43722 if (f.id == id || f.name == id ){
43733 * Render this form into the passed container. This should only be called once!
43734 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43735 * @return {Form} this
43737 render : function(ct)
43743 var o = this.autoCreate || {
43745 method : this.method || 'POST',
43746 id : this.id || Roo.id()
43748 this.initEl(ct.createChild(o));
43750 this.root.render(this.el);
43754 this.items.each(function(f){
43755 f.render('x-form-el-'+f.id);
43758 if(this.buttons.length > 0){
43759 // tables are required to maintain order and for correct IE layout
43760 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43761 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43762 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43764 var tr = tb.getElementsByTagName('tr')[0];
43765 for(var i = 0, len = this.buttons.length; i < len; i++) {
43766 var b = this.buttons[i];
43767 var td = document.createElement('td');
43768 td.className = 'x-form-btn-td';
43769 b.render(tr.appendChild(td));
43772 if(this.monitorValid){ // initialize after render
43773 this.startMonitoring();
43775 this.fireEvent('rendered', this);
43780 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43781 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43782 * object or a valid Roo.DomHelper element config
43783 * @param {Function} handler The function called when the button is clicked
43784 * @param {Object} scope (optional) The scope of the handler function
43785 * @return {Roo.Button}
43787 addButton : function(config, handler, scope){
43791 minWidth: this.minButtonWidth,
43794 if(typeof config == "string"){
43797 Roo.apply(bc, config);
43799 var btn = new Roo.Button(null, bc);
43800 this.buttons.push(btn);
43805 * Adds a series of form elements (using the xtype property as the factory method.
43806 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
43807 * @param {Object} config
43810 addxtype : function()
43812 var ar = Array.prototype.slice.call(arguments, 0);
43814 for(var i = 0; i < ar.length; i++) {
43816 continue; // skip -- if this happends something invalid got sent, we
43817 // should ignore it, as basically that interface element will not show up
43818 // and that should be pretty obvious!!
43821 if (Roo.form[ar[i].xtype]) {
43823 var fe = Roo.factory(ar[i], Roo.form);
43829 fe.store.form = this;
43834 this.allItems.push(fe);
43835 if (fe.items && fe.addxtype) {
43836 fe.addxtype.apply(fe, fe.items);
43846 // console.log('adding ' + ar[i].xtype);
43848 if (ar[i].xtype == 'Button') {
43849 //console.log('adding button');
43850 //console.log(ar[i]);
43851 this.addButton(ar[i]);
43852 this.allItems.push(fe);
43856 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
43857 alert('end is not supported on xtype any more, use items');
43859 // //console.log('adding end');
43867 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
43868 * option "monitorValid"
43870 startMonitoring : function(){
43873 Roo.TaskMgr.start({
43874 run : this.bindHandler,
43875 interval : this.monitorPoll || 200,
43882 * Stops monitoring of the valid state of this form
43884 stopMonitoring : function(){
43885 this.bound = false;
43889 bindHandler : function(){
43891 return false; // stops binding
43894 this.items.each(function(f){
43895 if(!f.isValid(true)){
43900 for(var i = 0, len = this.buttons.length; i < len; i++){
43901 var btn = this.buttons[i];
43902 if(btn.formBind === true && btn.disabled === valid){
43903 btn.setDisabled(!valid);
43906 this.fireEvent('clientvalidation', this, valid);
43920 Roo.Form = Roo.form.Form;
43923 * Ext JS Library 1.1.1
43924 * Copyright(c) 2006-2007, Ext JS, LLC.
43926 * Originally Released Under LGPL - original licence link has changed is not relivant.
43929 * <script type="text/javascript">
43933 * @class Roo.form.Action
43934 * Internal Class used to handle form actions
43936 * @param {Roo.form.BasicForm} el The form element or its id
43937 * @param {Object} config Configuration options
43941 // define the action interface
43942 Roo.form.Action = function(form, options){
43944 this.options = options || {};
43947 * Client Validation Failed
43950 Roo.form.Action.CLIENT_INVALID = 'client';
43952 * Server Validation Failed
43955 Roo.form.Action.SERVER_INVALID = 'server';
43957 * Connect to Server Failed
43960 Roo.form.Action.CONNECT_FAILURE = 'connect';
43962 * Reading Data from Server Failed
43965 Roo.form.Action.LOAD_FAILURE = 'load';
43967 Roo.form.Action.prototype = {
43969 failureType : undefined,
43970 response : undefined,
43971 result : undefined,
43973 // interface method
43974 run : function(options){
43978 // interface method
43979 success : function(response){
43983 // interface method
43984 handleResponse : function(response){
43988 // default connection failure
43989 failure : function(response){
43991 this.response = response;
43992 this.failureType = Roo.form.Action.CONNECT_FAILURE;
43993 this.form.afterAction(this, false);
43996 processResponse : function(response){
43997 this.response = response;
43998 if(!response.responseText){
44001 this.result = this.handleResponse(response);
44002 return this.result;
44005 // utility functions used internally
44006 getUrl : function(appendParams){
44007 var url = this.options.url || this.form.url || this.form.el.dom.action;
44009 var p = this.getParams();
44011 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44017 getMethod : function(){
44018 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44021 getParams : function(){
44022 var bp = this.form.baseParams;
44023 var p = this.options.params;
44025 if(typeof p == "object"){
44026 p = Roo.urlEncode(Roo.applyIf(p, bp));
44027 }else if(typeof p == 'string' && bp){
44028 p += '&' + Roo.urlEncode(bp);
44031 p = Roo.urlEncode(bp);
44036 createCallback : function(){
44038 success: this.success,
44039 failure: this.failure,
44041 timeout: (this.form.timeout*1000),
44042 upload: this.form.fileUpload ? this.success : undefined
44047 Roo.form.Action.Submit = function(form, options){
44048 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44051 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44054 haveProgress : false,
44055 uploadComplete : false,
44057 // uploadProgress indicator.
44058 uploadProgress : function()
44060 if (!this.form.progressUrl) {
44064 if (!this.haveProgress) {
44065 Roo.MessageBox.progress("Uploading", "Uploading");
44067 if (this.uploadComplete) {
44068 Roo.MessageBox.hide();
44072 this.haveProgress = true;
44074 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44076 var c = new Roo.data.Connection();
44078 url : this.form.progressUrl,
44083 success : function(req){
44084 //console.log(data);
44088 rdata = Roo.decode(req.responseText)
44090 Roo.log("Invalid data from server..");
44094 if (!rdata || !rdata.success) {
44096 Roo.MessageBox.alert(Roo.encode(rdata));
44099 var data = rdata.data;
44101 if (this.uploadComplete) {
44102 Roo.MessageBox.hide();
44107 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44108 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44111 this.uploadProgress.defer(2000,this);
44114 failure: function(data) {
44115 Roo.log('progress url failed ');
44126 // run get Values on the form, so it syncs any secondary forms.
44127 this.form.getValues();
44129 var o = this.options;
44130 var method = this.getMethod();
44131 var isPost = method == 'POST';
44132 if(o.clientValidation === false || this.form.isValid()){
44134 if (this.form.progressUrl) {
44135 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44136 (new Date() * 1) + '' + Math.random());
44141 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44142 form:this.form.el.dom,
44143 url:this.getUrl(!isPost),
44145 params:isPost ? this.getParams() : null,
44146 isUpload: this.form.fileUpload
44149 this.uploadProgress();
44151 }else if (o.clientValidation !== false){ // client validation failed
44152 this.failureType = Roo.form.Action.CLIENT_INVALID;
44153 this.form.afterAction(this, false);
44157 success : function(response)
44159 this.uploadComplete= true;
44160 if (this.haveProgress) {
44161 Roo.MessageBox.hide();
44165 var result = this.processResponse(response);
44166 if(result === true || result.success){
44167 this.form.afterAction(this, true);
44171 this.form.markInvalid(result.errors);
44172 this.failureType = Roo.form.Action.SERVER_INVALID;
44174 this.form.afterAction(this, false);
44176 failure : function(response)
44178 this.uploadComplete= true;
44179 if (this.haveProgress) {
44180 Roo.MessageBox.hide();
44183 this.response = response;
44184 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44185 this.form.afterAction(this, false);
44188 handleResponse : function(response){
44189 if(this.form.errorReader){
44190 var rs = this.form.errorReader.read(response);
44193 for(var i = 0, len = rs.records.length; i < len; i++) {
44194 var r = rs.records[i];
44195 errors[i] = r.data;
44198 if(errors.length < 1){
44202 success : rs.success,
44208 ret = Roo.decode(response.responseText);
44212 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44222 Roo.form.Action.Load = function(form, options){
44223 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44224 this.reader = this.form.reader;
44227 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44232 Roo.Ajax.request(Roo.apply(
44233 this.createCallback(), {
44234 method:this.getMethod(),
44235 url:this.getUrl(false),
44236 params:this.getParams()
44240 success : function(response){
44242 var result = this.processResponse(response);
44243 if(result === true || !result.success || !result.data){
44244 this.failureType = Roo.form.Action.LOAD_FAILURE;
44245 this.form.afterAction(this, false);
44248 this.form.clearInvalid();
44249 this.form.setValues(result.data);
44250 this.form.afterAction(this, true);
44253 handleResponse : function(response){
44254 if(this.form.reader){
44255 var rs = this.form.reader.read(response);
44256 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44258 success : rs.success,
44262 return Roo.decode(response.responseText);
44266 Roo.form.Action.ACTION_TYPES = {
44267 'load' : Roo.form.Action.Load,
44268 'submit' : Roo.form.Action.Submit
44271 * Ext JS Library 1.1.1
44272 * Copyright(c) 2006-2007, Ext JS, LLC.
44274 * Originally Released Under LGPL - original licence link has changed is not relivant.
44277 * <script type="text/javascript">
44281 * @class Roo.form.Layout
44282 * @extends Roo.Component
44283 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44285 * @param {Object} config Configuration options
44287 Roo.form.Layout = function(config){
44289 if (config.items) {
44290 xitems = config.items;
44291 delete config.items;
44293 Roo.form.Layout.superclass.constructor.call(this, config);
44295 Roo.each(xitems, this.addxtype, this);
44299 Roo.extend(Roo.form.Layout, Roo.Component, {
44301 * @cfg {String/Object} autoCreate
44302 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44305 * @cfg {String/Object/Function} style
44306 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44307 * a function which returns such a specification.
44310 * @cfg {String} labelAlign
44311 * Valid values are "left," "top" and "right" (defaults to "left")
44314 * @cfg {Number} labelWidth
44315 * Fixed width in pixels of all field labels (defaults to undefined)
44318 * @cfg {Boolean} clear
44319 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44323 * @cfg {String} labelSeparator
44324 * The separator to use after field labels (defaults to ':')
44326 labelSeparator : ':',
44328 * @cfg {Boolean} hideLabels
44329 * True to suppress the display of field labels in this layout (defaults to false)
44331 hideLabels : false,
44334 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44339 onRender : function(ct, position){
44340 if(this.el){ // from markup
44341 this.el = Roo.get(this.el);
44342 }else { // generate
44343 var cfg = this.getAutoCreate();
44344 this.el = ct.createChild(cfg, position);
44347 this.el.applyStyles(this.style);
44349 if(this.labelAlign){
44350 this.el.addClass('x-form-label-'+this.labelAlign);
44352 if(this.hideLabels){
44353 this.labelStyle = "display:none";
44354 this.elementStyle = "padding-left:0;";
44356 if(typeof this.labelWidth == 'number'){
44357 this.labelStyle = "width:"+this.labelWidth+"px;";
44358 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44360 if(this.labelAlign == 'top'){
44361 this.labelStyle = "width:auto;";
44362 this.elementStyle = "padding-left:0;";
44365 var stack = this.stack;
44366 var slen = stack.length;
44368 if(!this.fieldTpl){
44369 var t = new Roo.Template(
44370 '<div class="x-form-item {5}">',
44371 '<label for="{0}" style="{2}">{1}{4}</label>',
44372 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44374 '</div><div class="x-form-clear-left"></div>'
44376 t.disableFormats = true;
44378 Roo.form.Layout.prototype.fieldTpl = t;
44380 for(var i = 0; i < slen; i++) {
44381 if(stack[i].isFormField){
44382 this.renderField(stack[i]);
44384 this.renderComponent(stack[i]);
44389 this.el.createChild({cls:'x-form-clear'});
44394 renderField : function(f){
44395 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44398 f.labelStyle||this.labelStyle||'', //2
44399 this.elementStyle||'', //3
44400 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44401 f.itemCls||this.itemCls||'' //5
44402 ], true).getPrevSibling());
44406 renderComponent : function(c){
44407 c.render(c.isLayout ? this.el : this.el.createChild());
44410 * Adds a object form elements (using the xtype property as the factory method.)
44411 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44412 * @param {Object} config
44414 addxtype : function(o)
44416 // create the lement.
44417 o.form = this.form;
44418 var fe = Roo.factory(o, Roo.form);
44419 this.form.allItems.push(fe);
44420 this.stack.push(fe);
44422 if (fe.isFormField) {
44423 this.form.items.add(fe);
44431 * @class Roo.form.Column
44432 * @extends Roo.form.Layout
44433 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44435 * @param {Object} config Configuration options
44437 Roo.form.Column = function(config){
44438 Roo.form.Column.superclass.constructor.call(this, config);
44441 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44443 * @cfg {Number/String} width
44444 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44447 * @cfg {String/Object} autoCreate
44448 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44452 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44455 onRender : function(ct, position){
44456 Roo.form.Column.superclass.onRender.call(this, ct, position);
44458 this.el.setWidth(this.width);
44465 * @class Roo.form.Row
44466 * @extends Roo.form.Layout
44467 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44469 * @param {Object} config Configuration options
44473 Roo.form.Row = function(config){
44474 Roo.form.Row.superclass.constructor.call(this, config);
44477 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44479 * @cfg {Number/String} width
44480 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44483 * @cfg {Number/String} height
44484 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44486 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44490 onRender : function(ct, position){
44491 //console.log('row render');
44493 var t = new Roo.Template(
44494 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44495 '<label for="{0}" style="{2}">{1}{4}</label>',
44496 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44500 t.disableFormats = true;
44502 Roo.form.Layout.prototype.rowTpl = t;
44504 this.fieldTpl = this.rowTpl;
44506 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44507 var labelWidth = 100;
44509 if ((this.labelAlign != 'top')) {
44510 if (typeof this.labelWidth == 'number') {
44511 labelWidth = this.labelWidth
44513 this.padWidth = 20 + labelWidth;
44517 Roo.form.Column.superclass.onRender.call(this, ct, position);
44519 this.el.setWidth(this.width);
44522 this.el.setHeight(this.height);
44527 renderField : function(f){
44528 f.fieldEl = this.fieldTpl.append(this.el, [
44529 f.id, f.fieldLabel,
44530 f.labelStyle||this.labelStyle||'',
44531 this.elementStyle||'',
44532 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44533 f.itemCls||this.itemCls||'',
44534 f.width ? f.width + this.padWidth : 160 + this.padWidth
44541 * @class Roo.form.FieldSet
44542 * @extends Roo.form.Layout
44543 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44545 * @param {Object} config Configuration options
44547 Roo.form.FieldSet = function(config){
44548 Roo.form.FieldSet.superclass.constructor.call(this, config);
44551 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44553 * @cfg {String} legend
44554 * The text to display as the legend for the FieldSet (defaults to '')
44557 * @cfg {String/Object} autoCreate
44558 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44562 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44565 onRender : function(ct, position){
44566 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44568 this.setLegend(this.legend);
44573 setLegend : function(text){
44575 this.el.child('legend').update(text);
44580 * Ext JS Library 1.1.1
44581 * Copyright(c) 2006-2007, Ext JS, LLC.
44583 * Originally Released Under LGPL - original licence link has changed is not relivant.
44586 * <script type="text/javascript">
44589 * @class Roo.form.VTypes
44590 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44593 Roo.form.VTypes = function(){
44594 // closure these in so they are only created once.
44595 var alpha = /^[a-zA-Z_]+$/;
44596 var alphanum = /^[a-zA-Z0-9_]+$/;
44597 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44598 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44600 // All these messages and functions are configurable
44603 * The function used to validate email addresses
44604 * @param {String} value The email address
44606 'email' : function(v){
44607 return email.test(v);
44610 * The error text to display when the email validation function returns false
44613 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44615 * The keystroke filter mask to be applied on email input
44618 'emailMask' : /[a-z0-9_\.\-@]/i,
44621 * The function used to validate URLs
44622 * @param {String} value The URL
44624 'url' : function(v){
44625 return url.test(v);
44628 * The error text to display when the url validation function returns false
44631 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44634 * The function used to validate alpha values
44635 * @param {String} value The value
44637 'alpha' : function(v){
44638 return alpha.test(v);
44641 * The error text to display when the alpha validation function returns false
44644 'alphaText' : 'This field should only contain letters and _',
44646 * The keystroke filter mask to be applied on alpha input
44649 'alphaMask' : /[a-z_]/i,
44652 * The function used to validate alphanumeric values
44653 * @param {String} value The value
44655 'alphanum' : function(v){
44656 return alphanum.test(v);
44659 * The error text to display when the alphanumeric validation function returns false
44662 'alphanumText' : 'This field should only contain letters, numbers and _',
44664 * The keystroke filter mask to be applied on alphanumeric input
44667 'alphanumMask' : /[a-z0-9_]/i
44669 }();//<script type="text/javascript">
44672 * @class Roo.form.FCKeditor
44673 * @extends Roo.form.TextArea
44674 * Wrapper around the FCKEditor http://www.fckeditor.net
44676 * Creates a new FCKeditor
44677 * @param {Object} config Configuration options
44679 Roo.form.FCKeditor = function(config){
44680 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44683 * @event editorinit
44684 * Fired when the editor is initialized - you can add extra handlers here..
44685 * @param {FCKeditor} this
44686 * @param {Object} the FCK object.
44693 Roo.form.FCKeditor.editors = { };
44694 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44696 //defaultAutoCreate : {
44697 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44701 * @cfg {Object} fck options - see fck manual for details.
44706 * @cfg {Object} fck toolbar set (Basic or Default)
44708 toolbarSet : 'Basic',
44710 * @cfg {Object} fck BasePath
44712 basePath : '/fckeditor/',
44720 onRender : function(ct, position)
44723 this.defaultAutoCreate = {
44725 style:"width:300px;height:60px;",
44726 autocomplete: "off"
44729 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44732 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44733 if(this.preventScrollbars){
44734 this.el.setStyle("overflow", "hidden");
44736 this.el.setHeight(this.growMin);
44739 //console.log('onrender' + this.getId() );
44740 Roo.form.FCKeditor.editors[this.getId()] = this;
44743 this.replaceTextarea() ;
44747 getEditor : function() {
44748 return this.fckEditor;
44751 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44752 * @param {Mixed} value The value to set
44756 setValue : function(value)
44758 //console.log('setValue: ' + value);
44760 if(typeof(value) == 'undefined') { // not sure why this is happending...
44763 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44765 //if(!this.el || !this.getEditor()) {
44766 // this.value = value;
44767 //this.setValue.defer(100,this,[value]);
44771 if(!this.getEditor()) {
44775 this.getEditor().SetData(value);
44782 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44783 * @return {Mixed} value The field value
44785 getValue : function()
44788 if (this.frame && this.frame.dom.style.display == 'none') {
44789 return Roo.form.FCKeditor.superclass.getValue.call(this);
44792 if(!this.el || !this.getEditor()) {
44794 // this.getValue.defer(100,this);
44799 var value=this.getEditor().GetData();
44800 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44801 return Roo.form.FCKeditor.superclass.getValue.call(this);
44807 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
44808 * @return {Mixed} value The field value
44810 getRawValue : function()
44812 if (this.frame && this.frame.dom.style.display == 'none') {
44813 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44816 if(!this.el || !this.getEditor()) {
44817 //this.getRawValue.defer(100,this);
44824 var value=this.getEditor().GetData();
44825 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
44826 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
44830 setSize : function(w,h) {
44834 //if (this.frame && this.frame.dom.style.display == 'none') {
44835 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44838 //if(!this.el || !this.getEditor()) {
44839 // this.setSize.defer(100,this, [w,h]);
44845 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
44847 this.frame.dom.setAttribute('width', w);
44848 this.frame.dom.setAttribute('height', h);
44849 this.frame.setSize(w,h);
44853 toggleSourceEdit : function(value) {
44857 this.el.dom.style.display = value ? '' : 'none';
44858 this.frame.dom.style.display = value ? 'none' : '';
44863 focus: function(tag)
44865 if (this.frame.dom.style.display == 'none') {
44866 return Roo.form.FCKeditor.superclass.focus.call(this);
44868 if(!this.el || !this.getEditor()) {
44869 this.focus.defer(100,this, [tag]);
44876 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
44877 this.getEditor().Focus();
44879 if (!this.getEditor().Selection.GetSelection()) {
44880 this.focus.defer(100,this, [tag]);
44885 var r = this.getEditor().EditorDocument.createRange();
44886 r.setStart(tgs[0],0);
44887 r.setEnd(tgs[0],0);
44888 this.getEditor().Selection.GetSelection().removeAllRanges();
44889 this.getEditor().Selection.GetSelection().addRange(r);
44890 this.getEditor().Focus();
44897 replaceTextarea : function()
44899 if ( document.getElementById( this.getId() + '___Frame' ) )
44901 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
44903 // We must check the elements firstly using the Id and then the name.
44904 var oTextarea = document.getElementById( this.getId() );
44906 var colElementsByName = document.getElementsByName( this.getId() ) ;
44908 oTextarea.style.display = 'none' ;
44910 if ( oTextarea.tabIndex ) {
44911 this.TabIndex = oTextarea.tabIndex ;
44914 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
44915 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
44916 this.frame = Roo.get(this.getId() + '___Frame')
44919 _getConfigHtml : function()
44923 for ( var o in this.fckconfig ) {
44924 sConfig += sConfig.length > 0 ? '&' : '';
44925 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
44928 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
44932 _getIFrameHtml : function()
44934 var sFile = 'fckeditor.html' ;
44935 /* no idea what this is about..
44938 if ( (/fcksource=true/i).test( window.top.location.search ) )
44939 sFile = 'fckeditor.original.html' ;
44944 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
44945 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
44948 var html = '<iframe id="' + this.getId() +
44949 '___Frame" src="' + sLink +
44950 '" width="' + this.width +
44951 '" height="' + this.height + '"' +
44952 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
44953 ' frameborder="0" scrolling="no"></iframe>' ;
44958 _insertHtmlBefore : function( html, element )
44960 if ( element.insertAdjacentHTML ) {
44962 element.insertAdjacentHTML( 'beforeBegin', html ) ;
44964 var oRange = document.createRange() ;
44965 oRange.setStartBefore( element ) ;
44966 var oFragment = oRange.createContextualFragment( html );
44967 element.parentNode.insertBefore( oFragment, element ) ;
44980 //Roo.reg('fckeditor', Roo.form.FCKeditor);
44982 function FCKeditor_OnComplete(editorInstance){
44983 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
44984 f.fckEditor = editorInstance;
44985 //console.log("loaded");
44986 f.fireEvent('editorinit', f, editorInstance);
45006 //<script type="text/javascript">
45008 * @class Roo.form.GridField
45009 * @extends Roo.form.Field
45010 * Embed a grid (or editable grid into a form)
45013 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45015 * xgrid.store = Roo.data.Store
45016 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45017 * xgrid.store.reader = Roo.data.JsonReader
45021 * Creates a new GridField
45022 * @param {Object} config Configuration options
45024 Roo.form.GridField = function(config){
45025 Roo.form.GridField.superclass.constructor.call(this, config);
45029 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45031 * @cfg {Number} width - used to restrict width of grid..
45035 * @cfg {Number} height - used to restrict height of grid..
45039 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45045 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45046 * {tag: "input", type: "checkbox", autocomplete: "off"})
45048 // defaultAutoCreate : { tag: 'div' },
45049 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45051 * @cfg {String} addTitle Text to include for adding a title.
45055 onResize : function(){
45056 Roo.form.Field.superclass.onResize.apply(this, arguments);
45059 initEvents : function(){
45060 // Roo.form.Checkbox.superclass.initEvents.call(this);
45061 // has no events...
45066 getResizeEl : function(){
45070 getPositionEl : function(){
45075 onRender : function(ct, position){
45077 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45078 var style = this.style;
45081 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45082 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45083 this.viewEl = this.wrap.createChild({ tag: 'div' });
45085 this.viewEl.applyStyles(style);
45088 this.viewEl.setWidth(this.width);
45091 this.viewEl.setHeight(this.height);
45093 //if(this.inputValue !== undefined){
45094 //this.setValue(this.value);
45097 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45100 this.grid.render();
45101 this.grid.getDataSource().on('remove', this.refreshValue, this);
45102 this.grid.getDataSource().on('update', this.refreshValue, this);
45103 this.grid.on('afteredit', this.refreshValue, this);
45109 * Sets the value of the item.
45110 * @param {String} either an object or a string..
45112 setValue : function(v){
45114 v = v || []; // empty set..
45115 // this does not seem smart - it really only affects memoryproxy grids..
45116 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45117 var ds = this.grid.getDataSource();
45118 // assumes a json reader..
45120 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45121 ds.loadData( data);
45123 // clear selection so it does not get stale.
45124 if (this.grid.sm) {
45125 this.grid.sm.clearSelections();
45128 Roo.form.GridField.superclass.setValue.call(this, v);
45129 this.refreshValue();
45130 // should load data in the grid really....
45134 refreshValue: function() {
45136 this.grid.getDataSource().each(function(r) {
45139 this.el.dom.value = Roo.encode(val);
45147 * Ext JS Library 1.1.1
45148 * Copyright(c) 2006-2007, Ext JS, LLC.
45150 * Originally Released Under LGPL - original licence link has changed is not relivant.
45153 * <script type="text/javascript">
45156 * @class Roo.form.DisplayField
45157 * @extends Roo.form.Field
45158 * A generic Field to display non-editable data.
45160 * Creates a new Display Field item.
45161 * @param {Object} config Configuration options
45163 Roo.form.DisplayField = function(config){
45164 Roo.form.DisplayField.superclass.constructor.call(this, config);
45168 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45169 inputType: 'hidden',
45175 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45177 focusClass : undefined,
45179 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45181 fieldClass: 'x-form-field',
45184 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45186 valueRenderer: undefined,
45190 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45191 * {tag: "input", type: "checkbox", autocomplete: "off"})
45194 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45196 onResize : function(){
45197 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45201 initEvents : function(){
45202 // Roo.form.Checkbox.superclass.initEvents.call(this);
45203 // has no events...
45208 getResizeEl : function(){
45212 getPositionEl : function(){
45217 onRender : function(ct, position){
45219 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45220 //if(this.inputValue !== undefined){
45221 this.wrap = this.el.wrap();
45223 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45225 if (this.bodyStyle) {
45226 this.viewEl.applyStyles(this.bodyStyle);
45228 //this.viewEl.setStyle('padding', '2px');
45230 this.setValue(this.value);
45235 initValue : Roo.emptyFn,
45240 onClick : function(){
45245 * Sets the checked state of the checkbox.
45246 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45248 setValue : function(v){
45250 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45251 // this might be called before we have a dom element..
45252 if (!this.viewEl) {
45255 this.viewEl.dom.innerHTML = html;
45256 Roo.form.DisplayField.superclass.setValue.call(this, v);
45266 * @class Roo.form.DayPicker
45267 * @extends Roo.form.Field
45268 * A Day picker show [M] [T] [W] ....
45270 * Creates a new Day Picker
45271 * @param {Object} config Configuration options
45273 Roo.form.DayPicker= function(config){
45274 Roo.form.DayPicker.superclass.constructor.call(this, config);
45278 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45280 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45282 focusClass : undefined,
45284 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45286 fieldClass: "x-form-field",
45289 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45290 * {tag: "input", type: "checkbox", autocomplete: "off"})
45292 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45295 actionMode : 'viewEl',
45299 inputType : 'hidden',
45302 inputElement: false, // real input element?
45303 basedOn: false, // ????
45305 isFormField: true, // not sure where this is needed!!!!
45307 onResize : function(){
45308 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45309 if(!this.boxLabel){
45310 this.el.alignTo(this.wrap, 'c-c');
45314 initEvents : function(){
45315 Roo.form.Checkbox.superclass.initEvents.call(this);
45316 this.el.on("click", this.onClick, this);
45317 this.el.on("change", this.onClick, this);
45321 getResizeEl : function(){
45325 getPositionEl : function(){
45331 onRender : function(ct, position){
45332 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45334 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45336 var r1 = '<table><tr>';
45337 var r2 = '<tr class="x-form-daypick-icons">';
45338 for (var i=0; i < 7; i++) {
45339 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45340 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45343 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45344 viewEl.select('img').on('click', this.onClick, this);
45345 this.viewEl = viewEl;
45348 // this will not work on Chrome!!!
45349 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45350 this.el.on('propertychange', this.setFromHidden, this); //ie
45358 initValue : Roo.emptyFn,
45361 * Returns the checked state of the checkbox.
45362 * @return {Boolean} True if checked, else false
45364 getValue : function(){
45365 return this.el.dom.value;
45370 onClick : function(e){
45371 //this.setChecked(!this.checked);
45372 Roo.get(e.target).toggleClass('x-menu-item-checked');
45373 this.refreshValue();
45374 //if(this.el.dom.checked != this.checked){
45375 // this.setValue(this.el.dom.checked);
45380 refreshValue : function()
45383 this.viewEl.select('img',true).each(function(e,i,n) {
45384 val += e.is(".x-menu-item-checked") ? String(n) : '';
45386 this.setValue(val, true);
45390 * Sets the checked state of the checkbox.
45391 * On is always based on a string comparison between inputValue and the param.
45392 * @param {Boolean/String} value - the value to set
45393 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45395 setValue : function(v,suppressEvent){
45396 if (!this.el.dom) {
45399 var old = this.el.dom.value ;
45400 this.el.dom.value = v;
45401 if (suppressEvent) {
45405 // update display..
45406 this.viewEl.select('img',true).each(function(e,i,n) {
45408 var on = e.is(".x-menu-item-checked");
45409 var newv = v.indexOf(String(n)) > -1;
45411 e.toggleClass('x-menu-item-checked');
45417 this.fireEvent('change', this, v, old);
45422 // handle setting of hidden value by some other method!!?!?
45423 setFromHidden: function()
45428 //console.log("SET FROM HIDDEN");
45429 //alert('setFrom hidden');
45430 this.setValue(this.el.dom.value);
45433 onDestroy : function()
45436 Roo.get(this.viewEl).remove();
45439 Roo.form.DayPicker.superclass.onDestroy.call(this);
45443 * RooJS Library 1.1.1
45444 * Copyright(c) 2008-2011 Alan Knowles
45451 * @class Roo.form.ComboCheck
45452 * @extends Roo.form.ComboBox
45453 * A combobox for multiple select items.
45455 * FIXME - could do with a reset button..
45458 * Create a new ComboCheck
45459 * @param {Object} config Configuration options
45461 Roo.form.ComboCheck = function(config){
45462 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45463 // should verify some data...
45465 // hiddenName = required..
45466 // displayField = required
45467 // valudField == required
45468 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45470 Roo.each(req, function(e) {
45471 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45472 throw "Roo.form.ComboCheck : missing value for: " + e;
45479 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45484 selectedClass: 'x-menu-item-checked',
45487 onRender : function(ct, position){
45493 var cls = 'x-combo-list';
45496 this.tpl = new Roo.Template({
45497 html : '<div class="'+cls+'-item x-menu-check-item">' +
45498 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45499 '<span>{' + this.displayField + '}</span>' +
45506 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45507 this.view.singleSelect = false;
45508 this.view.multiSelect = true;
45509 this.view.toggleSelect = true;
45510 this.pageTb.add(new Roo.Toolbar.Fill(), {
45513 handler: function()
45520 onViewOver : function(e, t){
45526 onViewClick : function(doFocus,index){
45530 select: function () {
45531 //Roo.log("SELECT CALLED");
45534 selectByValue : function(xv, scrollIntoView){
45535 var ar = this.getValueArray();
45538 Roo.each(ar, function(v) {
45539 if(v === undefined || v === null){
45542 var r = this.findRecord(this.valueField, v);
45544 sels.push(this.store.indexOf(r))
45548 this.view.select(sels);
45554 onSelect : function(record, index){
45555 // Roo.log("onselect Called");
45556 // this is only called by the clear button now..
45557 this.view.clearSelections();
45558 this.setValue('[]');
45559 if (this.value != this.valueBefore) {
45560 this.fireEvent('change', this, this.value, this.valueBefore);
45561 this.valueBefore = this.value;
45564 getValueArray : function()
45569 //Roo.log(this.value);
45570 if (typeof(this.value) == 'undefined') {
45573 var ar = Roo.decode(this.value);
45574 return ar instanceof Array ? ar : []; //?? valid?
45577 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45582 expand : function ()
45585 Roo.form.ComboCheck.superclass.expand.call(this);
45586 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
45587 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
45592 collapse : function(){
45593 Roo.form.ComboCheck.superclass.collapse.call(this);
45594 var sl = this.view.getSelectedIndexes();
45595 var st = this.store;
45599 Roo.each(sl, function(i) {
45601 nv.push(r.get(this.valueField));
45603 this.setValue(Roo.encode(nv));
45604 if (this.value != this.valueBefore) {
45606 this.fireEvent('change', this, this.value, this.valueBefore);
45607 this.valueBefore = this.value;
45612 setValue : function(v){
45616 var vals = this.getValueArray();
45618 Roo.each(vals, function(k) {
45619 var r = this.findRecord(this.valueField, k);
45621 tv.push(r.data[this.displayField]);
45622 }else if(this.valueNotFoundText !== undefined){
45623 tv.push( this.valueNotFoundText );
45628 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45629 this.hiddenField.value = v;
45633 });//<script type="text/javasscript">
45637 * @class Roo.DDView
45638 * A DnD enabled version of Roo.View.
45639 * @param {Element/String} container The Element in which to create the View.
45640 * @param {String} tpl The template string used to create the markup for each element of the View
45641 * @param {Object} config The configuration properties. These include all the config options of
45642 * {@link Roo.View} plus some specific to this class.<br>
45644 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
45645 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
45647 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
45648 .x-view-drag-insert-above {
45649 border-top:1px dotted #3366cc;
45651 .x-view-drag-insert-below {
45652 border-bottom:1px dotted #3366cc;
45658 Roo.DDView = function(container, tpl, config) {
45659 Roo.DDView.superclass.constructor.apply(this, arguments);
45660 this.getEl().setStyle("outline", "0px none");
45661 this.getEl().unselectable();
45662 if (this.dragGroup) {
45663 this.setDraggable(this.dragGroup.split(","));
45665 if (this.dropGroup) {
45666 this.setDroppable(this.dropGroup.split(","));
45668 if (this.deletable) {
45669 this.setDeletable();
45671 this.isDirtyFlag = false;
45677 Roo.extend(Roo.DDView, Roo.View, {
45678 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
45679 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
45680 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
45681 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
45685 reset: Roo.emptyFn,
45687 clearInvalid: Roo.form.Field.prototype.clearInvalid,
45689 validate: function() {
45693 destroy: function() {
45694 this.purgeListeners();
45695 this.getEl.removeAllListeners();
45696 this.getEl().remove();
45697 if (this.dragZone) {
45698 if (this.dragZone.destroy) {
45699 this.dragZone.destroy();
45702 if (this.dropZone) {
45703 if (this.dropZone.destroy) {
45704 this.dropZone.destroy();
45709 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
45710 getName: function() {
45714 /** Loads the View from a JSON string representing the Records to put into the Store. */
45715 setValue: function(v) {
45717 throw "DDView.setValue(). DDView must be constructed with a valid Store";
45720 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
45721 this.store.proxy = new Roo.data.MemoryProxy(data);
45725 /** @return {String} a parenthesised list of the ids of the Records in the View. */
45726 getValue: function() {
45728 this.store.each(function(rec) {
45729 result += rec.id + ',';
45731 return result.substr(0, result.length - 1) + ')';
45734 getIds: function() {
45735 var i = 0, result = new Array(this.store.getCount());
45736 this.store.each(function(rec) {
45737 result[i++] = rec.id;
45742 isDirty: function() {
45743 return this.isDirtyFlag;
45747 * Part of the Roo.dd.DropZone interface. If no target node is found, the
45748 * whole Element becomes the target, and this causes the drop gesture to append.
45750 getTargetFromEvent : function(e) {
45751 var target = e.getTarget();
45752 while ((target !== null) && (target.parentNode != this.el.dom)) {
45753 target = target.parentNode;
45756 target = this.el.dom.lastChild || this.el.dom;
45762 * Create the drag data which consists of an object which has the property "ddel" as
45763 * the drag proxy element.
45765 getDragData : function(e) {
45766 var target = this.findItemFromChild(e.getTarget());
45768 this.handleSelection(e);
45769 var selNodes = this.getSelectedNodes();
45772 copy: this.copy || (this.allowCopy && e.ctrlKey),
45776 var selectedIndices = this.getSelectedIndexes();
45777 for (var i = 0; i < selectedIndices.length; i++) {
45778 dragData.records.push(this.store.getAt(selectedIndices[i]));
45780 if (selNodes.length == 1) {
45781 dragData.ddel = target.cloneNode(true); // the div element
45783 var div = document.createElement('div'); // create the multi element drag "ghost"
45784 div.className = 'multi-proxy';
45785 for (var i = 0, len = selNodes.length; i < len; i++) {
45786 div.appendChild(selNodes[i].cloneNode(true));
45788 dragData.ddel = div;
45790 //console.log(dragData)
45791 //console.log(dragData.ddel.innerHTML)
45794 //console.log('nodragData')
45798 /** Specify to which ddGroup items in this DDView may be dragged. */
45799 setDraggable: function(ddGroup) {
45800 if (ddGroup instanceof Array) {
45801 Roo.each(ddGroup, this.setDraggable, this);
45804 if (this.dragZone) {
45805 this.dragZone.addToGroup(ddGroup);
45807 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
45808 containerScroll: true,
45812 // Draggability implies selection. DragZone's mousedown selects the element.
45813 if (!this.multiSelect) { this.singleSelect = true; }
45815 // Wire the DragZone's handlers up to methods in *this*
45816 this.dragZone.getDragData = this.getDragData.createDelegate(this);
45820 /** Specify from which ddGroup this DDView accepts drops. */
45821 setDroppable: function(ddGroup) {
45822 if (ddGroup instanceof Array) {
45823 Roo.each(ddGroup, this.setDroppable, this);
45826 if (this.dropZone) {
45827 this.dropZone.addToGroup(ddGroup);
45829 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
45830 containerScroll: true,
45834 // Wire the DropZone's handlers up to methods in *this*
45835 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
45836 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
45837 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
45838 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
45839 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
45843 /** Decide whether to drop above or below a View node. */
45844 getDropPoint : function(e, n, dd){
45845 if (n == this.el.dom) { return "above"; }
45846 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
45847 var c = t + (b - t) / 2;
45848 var y = Roo.lib.Event.getPageY(e);
45856 onNodeEnter : function(n, dd, e, data){
45860 onNodeOver : function(n, dd, e, data){
45861 var pt = this.getDropPoint(e, n, dd);
45862 // set the insert point style on the target node
45863 var dragElClass = this.dropNotAllowed;
45866 if (pt == "above"){
45867 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
45868 targetElClass = "x-view-drag-insert-above";
45870 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
45871 targetElClass = "x-view-drag-insert-below";
45873 if (this.lastInsertClass != targetElClass){
45874 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
45875 this.lastInsertClass = targetElClass;
45878 return dragElClass;
45881 onNodeOut : function(n, dd, e, data){
45882 this.removeDropIndicators(n);
45885 onNodeDrop : function(n, dd, e, data){
45886 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
45889 var pt = this.getDropPoint(e, n, dd);
45890 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
45891 if (pt == "below") { insertAt++; }
45892 for (var i = 0; i < data.records.length; i++) {
45893 var r = data.records[i];
45894 var dup = this.store.getById(r.id);
45895 if (dup && (dd != this.dragZone)) {
45896 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
45899 this.store.insert(insertAt++, r.copy());
45901 data.source.isDirtyFlag = true;
45903 this.store.insert(insertAt++, r);
45905 this.isDirtyFlag = true;
45908 this.dragZone.cachedTarget = null;
45912 removeDropIndicators : function(n){
45914 Roo.fly(n).removeClass([
45915 "x-view-drag-insert-above",
45916 "x-view-drag-insert-below"]);
45917 this.lastInsertClass = "_noclass";
45922 * Utility method. Add a delete option to the DDView's context menu.
45923 * @param {String} imageUrl The URL of the "delete" icon image.
45925 setDeletable: function(imageUrl) {
45926 if (!this.singleSelect && !this.multiSelect) {
45927 this.singleSelect = true;
45929 var c = this.getContextMenu();
45930 this.contextMenu.on("itemclick", function(item) {
45933 this.remove(this.getSelectedIndexes());
45937 this.contextMenu.add({
45944 /** Return the context menu for this DDView. */
45945 getContextMenu: function() {
45946 if (!this.contextMenu) {
45947 // Create the View's context menu
45948 this.contextMenu = new Roo.menu.Menu({
45949 id: this.id + "-contextmenu"
45951 this.el.on("contextmenu", this.showContextMenu, this);
45953 return this.contextMenu;
45956 disableContextMenu: function() {
45957 if (this.contextMenu) {
45958 this.el.un("contextmenu", this.showContextMenu, this);
45962 showContextMenu: function(e, item) {
45963 item = this.findItemFromChild(e.getTarget());
45966 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
45967 this.contextMenu.showAt(e.getXY());
45972 * Remove {@link Roo.data.Record}s at the specified indices.
45973 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
45975 remove: function(selectedIndices) {
45976 selectedIndices = [].concat(selectedIndices);
45977 for (var i = 0; i < selectedIndices.length; i++) {
45978 var rec = this.store.getAt(selectedIndices[i]);
45979 this.store.remove(rec);
45984 * Double click fires the event, but also, if this is draggable, and there is only one other
45985 * related DropZone, it transfers the selected node.
45987 onDblClick : function(e){
45988 var item = this.findItemFromChild(e.getTarget());
45990 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
45993 if (this.dragGroup) {
45994 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
45995 while (targets.indexOf(this.dropZone) > -1) {
45996 targets.remove(this.dropZone);
45998 if (targets.length == 1) {
45999 this.dragZone.cachedTarget = null;
46000 var el = Roo.get(targets[0].getEl());
46001 var box = el.getBox(true);
46002 targets[0].onNodeDrop(el.dom, {
46004 xy: [box.x, box.y + box.height - 1]
46005 }, null, this.getDragData(e));
46011 handleSelection: function(e) {
46012 this.dragZone.cachedTarget = null;
46013 var item = this.findItemFromChild(e.getTarget());
46015 this.clearSelections(true);
46018 if (item && (this.multiSelect || this.singleSelect)){
46019 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
46020 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
46021 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
46022 this.unselect(item);
46024 this.select(item, this.multiSelect && e.ctrlKey);
46025 this.lastSelection = item;
46030 onItemClick : function(item, index, e){
46031 if(this.fireEvent("beforeclick", this, index, item, e) === false){
46037 unselect : function(nodeInfo, suppressEvent){
46038 var node = this.getNode(nodeInfo);
46039 if(node && this.isSelected(node)){
46040 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
46041 Roo.fly(node).removeClass(this.selectedClass);
46042 this.selections.remove(node);
46043 if(!suppressEvent){
46044 this.fireEvent("selectionchange", this, this.selections);
46052 * Ext JS Library 1.1.1
46053 * Copyright(c) 2006-2007, Ext JS, LLC.
46055 * Originally Released Under LGPL - original licence link has changed is not relivant.
46058 * <script type="text/javascript">
46062 * @class Roo.LayoutManager
46063 * @extends Roo.util.Observable
46064 * Base class for layout managers.
46066 Roo.LayoutManager = function(container, config){
46067 Roo.LayoutManager.superclass.constructor.call(this);
46068 this.el = Roo.get(container);
46069 // ie scrollbar fix
46070 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
46071 document.body.scroll = "no";
46072 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
46073 this.el.position('relative');
46075 this.id = this.el.id;
46076 this.el.addClass("x-layout-container");
46077 /** false to disable window resize monitoring @type Boolean */
46078 this.monitorWindowResize = true;
46083 * Fires when a layout is performed.
46084 * @param {Roo.LayoutManager} this
46088 * @event regionresized
46089 * Fires when the user resizes a region.
46090 * @param {Roo.LayoutRegion} region The resized region
46091 * @param {Number} newSize The new size (width for east/west, height for north/south)
46093 "regionresized" : true,
46095 * @event regioncollapsed
46096 * Fires when a region is collapsed.
46097 * @param {Roo.LayoutRegion} region The collapsed region
46099 "regioncollapsed" : true,
46101 * @event regionexpanded
46102 * Fires when a region is expanded.
46103 * @param {Roo.LayoutRegion} region The expanded region
46105 "regionexpanded" : true
46107 this.updating = false;
46108 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
46111 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
46113 * Returns true if this layout is currently being updated
46114 * @return {Boolean}
46116 isUpdating : function(){
46117 return this.updating;
46121 * Suspend the LayoutManager from doing auto-layouts while
46122 * making multiple add or remove calls
46124 beginUpdate : function(){
46125 this.updating = true;
46129 * Restore auto-layouts and optionally disable the manager from performing a layout
46130 * @param {Boolean} noLayout true to disable a layout update
46132 endUpdate : function(noLayout){
46133 this.updating = false;
46139 layout: function(){
46143 onRegionResized : function(region, newSize){
46144 this.fireEvent("regionresized", region, newSize);
46148 onRegionCollapsed : function(region){
46149 this.fireEvent("regioncollapsed", region);
46152 onRegionExpanded : function(region){
46153 this.fireEvent("regionexpanded", region);
46157 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
46158 * performs box-model adjustments.
46159 * @return {Object} The size as an object {width: (the width), height: (the height)}
46161 getViewSize : function(){
46163 if(this.el.dom != document.body){
46164 size = this.el.getSize();
46166 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
46168 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
46169 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
46174 * Returns the Element this layout is bound to.
46175 * @return {Roo.Element}
46177 getEl : function(){
46182 * Returns the specified region.
46183 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
46184 * @return {Roo.LayoutRegion}
46186 getRegion : function(target){
46187 return this.regions[target.toLowerCase()];
46190 onWindowResize : function(){
46191 if(this.monitorWindowResize){
46197 * Ext JS Library 1.1.1
46198 * Copyright(c) 2006-2007, Ext JS, LLC.
46200 * Originally Released Under LGPL - original licence link has changed is not relivant.
46203 * <script type="text/javascript">
46206 * @class Roo.BorderLayout
46207 * @extends Roo.LayoutManager
46208 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
46209 * please see: <br><br>
46210 * <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>
46211 * <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>
46214 var layout = new Roo.BorderLayout(document.body, {
46248 preferredTabWidth: 150
46253 var CP = Roo.ContentPanel;
46255 layout.beginUpdate();
46256 layout.add("north", new CP("north", "North"));
46257 layout.add("south", new CP("south", {title: "South", closable: true}));
46258 layout.add("west", new CP("west", {title: "West"}));
46259 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
46260 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
46261 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
46262 layout.getRegion("center").showPanel("center1");
46263 layout.endUpdate();
46266 <b>The container the layout is rendered into can be either the body element or any other element.
46267 If it is not the body element, the container needs to either be an absolute positioned element,
46268 or you will need to add "position:relative" to the css of the container. You will also need to specify
46269 the container size if it is not the body element.</b>
46272 * Create a new BorderLayout
46273 * @param {String/HTMLElement/Element} container The container this layout is bound to
46274 * @param {Object} config Configuration options
46276 Roo.BorderLayout = function(container, config){
46277 config = config || {};
46278 Roo.BorderLayout.superclass.constructor.call(this, container, config);
46279 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
46280 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
46281 var target = this.factory.validRegions[i];
46282 if(config[target]){
46283 this.addRegion(target, config[target]);
46288 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
46290 * Creates and adds a new region if it doesn't already exist.
46291 * @param {String} target The target region key (north, south, east, west or center).
46292 * @param {Object} config The regions config object
46293 * @return {BorderLayoutRegion} The new region
46295 addRegion : function(target, config){
46296 if(!this.regions[target]){
46297 var r = this.factory.create(target, this, config);
46298 this.bindRegion(target, r);
46300 return this.regions[target];
46304 bindRegion : function(name, r){
46305 this.regions[name] = r;
46306 r.on("visibilitychange", this.layout, this);
46307 r.on("paneladded", this.layout, this);
46308 r.on("panelremoved", this.layout, this);
46309 r.on("invalidated", this.layout, this);
46310 r.on("resized", this.onRegionResized, this);
46311 r.on("collapsed", this.onRegionCollapsed, this);
46312 r.on("expanded", this.onRegionExpanded, this);
46316 * Performs a layout update.
46318 layout : function(){
46319 if(this.updating) return;
46320 var size = this.getViewSize();
46321 var w = size.width;
46322 var h = size.height;
46327 //var x = 0, y = 0;
46329 var rs = this.regions;
46330 var north = rs["north"];
46331 var south = rs["south"];
46332 var west = rs["west"];
46333 var east = rs["east"];
46334 var center = rs["center"];
46335 //if(this.hideOnLayout){ // not supported anymore
46336 //c.el.setStyle("display", "none");
46338 if(north && north.isVisible()){
46339 var b = north.getBox();
46340 var m = north.getMargins();
46341 b.width = w - (m.left+m.right);
46344 centerY = b.height + b.y + m.bottom;
46345 centerH -= centerY;
46346 north.updateBox(this.safeBox(b));
46348 if(south && south.isVisible()){
46349 var b = south.getBox();
46350 var m = south.getMargins();
46351 b.width = w - (m.left+m.right);
46353 var totalHeight = (b.height + m.top + m.bottom);
46354 b.y = h - totalHeight + m.top;
46355 centerH -= totalHeight;
46356 south.updateBox(this.safeBox(b));
46358 if(west && west.isVisible()){
46359 var b = west.getBox();
46360 var m = west.getMargins();
46361 b.height = centerH - (m.top+m.bottom);
46363 b.y = centerY + m.top;
46364 var totalWidth = (b.width + m.left + m.right);
46365 centerX += totalWidth;
46366 centerW -= totalWidth;
46367 west.updateBox(this.safeBox(b));
46369 if(east && east.isVisible()){
46370 var b = east.getBox();
46371 var m = east.getMargins();
46372 b.height = centerH - (m.top+m.bottom);
46373 var totalWidth = (b.width + m.left + m.right);
46374 b.x = w - totalWidth + m.left;
46375 b.y = centerY + m.top;
46376 centerW -= totalWidth;
46377 east.updateBox(this.safeBox(b));
46380 var m = center.getMargins();
46382 x: centerX + m.left,
46383 y: centerY + m.top,
46384 width: centerW - (m.left+m.right),
46385 height: centerH - (m.top+m.bottom)
46387 //if(this.hideOnLayout){
46388 //center.el.setStyle("display", "block");
46390 center.updateBox(this.safeBox(centerBox));
46393 this.fireEvent("layout", this);
46397 safeBox : function(box){
46398 box.width = Math.max(0, box.width);
46399 box.height = Math.max(0, box.height);
46404 * Adds a ContentPanel (or subclass) to this layout.
46405 * @param {String} target The target region key (north, south, east, west or center).
46406 * @param {Roo.ContentPanel} panel The panel to add
46407 * @return {Roo.ContentPanel} The added panel
46409 add : function(target, panel){
46411 target = target.toLowerCase();
46412 return this.regions[target].add(panel);
46416 * Remove a ContentPanel (or subclass) to this layout.
46417 * @param {String} target The target region key (north, south, east, west or center).
46418 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
46419 * @return {Roo.ContentPanel} The removed panel
46421 remove : function(target, panel){
46422 target = target.toLowerCase();
46423 return this.regions[target].remove(panel);
46427 * Searches all regions for a panel with the specified id
46428 * @param {String} panelId
46429 * @return {Roo.ContentPanel} The panel or null if it wasn't found
46431 findPanel : function(panelId){
46432 var rs = this.regions;
46433 for(var target in rs){
46434 if(typeof rs[target] != "function"){
46435 var p = rs[target].getPanel(panelId);
46445 * Searches all regions for a panel with the specified id and activates (shows) it.
46446 * @param {String/ContentPanel} panelId The panels id or the panel itself
46447 * @return {Roo.ContentPanel} The shown panel or null
46449 showPanel : function(panelId) {
46450 var rs = this.regions;
46451 for(var target in rs){
46452 var r = rs[target];
46453 if(typeof r != "function"){
46454 if(r.hasPanel(panelId)){
46455 return r.showPanel(panelId);
46463 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
46464 * @param {Roo.state.Provider} provider (optional) An alternate state provider
46466 restoreState : function(provider){
46468 provider = Roo.state.Manager;
46470 var sm = new Roo.LayoutStateManager();
46471 sm.init(this, provider);
46475 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
46476 * object should contain properties for each region to add ContentPanels to, and each property's value should be
46477 * a valid ContentPanel config object. Example:
46479 // Create the main layout
46480 var layout = new Roo.BorderLayout('main-ct', {
46491 // Create and add multiple ContentPanels at once via configs
46494 id: 'source-files',
46496 title:'Ext Source Files',
46509 * @param {Object} regions An object containing ContentPanel configs by region name
46511 batchAdd : function(regions){
46512 this.beginUpdate();
46513 for(var rname in regions){
46514 var lr = this.regions[rname];
46516 this.addTypedPanels(lr, regions[rname]);
46523 addTypedPanels : function(lr, ps){
46524 if(typeof ps == 'string'){
46525 lr.add(new Roo.ContentPanel(ps));
46527 else if(ps instanceof Array){
46528 for(var i =0, len = ps.length; i < len; i++){
46529 this.addTypedPanels(lr, ps[i]);
46532 else if(!ps.events){ // raw config?
46534 delete ps.el; // prevent conflict
46535 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
46537 else { // panel object assumed!
46542 * Adds a xtype elements to the layout.
46546 xtype : 'ContentPanel',
46553 xtype : 'NestedLayoutPanel',
46559 items : [ ... list of content panels or nested layout panels.. ]
46563 * @param {Object} cfg Xtype definition of item to add.
46565 addxtype : function(cfg)
46567 // basically accepts a pannel...
46568 // can accept a layout region..!?!?
46569 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
46571 if (!cfg.xtype.match(/Panel$/)) {
46576 if (typeof(cfg.region) == 'undefined') {
46577 Roo.log("Failed to add Panel, region was not set");
46581 var region = cfg.region;
46587 xitems = cfg.items;
46594 case 'ContentPanel': // ContentPanel (el, cfg)
46595 case 'ScrollPanel': // ContentPanel (el, cfg)
46596 if(cfg.autoCreate) {
46597 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
46599 var el = this.el.createChild();
46600 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
46603 this.add(region, ret);
46607 case 'TreePanel': // our new panel!
46608 cfg.el = this.el.createChild();
46609 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
46610 this.add(region, ret);
46613 case 'NestedLayoutPanel':
46614 // create a new Layout (which is a Border Layout...
46615 var el = this.el.createChild();
46616 var clayout = cfg.layout;
46618 clayout.items = clayout.items || [];
46619 // replace this exitems with the clayout ones..
46620 xitems = clayout.items;
46623 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
46624 cfg.background = false;
46626 var layout = new Roo.BorderLayout(el, clayout);
46628 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
46629 //console.log('adding nested layout panel ' + cfg.toSource());
46630 this.add(region, ret);
46631 nb = {}; /// find first...
46636 // needs grid and region
46638 //var el = this.getRegion(region).el.createChild();
46639 var el = this.el.createChild();
46640 // create the grid first...
46642 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
46644 if (region == 'center' && this.active ) {
46645 cfg.background = false;
46647 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
46649 this.add(region, ret);
46650 if (cfg.background) {
46651 ret.on('activate', function(gp) {
46652 if (!gp.grid.rendered) {
46665 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
46667 // GridPanel (grid, cfg)
46670 this.beginUpdate();
46674 Roo.each(xitems, function(i) {
46675 region = nb && i.region ? i.region : false;
46677 var add = ret.addxtype(i);
46680 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
46681 if (!i.background) {
46682 abn[region] = nb[region] ;
46689 // make the last non-background panel active..
46690 //if (nb) { Roo.log(abn); }
46693 for(var r in abn) {
46694 region = this.getRegion(r);
46696 // tried using nb[r], but it does not work..
46698 region.showPanel(abn[r]);
46709 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
46710 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
46711 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
46712 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
46715 var CP = Roo.ContentPanel;
46717 var layout = Roo.BorderLayout.create({
46721 panels: [new CP("north", "North")]
46730 panels: [new CP("west", {title: "West"})]
46739 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
46748 panels: [new CP("south", {title: "South", closable: true})]
46755 preferredTabWidth: 150,
46757 new CP("center1", {title: "Close Me", closable: true}),
46758 new CP("center2", {title: "Center Panel", closable: false})
46763 layout.getRegion("center").showPanel("center1");
46768 Roo.BorderLayout.create = function(config, targetEl){
46769 var layout = new Roo.BorderLayout(targetEl || document.body, config);
46770 layout.beginUpdate();
46771 var regions = Roo.BorderLayout.RegionFactory.validRegions;
46772 for(var j = 0, jlen = regions.length; j < jlen; j++){
46773 var lr = regions[j];
46774 if(layout.regions[lr] && config[lr].panels){
46775 var r = layout.regions[lr];
46776 var ps = config[lr].panels;
46777 layout.addTypedPanels(r, ps);
46780 layout.endUpdate();
46785 Roo.BorderLayout.RegionFactory = {
46787 validRegions : ["north","south","east","west","center"],
46790 create : function(target, mgr, config){
46791 target = target.toLowerCase();
46792 if(config.lightweight || config.basic){
46793 return new Roo.BasicLayoutRegion(mgr, config, target);
46797 return new Roo.NorthLayoutRegion(mgr, config);
46799 return new Roo.SouthLayoutRegion(mgr, config);
46801 return new Roo.EastLayoutRegion(mgr, config);
46803 return new Roo.WestLayoutRegion(mgr, config);
46805 return new Roo.CenterLayoutRegion(mgr, config);
46807 throw 'Layout region "'+target+'" not supported.';
46811 * Ext JS Library 1.1.1
46812 * Copyright(c) 2006-2007, Ext JS, LLC.
46814 * Originally Released Under LGPL - original licence link has changed is not relivant.
46817 * <script type="text/javascript">
46821 * @class Roo.BasicLayoutRegion
46822 * @extends Roo.util.Observable
46823 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
46824 * and does not have a titlebar, tabs or any other features. All it does is size and position
46825 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
46827 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
46829 this.position = pos;
46832 * @scope Roo.BasicLayoutRegion
46836 * @event beforeremove
46837 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
46838 * @param {Roo.LayoutRegion} this
46839 * @param {Roo.ContentPanel} panel The panel
46840 * @param {Object} e The cancel event object
46842 "beforeremove" : true,
46844 * @event invalidated
46845 * Fires when the layout for this region is changed.
46846 * @param {Roo.LayoutRegion} this
46848 "invalidated" : true,
46850 * @event visibilitychange
46851 * Fires when this region is shown or hidden
46852 * @param {Roo.LayoutRegion} this
46853 * @param {Boolean} visibility true or false
46855 "visibilitychange" : true,
46857 * @event paneladded
46858 * Fires when a panel is added.
46859 * @param {Roo.LayoutRegion} this
46860 * @param {Roo.ContentPanel} panel The panel
46862 "paneladded" : true,
46864 * @event panelremoved
46865 * Fires when a panel is removed.
46866 * @param {Roo.LayoutRegion} this
46867 * @param {Roo.ContentPanel} panel The panel
46869 "panelremoved" : true,
46872 * Fires when this region is collapsed.
46873 * @param {Roo.LayoutRegion} this
46875 "collapsed" : true,
46878 * Fires when this region is expanded.
46879 * @param {Roo.LayoutRegion} this
46884 * Fires when this region is slid into view.
46885 * @param {Roo.LayoutRegion} this
46887 "slideshow" : true,
46890 * Fires when this region slides out of view.
46891 * @param {Roo.LayoutRegion} this
46893 "slidehide" : true,
46895 * @event panelactivated
46896 * Fires when a panel is activated.
46897 * @param {Roo.LayoutRegion} this
46898 * @param {Roo.ContentPanel} panel The activated panel
46900 "panelactivated" : true,
46903 * Fires when the user resizes this region.
46904 * @param {Roo.LayoutRegion} this
46905 * @param {Number} newSize The new size (width for east/west, height for north/south)
46909 /** A collection of panels in this region. @type Roo.util.MixedCollection */
46910 this.panels = new Roo.util.MixedCollection();
46911 this.panels.getKey = this.getPanelId.createDelegate(this);
46913 this.activePanel = null;
46914 // ensure listeners are added...
46916 if (config.listeners || config.events) {
46917 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
46918 listeners : config.listeners || {},
46919 events : config.events || {}
46923 if(skipConfig !== true){
46924 this.applyConfig(config);
46928 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
46929 getPanelId : function(p){
46933 applyConfig : function(config){
46934 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
46935 this.config = config;
46940 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
46941 * the width, for horizontal (north, south) the height.
46942 * @param {Number} newSize The new width or height
46944 resizeTo : function(newSize){
46945 var el = this.el ? this.el :
46946 (this.activePanel ? this.activePanel.getEl() : null);
46948 switch(this.position){
46951 el.setWidth(newSize);
46952 this.fireEvent("resized", this, newSize);
46956 el.setHeight(newSize);
46957 this.fireEvent("resized", this, newSize);
46963 getBox : function(){
46964 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
46967 getMargins : function(){
46968 return this.margins;
46971 updateBox : function(box){
46973 var el = this.activePanel.getEl();
46974 el.dom.style.left = box.x + "px";
46975 el.dom.style.top = box.y + "px";
46976 this.activePanel.setSize(box.width, box.height);
46980 * Returns the container element for this region.
46981 * @return {Roo.Element}
46983 getEl : function(){
46984 return this.activePanel;
46988 * Returns true if this region is currently visible.
46989 * @return {Boolean}
46991 isVisible : function(){
46992 return this.activePanel ? true : false;
46995 setActivePanel : function(panel){
46996 panel = this.getPanel(panel);
46997 if(this.activePanel && this.activePanel != panel){
46998 this.activePanel.setActiveState(false);
46999 this.activePanel.getEl().setLeftTop(-10000,-10000);
47001 this.activePanel = panel;
47002 panel.setActiveState(true);
47004 panel.setSize(this.box.width, this.box.height);
47006 this.fireEvent("panelactivated", this, panel);
47007 this.fireEvent("invalidated");
47011 * Show the specified panel.
47012 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
47013 * @return {Roo.ContentPanel} The shown panel or null
47015 showPanel : function(panel){
47016 if(panel = this.getPanel(panel)){
47017 this.setActivePanel(panel);
47023 * Get the active panel for this region.
47024 * @return {Roo.ContentPanel} The active panel or null
47026 getActivePanel : function(){
47027 return this.activePanel;
47031 * Add the passed ContentPanel(s)
47032 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
47033 * @return {Roo.ContentPanel} The panel added (if only one was added)
47035 add : function(panel){
47036 if(arguments.length > 1){
47037 for(var i = 0, len = arguments.length; i < len; i++) {
47038 this.add(arguments[i]);
47042 if(this.hasPanel(panel)){
47043 this.showPanel(panel);
47046 var el = panel.getEl();
47047 if(el.dom.parentNode != this.mgr.el.dom){
47048 this.mgr.el.dom.appendChild(el.dom);
47050 if(panel.setRegion){
47051 panel.setRegion(this);
47053 this.panels.add(panel);
47054 el.setStyle("position", "absolute");
47055 if(!panel.background){
47056 this.setActivePanel(panel);
47057 if(this.config.initialSize && this.panels.getCount()==1){
47058 this.resizeTo(this.config.initialSize);
47061 this.fireEvent("paneladded", this, panel);
47066 * Returns true if the panel is in this region.
47067 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47068 * @return {Boolean}
47070 hasPanel : function(panel){
47071 if(typeof panel == "object"){ // must be panel obj
47072 panel = panel.getId();
47074 return this.getPanel(panel) ? true : false;
47078 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
47079 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47080 * @param {Boolean} preservePanel Overrides the config preservePanel option
47081 * @return {Roo.ContentPanel} The panel that was removed
47083 remove : function(panel, preservePanel){
47084 panel = this.getPanel(panel);
47089 this.fireEvent("beforeremove", this, panel, e);
47090 if(e.cancel === true){
47093 var panelId = panel.getId();
47094 this.panels.removeKey(panelId);
47099 * Returns the panel specified or null if it's not in this region.
47100 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47101 * @return {Roo.ContentPanel}
47103 getPanel : function(id){
47104 if(typeof id == "object"){ // must be panel obj
47107 return this.panels.get(id);
47111 * Returns this regions position (north/south/east/west/center).
47114 getPosition: function(){
47115 return this.position;
47119 * Ext JS Library 1.1.1
47120 * Copyright(c) 2006-2007, Ext JS, LLC.
47122 * Originally Released Under LGPL - original licence link has changed is not relivant.
47125 * <script type="text/javascript">
47129 * @class Roo.LayoutRegion
47130 * @extends Roo.BasicLayoutRegion
47131 * This class represents a region in a layout manager.
47132 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
47133 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
47134 * @cfg {Boolean} floatable False to disable floating (defaults to true)
47135 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
47136 * @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})
47137 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
47138 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
47139 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
47140 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
47141 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
47142 * @cfg {String} title The title for the region (overrides panel titles)
47143 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
47144 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
47145 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
47146 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
47147 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
47148 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
47149 * the space available, similar to FireFox 1.5 tabs (defaults to false)
47150 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
47151 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
47152 * @cfg {Boolean} showPin True to show a pin button
47153 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
47154 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
47155 * @cfg {Boolean} disableTabTips True to disable tab tooltips
47156 * @cfg {Number} width For East/West panels
47157 * @cfg {Number} height For North/South panels
47158 * @cfg {Boolean} split To show the splitter
47159 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
47161 Roo.LayoutRegion = function(mgr, config, pos){
47162 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
47163 var dh = Roo.DomHelper;
47164 /** This region's container element
47165 * @type Roo.Element */
47166 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
47167 /** This region's title element
47168 * @type Roo.Element */
47170 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
47171 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
47172 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
47174 this.titleEl.enableDisplayMode();
47175 /** This region's title text element
47176 * @type HTMLElement */
47177 this.titleTextEl = this.titleEl.dom.firstChild;
47178 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
47179 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
47180 this.closeBtn.enableDisplayMode();
47181 this.closeBtn.on("click", this.closeClicked, this);
47182 this.closeBtn.hide();
47184 this.createBody(config);
47185 this.visible = true;
47186 this.collapsed = false;
47188 if(config.hideWhenEmpty){
47190 this.on("paneladded", this.validateVisibility, this);
47191 this.on("panelremoved", this.validateVisibility, this);
47193 this.applyConfig(config);
47196 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
47198 createBody : function(){
47199 /** This region's body element
47200 * @type Roo.Element */
47201 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
47204 applyConfig : function(c){
47205 if(c.collapsible && this.position != "center" && !this.collapsedEl){
47206 var dh = Roo.DomHelper;
47207 if(c.titlebar !== false){
47208 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
47209 this.collapseBtn.on("click", this.collapse, this);
47210 this.collapseBtn.enableDisplayMode();
47212 if(c.showPin === true || this.showPin){
47213 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
47214 this.stickBtn.enableDisplayMode();
47215 this.stickBtn.on("click", this.expand, this);
47216 this.stickBtn.hide();
47219 /** This region's collapsed element
47220 * @type Roo.Element */
47221 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
47222 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
47224 if(c.floatable !== false){
47225 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
47226 this.collapsedEl.on("click", this.collapseClick, this);
47229 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
47230 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
47231 id: "message", unselectable: "on", style:{"float":"left"}});
47232 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
47234 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
47235 this.expandBtn.on("click", this.expand, this);
47237 if(this.collapseBtn){
47238 this.collapseBtn.setVisible(c.collapsible == true);
47240 this.cmargins = c.cmargins || this.cmargins ||
47241 (this.position == "west" || this.position == "east" ?
47242 {top: 0, left: 2, right:2, bottom: 0} :
47243 {top: 2, left: 0, right:0, bottom: 2});
47244 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
47245 this.bottomTabs = c.tabPosition != "top";
47246 this.autoScroll = c.autoScroll || false;
47247 if(this.autoScroll){
47248 this.bodyEl.setStyle("overflow", "auto");
47250 this.bodyEl.setStyle("overflow", "hidden");
47252 //if(c.titlebar !== false){
47253 if((!c.titlebar && !c.title) || c.titlebar === false){
47254 this.titleEl.hide();
47256 this.titleEl.show();
47258 this.titleTextEl.innerHTML = c.title;
47262 this.duration = c.duration || .30;
47263 this.slideDuration = c.slideDuration || .45;
47266 this.collapse(true);
47273 * Returns true if this region is currently visible.
47274 * @return {Boolean}
47276 isVisible : function(){
47277 return this.visible;
47281 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
47282 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
47284 setCollapsedTitle : function(title){
47285 title = title || " ";
47286 if(this.collapsedTitleTextEl){
47287 this.collapsedTitleTextEl.innerHTML = title;
47291 getBox : function(){
47293 if(!this.collapsed){
47294 b = this.el.getBox(false, true);
47296 b = this.collapsedEl.getBox(false, true);
47301 getMargins : function(){
47302 return this.collapsed ? this.cmargins : this.margins;
47305 highlight : function(){
47306 this.el.addClass("x-layout-panel-dragover");
47309 unhighlight : function(){
47310 this.el.removeClass("x-layout-panel-dragover");
47313 updateBox : function(box){
47315 if(!this.collapsed){
47316 this.el.dom.style.left = box.x + "px";
47317 this.el.dom.style.top = box.y + "px";
47318 this.updateBody(box.width, box.height);
47320 this.collapsedEl.dom.style.left = box.x + "px";
47321 this.collapsedEl.dom.style.top = box.y + "px";
47322 this.collapsedEl.setSize(box.width, box.height);
47325 this.tabs.autoSizeTabs();
47329 updateBody : function(w, h){
47331 this.el.setWidth(w);
47332 w -= this.el.getBorderWidth("rl");
47333 if(this.config.adjustments){
47334 w += this.config.adjustments[0];
47338 this.el.setHeight(h);
47339 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
47340 h -= this.el.getBorderWidth("tb");
47341 if(this.config.adjustments){
47342 h += this.config.adjustments[1];
47344 this.bodyEl.setHeight(h);
47346 h = this.tabs.syncHeight(h);
47349 if(this.panelSize){
47350 w = w !== null ? w : this.panelSize.width;
47351 h = h !== null ? h : this.panelSize.height;
47353 if(this.activePanel){
47354 var el = this.activePanel.getEl();
47355 w = w !== null ? w : el.getWidth();
47356 h = h !== null ? h : el.getHeight();
47357 this.panelSize = {width: w, height: h};
47358 this.activePanel.setSize(w, h);
47360 if(Roo.isIE && this.tabs){
47361 this.tabs.el.repaint();
47366 * Returns the container element for this region.
47367 * @return {Roo.Element}
47369 getEl : function(){
47374 * Hides this region.
47377 if(!this.collapsed){
47378 this.el.dom.style.left = "-2000px";
47381 this.collapsedEl.dom.style.left = "-2000px";
47382 this.collapsedEl.hide();
47384 this.visible = false;
47385 this.fireEvent("visibilitychange", this, false);
47389 * Shows this region if it was previously hidden.
47392 if(!this.collapsed){
47395 this.collapsedEl.show();
47397 this.visible = true;
47398 this.fireEvent("visibilitychange", this, true);
47401 closeClicked : function(){
47402 if(this.activePanel){
47403 this.remove(this.activePanel);
47407 collapseClick : function(e){
47409 e.stopPropagation();
47412 e.stopPropagation();
47418 * Collapses this region.
47419 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
47421 collapse : function(skipAnim){
47422 if(this.collapsed) return;
47423 this.collapsed = true;
47425 this.split.el.hide();
47427 if(this.config.animate && skipAnim !== true){
47428 this.fireEvent("invalidated", this);
47429 this.animateCollapse();
47431 this.el.setLocation(-20000,-20000);
47433 this.collapsedEl.show();
47434 this.fireEvent("collapsed", this);
47435 this.fireEvent("invalidated", this);
47439 animateCollapse : function(){
47444 * Expands this region if it was previously collapsed.
47445 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
47446 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
47448 expand : function(e, skipAnim){
47449 if(e) e.stopPropagation();
47450 if(!this.collapsed || this.el.hasActiveFx()) return;
47452 this.afterSlideIn();
47455 this.collapsed = false;
47456 if(this.config.animate && skipAnim !== true){
47457 this.animateExpand();
47461 this.split.el.show();
47463 this.collapsedEl.setLocation(-2000,-2000);
47464 this.collapsedEl.hide();
47465 this.fireEvent("invalidated", this);
47466 this.fireEvent("expanded", this);
47470 animateExpand : function(){
47474 initTabs : function()
47476 this.bodyEl.setStyle("overflow", "hidden");
47477 var ts = new Roo.TabPanel(
47480 tabPosition: this.bottomTabs ? 'bottom' : 'top',
47481 disableTooltips: this.config.disableTabTips,
47482 toolbar : this.config.toolbar
47485 if(this.config.hideTabs){
47486 ts.stripWrap.setDisplayed(false);
47489 ts.resizeTabs = this.config.resizeTabs === true;
47490 ts.minTabWidth = this.config.minTabWidth || 40;
47491 ts.maxTabWidth = this.config.maxTabWidth || 250;
47492 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
47493 ts.monitorResize = false;
47494 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47495 ts.bodyEl.addClass('x-layout-tabs-body');
47496 this.panels.each(this.initPanelAsTab, this);
47499 initPanelAsTab : function(panel){
47500 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
47501 this.config.closeOnTab && panel.isClosable());
47502 if(panel.tabTip !== undefined){
47503 ti.setTooltip(panel.tabTip);
47505 ti.on("activate", function(){
47506 this.setActivePanel(panel);
47508 if(this.config.closeOnTab){
47509 ti.on("beforeclose", function(t, e){
47511 this.remove(panel);
47517 updatePanelTitle : function(panel, title){
47518 if(this.activePanel == panel){
47519 this.updateTitle(title);
47522 var ti = this.tabs.getTab(panel.getEl().id);
47524 if(panel.tabTip !== undefined){
47525 ti.setTooltip(panel.tabTip);
47530 updateTitle : function(title){
47531 if(this.titleTextEl && !this.config.title){
47532 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
47536 setActivePanel : function(panel){
47537 panel = this.getPanel(panel);
47538 if(this.activePanel && this.activePanel != panel){
47539 this.activePanel.setActiveState(false);
47541 this.activePanel = panel;
47542 panel.setActiveState(true);
47543 if(this.panelSize){
47544 panel.setSize(this.panelSize.width, this.panelSize.height);
47547 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
47549 this.updateTitle(panel.getTitle());
47551 this.fireEvent("invalidated", this);
47553 this.fireEvent("panelactivated", this, panel);
47557 * Shows the specified panel.
47558 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
47559 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
47561 showPanel : function(panel){
47562 if(panel = this.getPanel(panel)){
47564 var tab = this.tabs.getTab(panel.getEl().id);
47565 if(tab.isHidden()){
47566 this.tabs.unhideTab(tab.id);
47570 this.setActivePanel(panel);
47577 * Get the active panel for this region.
47578 * @return {Roo.ContentPanel} The active panel or null
47580 getActivePanel : function(){
47581 return this.activePanel;
47584 validateVisibility : function(){
47585 if(this.panels.getCount() < 1){
47586 this.updateTitle(" ");
47587 this.closeBtn.hide();
47590 if(!this.isVisible()){
47597 * Adds the passed ContentPanel(s) to this region.
47598 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
47599 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
47601 add : function(panel){
47602 if(arguments.length > 1){
47603 for(var i = 0, len = arguments.length; i < len; i++) {
47604 this.add(arguments[i]);
47608 if(this.hasPanel(panel)){
47609 this.showPanel(panel);
47612 panel.setRegion(this);
47613 this.panels.add(panel);
47614 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
47615 this.bodyEl.dom.appendChild(panel.getEl().dom);
47616 if(panel.background !== true){
47617 this.setActivePanel(panel);
47619 this.fireEvent("paneladded", this, panel);
47625 this.initPanelAsTab(panel);
47627 if(panel.background !== true){
47628 this.tabs.activate(panel.getEl().id);
47630 this.fireEvent("paneladded", this, panel);
47635 * Hides the tab for the specified panel.
47636 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47638 hidePanel : function(panel){
47639 if(this.tabs && (panel = this.getPanel(panel))){
47640 this.tabs.hideTab(panel.getEl().id);
47645 * Unhides the tab for a previously hidden panel.
47646 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47648 unhidePanel : function(panel){
47649 if(this.tabs && (panel = this.getPanel(panel))){
47650 this.tabs.unhideTab(panel.getEl().id);
47654 clearPanels : function(){
47655 while(this.panels.getCount() > 0){
47656 this.remove(this.panels.first());
47661 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
47662 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
47663 * @param {Boolean} preservePanel Overrides the config preservePanel option
47664 * @return {Roo.ContentPanel} The panel that was removed
47666 remove : function(panel, preservePanel){
47667 panel = this.getPanel(panel);
47672 this.fireEvent("beforeremove", this, panel, e);
47673 if(e.cancel === true){
47676 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
47677 var panelId = panel.getId();
47678 this.panels.removeKey(panelId);
47680 document.body.appendChild(panel.getEl().dom);
47683 this.tabs.removeTab(panel.getEl().id);
47684 }else if (!preservePanel){
47685 this.bodyEl.dom.removeChild(panel.getEl().dom);
47687 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
47688 var p = this.panels.first();
47689 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
47690 tempEl.appendChild(p.getEl().dom);
47691 this.bodyEl.update("");
47692 this.bodyEl.dom.appendChild(p.getEl().dom);
47694 this.updateTitle(p.getTitle());
47696 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
47697 this.setActivePanel(p);
47699 panel.setRegion(null);
47700 if(this.activePanel == panel){
47701 this.activePanel = null;
47703 if(this.config.autoDestroy !== false && preservePanel !== true){
47704 try{panel.destroy();}catch(e){}
47706 this.fireEvent("panelremoved", this, panel);
47711 * Returns the TabPanel component used by this region
47712 * @return {Roo.TabPanel}
47714 getTabs : function(){
47718 createTool : function(parentEl, className){
47719 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
47720 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
47721 btn.addClassOnOver("x-layout-tools-button-over");
47726 * Ext JS Library 1.1.1
47727 * Copyright(c) 2006-2007, Ext JS, LLC.
47729 * Originally Released Under LGPL - original licence link has changed is not relivant.
47732 * <script type="text/javascript">
47738 * @class Roo.SplitLayoutRegion
47739 * @extends Roo.LayoutRegion
47740 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
47742 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
47743 this.cursor = cursor;
47744 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
47747 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
47748 splitTip : "Drag to resize.",
47749 collapsibleSplitTip : "Drag to resize. Double click to hide.",
47750 useSplitTips : false,
47752 applyConfig : function(config){
47753 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
47756 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
47757 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
47758 /** The SplitBar for this region
47759 * @type Roo.SplitBar */
47760 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
47761 this.split.on("moved", this.onSplitMove, this);
47762 this.split.useShim = config.useShim === true;
47763 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
47764 if(this.useSplitTips){
47765 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
47767 if(config.collapsible){
47768 this.split.el.on("dblclick", this.collapse, this);
47771 if(typeof config.minSize != "undefined"){
47772 this.split.minSize = config.minSize;
47774 if(typeof config.maxSize != "undefined"){
47775 this.split.maxSize = config.maxSize;
47777 if(config.hideWhenEmpty || config.hidden || config.collapsed){
47778 this.hideSplitter();
47783 getHMaxSize : function(){
47784 var cmax = this.config.maxSize || 10000;
47785 var center = this.mgr.getRegion("center");
47786 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
47789 getVMaxSize : function(){
47790 var cmax = this.config.maxSize || 10000;
47791 var center = this.mgr.getRegion("center");
47792 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
47795 onSplitMove : function(split, newSize){
47796 this.fireEvent("resized", this, newSize);
47800 * Returns the {@link Roo.SplitBar} for this region.
47801 * @return {Roo.SplitBar}
47803 getSplitBar : function(){
47808 this.hideSplitter();
47809 Roo.SplitLayoutRegion.superclass.hide.call(this);
47812 hideSplitter : function(){
47814 this.split.el.setLocation(-2000,-2000);
47815 this.split.el.hide();
47821 this.split.el.show();
47823 Roo.SplitLayoutRegion.superclass.show.call(this);
47826 beforeSlide: function(){
47827 if(Roo.isGecko){// firefox overflow auto bug workaround
47828 this.bodyEl.clip();
47829 if(this.tabs) this.tabs.bodyEl.clip();
47830 if(this.activePanel){
47831 this.activePanel.getEl().clip();
47833 if(this.activePanel.beforeSlide){
47834 this.activePanel.beforeSlide();
47840 afterSlide : function(){
47841 if(Roo.isGecko){// firefox overflow auto bug workaround
47842 this.bodyEl.unclip();
47843 if(this.tabs) this.tabs.bodyEl.unclip();
47844 if(this.activePanel){
47845 this.activePanel.getEl().unclip();
47846 if(this.activePanel.afterSlide){
47847 this.activePanel.afterSlide();
47853 initAutoHide : function(){
47854 if(this.autoHide !== false){
47855 if(!this.autoHideHd){
47856 var st = new Roo.util.DelayedTask(this.slideIn, this);
47857 this.autoHideHd = {
47858 "mouseout": function(e){
47859 if(!e.within(this.el, true)){
47863 "mouseover" : function(e){
47869 this.el.on(this.autoHideHd);
47873 clearAutoHide : function(){
47874 if(this.autoHide !== false){
47875 this.el.un("mouseout", this.autoHideHd.mouseout);
47876 this.el.un("mouseover", this.autoHideHd.mouseover);
47880 clearMonitor : function(){
47881 Roo.get(document).un("click", this.slideInIf, this);
47884 // these names are backwards but not changed for compat
47885 slideOut : function(){
47886 if(this.isSlid || this.el.hasActiveFx()){
47889 this.isSlid = true;
47890 if(this.collapseBtn){
47891 this.collapseBtn.hide();
47893 this.closeBtnState = this.closeBtn.getStyle('display');
47894 this.closeBtn.hide();
47896 this.stickBtn.show();
47899 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
47900 this.beforeSlide();
47901 this.el.setStyle("z-index", 10001);
47902 this.el.slideIn(this.getSlideAnchor(), {
47903 callback: function(){
47905 this.initAutoHide();
47906 Roo.get(document).on("click", this.slideInIf, this);
47907 this.fireEvent("slideshow", this);
47914 afterSlideIn : function(){
47915 this.clearAutoHide();
47916 this.isSlid = false;
47917 this.clearMonitor();
47918 this.el.setStyle("z-index", "");
47919 if(this.collapseBtn){
47920 this.collapseBtn.show();
47922 this.closeBtn.setStyle('display', this.closeBtnState);
47924 this.stickBtn.hide();
47926 this.fireEvent("slidehide", this);
47929 slideIn : function(cb){
47930 if(!this.isSlid || this.el.hasActiveFx()){
47934 this.isSlid = false;
47935 this.beforeSlide();
47936 this.el.slideOut(this.getSlideAnchor(), {
47937 callback: function(){
47938 this.el.setLeftTop(-10000, -10000);
47940 this.afterSlideIn();
47948 slideInIf : function(e){
47949 if(!e.within(this.el)){
47954 animateCollapse : function(){
47955 this.beforeSlide();
47956 this.el.setStyle("z-index", 20000);
47957 var anchor = this.getSlideAnchor();
47958 this.el.slideOut(anchor, {
47959 callback : function(){
47960 this.el.setStyle("z-index", "");
47961 this.collapsedEl.slideIn(anchor, {duration:.3});
47963 this.el.setLocation(-10000,-10000);
47965 this.fireEvent("collapsed", this);
47972 animateExpand : function(){
47973 this.beforeSlide();
47974 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
47975 this.el.setStyle("z-index", 20000);
47976 this.collapsedEl.hide({
47979 this.el.slideIn(this.getSlideAnchor(), {
47980 callback : function(){
47981 this.el.setStyle("z-index", "");
47984 this.split.el.show();
47986 this.fireEvent("invalidated", this);
47987 this.fireEvent("expanded", this);
48015 getAnchor : function(){
48016 return this.anchors[this.position];
48019 getCollapseAnchor : function(){
48020 return this.canchors[this.position];
48023 getSlideAnchor : function(){
48024 return this.sanchors[this.position];
48027 getAlignAdj : function(){
48028 var cm = this.cmargins;
48029 switch(this.position){
48045 getExpandAdj : function(){
48046 var c = this.collapsedEl, cm = this.cmargins;
48047 switch(this.position){
48049 return [-(cm.right+c.getWidth()+cm.left), 0];
48052 return [cm.right+c.getWidth()+cm.left, 0];
48055 return [0, -(cm.top+cm.bottom+c.getHeight())];
48058 return [0, cm.top+cm.bottom+c.getHeight()];
48064 * Ext JS Library 1.1.1
48065 * Copyright(c) 2006-2007, Ext JS, LLC.
48067 * Originally Released Under LGPL - original licence link has changed is not relivant.
48070 * <script type="text/javascript">
48073 * These classes are private internal classes
48075 Roo.CenterLayoutRegion = function(mgr, config){
48076 Roo.LayoutRegion.call(this, mgr, config, "center");
48077 this.visible = true;
48078 this.minWidth = config.minWidth || 20;
48079 this.minHeight = config.minHeight || 20;
48082 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
48084 // center panel can't be hidden
48088 // center panel can't be hidden
48091 getMinWidth: function(){
48092 return this.minWidth;
48095 getMinHeight: function(){
48096 return this.minHeight;
48101 Roo.NorthLayoutRegion = function(mgr, config){
48102 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
48104 this.split.placement = Roo.SplitBar.TOP;
48105 this.split.orientation = Roo.SplitBar.VERTICAL;
48106 this.split.el.addClass("x-layout-split-v");
48108 var size = config.initialSize || config.height;
48109 if(typeof size != "undefined"){
48110 this.el.setHeight(size);
48113 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
48114 orientation: Roo.SplitBar.VERTICAL,
48115 getBox : function(){
48116 if(this.collapsed){
48117 return this.collapsedEl.getBox();
48119 var box = this.el.getBox();
48121 box.height += this.split.el.getHeight();
48126 updateBox : function(box){
48127 if(this.split && !this.collapsed){
48128 box.height -= this.split.el.getHeight();
48129 this.split.el.setLeft(box.x);
48130 this.split.el.setTop(box.y+box.height);
48131 this.split.el.setWidth(box.width);
48133 if(this.collapsed){
48134 this.updateBody(box.width, null);
48136 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48140 Roo.SouthLayoutRegion = function(mgr, config){
48141 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
48143 this.split.placement = Roo.SplitBar.BOTTOM;
48144 this.split.orientation = Roo.SplitBar.VERTICAL;
48145 this.split.el.addClass("x-layout-split-v");
48147 var size = config.initialSize || config.height;
48148 if(typeof size != "undefined"){
48149 this.el.setHeight(size);
48152 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
48153 orientation: Roo.SplitBar.VERTICAL,
48154 getBox : function(){
48155 if(this.collapsed){
48156 return this.collapsedEl.getBox();
48158 var box = this.el.getBox();
48160 var sh = this.split.el.getHeight();
48167 updateBox : function(box){
48168 if(this.split && !this.collapsed){
48169 var sh = this.split.el.getHeight();
48172 this.split.el.setLeft(box.x);
48173 this.split.el.setTop(box.y-sh);
48174 this.split.el.setWidth(box.width);
48176 if(this.collapsed){
48177 this.updateBody(box.width, null);
48179 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48183 Roo.EastLayoutRegion = function(mgr, config){
48184 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
48186 this.split.placement = Roo.SplitBar.RIGHT;
48187 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48188 this.split.el.addClass("x-layout-split-h");
48190 var size = config.initialSize || config.width;
48191 if(typeof size != "undefined"){
48192 this.el.setWidth(size);
48195 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
48196 orientation: Roo.SplitBar.HORIZONTAL,
48197 getBox : function(){
48198 if(this.collapsed){
48199 return this.collapsedEl.getBox();
48201 var box = this.el.getBox();
48203 var sw = this.split.el.getWidth();
48210 updateBox : function(box){
48211 if(this.split && !this.collapsed){
48212 var sw = this.split.el.getWidth();
48214 this.split.el.setLeft(box.x);
48215 this.split.el.setTop(box.y);
48216 this.split.el.setHeight(box.height);
48219 if(this.collapsed){
48220 this.updateBody(null, box.height);
48222 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48226 Roo.WestLayoutRegion = function(mgr, config){
48227 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
48229 this.split.placement = Roo.SplitBar.LEFT;
48230 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48231 this.split.el.addClass("x-layout-split-h");
48233 var size = config.initialSize || config.width;
48234 if(typeof size != "undefined"){
48235 this.el.setWidth(size);
48238 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
48239 orientation: Roo.SplitBar.HORIZONTAL,
48240 getBox : function(){
48241 if(this.collapsed){
48242 return this.collapsedEl.getBox();
48244 var box = this.el.getBox();
48246 box.width += this.split.el.getWidth();
48251 updateBox : function(box){
48252 if(this.split && !this.collapsed){
48253 var sw = this.split.el.getWidth();
48255 this.split.el.setLeft(box.x+box.width);
48256 this.split.el.setTop(box.y);
48257 this.split.el.setHeight(box.height);
48259 if(this.collapsed){
48260 this.updateBody(null, box.height);
48262 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48267 * Ext JS Library 1.1.1
48268 * Copyright(c) 2006-2007, Ext JS, LLC.
48270 * Originally Released Under LGPL - original licence link has changed is not relivant.
48273 * <script type="text/javascript">
48278 * Private internal class for reading and applying state
48280 Roo.LayoutStateManager = function(layout){
48281 // default empty state
48290 Roo.LayoutStateManager.prototype = {
48291 init : function(layout, provider){
48292 this.provider = provider;
48293 var state = provider.get(layout.id+"-layout-state");
48295 var wasUpdating = layout.isUpdating();
48297 layout.beginUpdate();
48299 for(var key in state){
48300 if(typeof state[key] != "function"){
48301 var rstate = state[key];
48302 var r = layout.getRegion(key);
48305 r.resizeTo(rstate.size);
48307 if(rstate.collapsed == true){
48310 r.expand(null, true);
48316 layout.endUpdate();
48318 this.state = state;
48320 this.layout = layout;
48321 layout.on("regionresized", this.onRegionResized, this);
48322 layout.on("regioncollapsed", this.onRegionCollapsed, this);
48323 layout.on("regionexpanded", this.onRegionExpanded, this);
48326 storeState : function(){
48327 this.provider.set(this.layout.id+"-layout-state", this.state);
48330 onRegionResized : function(region, newSize){
48331 this.state[region.getPosition()].size = newSize;
48335 onRegionCollapsed : function(region){
48336 this.state[region.getPosition()].collapsed = true;
48340 onRegionExpanded : function(region){
48341 this.state[region.getPosition()].collapsed = false;
48346 * Ext JS Library 1.1.1
48347 * Copyright(c) 2006-2007, Ext JS, LLC.
48349 * Originally Released Under LGPL - original licence link has changed is not relivant.
48352 * <script type="text/javascript">
48355 * @class Roo.ContentPanel
48356 * @extends Roo.util.Observable
48357 * A basic ContentPanel element.
48358 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
48359 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
48360 * @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
48361 * @cfg {Boolean} closable True if the panel can be closed/removed
48362 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
48363 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
48364 * @cfg {Toolbar} toolbar A toolbar for this panel
48365 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
48366 * @cfg {String} title The title for this panel
48367 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
48368 * @cfg {String} url Calls {@link #setUrl} with this value
48369 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
48370 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
48371 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
48372 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
48375 * Create a new ContentPanel.
48376 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
48377 * @param {String/Object} config A string to set only the title or a config object
48378 * @param {String} content (optional) Set the HTML content for this panel
48379 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
48381 Roo.ContentPanel = function(el, config, content){
48385 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
48389 if (config && config.parentLayout) {
48390 el = config.parentLayout.el.createChild();
48393 if(el.autoCreate){ // xtype is available if this is called from factory
48397 this.el = Roo.get(el);
48398 if(!this.el && config && config.autoCreate){
48399 if(typeof config.autoCreate == "object"){
48400 if(!config.autoCreate.id){
48401 config.autoCreate.id = config.id||el;
48403 this.el = Roo.DomHelper.append(document.body,
48404 config.autoCreate, true);
48406 this.el = Roo.DomHelper.append(document.body,
48407 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
48410 this.closable = false;
48411 this.loaded = false;
48412 this.active = false;
48413 if(typeof config == "string"){
48414 this.title = config;
48416 Roo.apply(this, config);
48419 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
48420 this.wrapEl = this.el.wrap();
48421 this.toolbar.container = this.el.insertSibling(false, 'before');
48422 this.toolbar = new Roo.Toolbar(this.toolbar);
48425 // xtype created footer. - not sure if will work as we normally have to render first..
48426 if (this.footer && !this.footer.el && this.footer.xtype) {
48427 if (!this.wrapEl) {
48428 this.wrapEl = this.el.wrap();
48431 this.footer.container = this.wrapEl.createChild();
48433 this.footer = Roo.factory(this.footer, Roo);
48438 this.resizeEl = Roo.get(this.resizeEl, true);
48440 this.resizeEl = this.el;
48442 // handle view.xtype
48444 if (this.view && typeof(this.view.xtype) != 'undefined') {
48445 this.view.el = this.el.appendChild(document.createElement("div"));
48446 this.view = Roo.factory(this.view);
48447 this.view.render && this.view.render(false, ''); // render blank..
48455 * Fires when this panel is activated.
48456 * @param {Roo.ContentPanel} this
48460 * @event deactivate
48461 * Fires when this panel is activated.
48462 * @param {Roo.ContentPanel} this
48464 "deactivate" : true,
48468 * Fires when this panel is resized if fitToFrame is true.
48469 * @param {Roo.ContentPanel} this
48470 * @param {Number} width The width after any component adjustments
48471 * @param {Number} height The height after any component adjustments
48477 * Fires when this tab is created
48478 * @param {Roo.ContentPanel} this
48485 if(this.autoScroll){
48486 this.resizeEl.setStyle("overflow", "auto");
48488 // fix randome scrolling
48489 this.el.on('scroll', function() {
48490 Roo.log('fix random scolling');
48491 this.scrollTo('top',0);
48494 content = content || this.content;
48496 this.setContent(content);
48498 if(config && config.url){
48499 this.setUrl(this.url, this.params, this.loadOnce);
48504 Roo.ContentPanel.superclass.constructor.call(this);
48506 this.fireEvent('render', this);
48509 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
48511 setRegion : function(region){
48512 this.region = region;
48514 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
48516 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
48521 * Returns the toolbar for this Panel if one was configured.
48522 * @return {Roo.Toolbar}
48524 getToolbar : function(){
48525 return this.toolbar;
48528 setActiveState : function(active){
48529 this.active = active;
48531 this.fireEvent("deactivate", this);
48533 this.fireEvent("activate", this);
48537 * Updates this panel's element
48538 * @param {String} content The new content
48539 * @param {Boolean} loadScripts (optional) true to look for and process scripts
48541 setContent : function(content, loadScripts){
48542 this.el.update(content, loadScripts);
48545 ignoreResize : function(w, h){
48546 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
48549 this.lastSize = {width: w, height: h};
48554 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
48555 * @return {Roo.UpdateManager} The UpdateManager
48557 getUpdateManager : function(){
48558 return this.el.getUpdateManager();
48561 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
48562 * @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:
48565 url: "your-url.php",
48566 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
48567 callback: yourFunction,
48568 scope: yourObject, //(optional scope)
48571 text: "Loading...",
48576 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
48577 * 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.
48578 * @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}
48579 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
48580 * @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.
48581 * @return {Roo.ContentPanel} this
48584 var um = this.el.getUpdateManager();
48585 um.update.apply(um, arguments);
48591 * 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.
48592 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
48593 * @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)
48594 * @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)
48595 * @return {Roo.UpdateManager} The UpdateManager
48597 setUrl : function(url, params, loadOnce){
48598 if(this.refreshDelegate){
48599 this.removeListener("activate", this.refreshDelegate);
48601 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
48602 this.on("activate", this.refreshDelegate);
48603 return this.el.getUpdateManager();
48606 _handleRefresh : function(url, params, loadOnce){
48607 if(!loadOnce || !this.loaded){
48608 var updater = this.el.getUpdateManager();
48609 updater.update(url, params, this._setLoaded.createDelegate(this));
48613 _setLoaded : function(){
48614 this.loaded = true;
48618 * Returns this panel's id
48621 getId : function(){
48626 * Returns this panel's element - used by regiosn to add.
48627 * @return {Roo.Element}
48629 getEl : function(){
48630 return this.wrapEl || this.el;
48633 adjustForComponents : function(width, height)
48635 //Roo.log('adjustForComponents ');
48636 if(this.resizeEl != this.el){
48637 width -= this.el.getFrameWidth('lr');
48638 height -= this.el.getFrameWidth('tb');
48641 var te = this.toolbar.getEl();
48642 height -= te.getHeight();
48643 te.setWidth(width);
48646 var te = this.footer.getEl();
48647 Roo.log("footer:" + te.getHeight());
48649 height -= te.getHeight();
48650 te.setWidth(width);
48654 if(this.adjustments){
48655 width += this.adjustments[0];
48656 height += this.adjustments[1];
48658 return {"width": width, "height": height};
48661 setSize : function(width, height){
48662 if(this.fitToFrame && !this.ignoreResize(width, height)){
48663 if(this.fitContainer && this.resizeEl != this.el){
48664 this.el.setSize(width, height);
48666 var size = this.adjustForComponents(width, height);
48667 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
48668 this.fireEvent('resize', this, size.width, size.height);
48673 * Returns this panel's title
48676 getTitle : function(){
48681 * Set this panel's title
48682 * @param {String} title
48684 setTitle : function(title){
48685 this.title = title;
48687 this.region.updatePanelTitle(this, title);
48692 * Returns true is this panel was configured to be closable
48693 * @return {Boolean}
48695 isClosable : function(){
48696 return this.closable;
48699 beforeSlide : function(){
48701 this.resizeEl.clip();
48704 afterSlide : function(){
48706 this.resizeEl.unclip();
48710 * Force a content refresh from the URL specified in the {@link #setUrl} method.
48711 * Will fail silently if the {@link #setUrl} method has not been called.
48712 * This does not activate the panel, just updates its content.
48714 refresh : function(){
48715 if(this.refreshDelegate){
48716 this.loaded = false;
48717 this.refreshDelegate();
48722 * Destroys this panel
48724 destroy : function(){
48725 this.el.removeAllListeners();
48726 var tempEl = document.createElement("span");
48727 tempEl.appendChild(this.el.dom);
48728 tempEl.innerHTML = "";
48734 * form - if the content panel contains a form - this is a reference to it.
48735 * @type {Roo.form.Form}
48739 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
48740 * This contains a reference to it.
48746 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
48756 * @param {Object} cfg Xtype definition of item to add.
48759 addxtype : function(cfg) {
48761 if (cfg.xtype.match(/^Form$/)) {
48764 //if (this.footer) {
48765 // el = this.footer.container.insertSibling(false, 'before');
48767 el = this.el.createChild();
48770 this.form = new Roo.form.Form(cfg);
48773 if ( this.form.allItems.length) this.form.render(el.dom);
48776 // should only have one of theses..
48777 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
48779 cfg.el = this.el.appendChild(document.createElement("div"));
48782 var ret = new Roo.factory(cfg);
48783 ret.render && ret.render(false, ''); // render blank..
48792 * @class Roo.GridPanel
48793 * @extends Roo.ContentPanel
48795 * Create a new GridPanel.
48796 * @param {Roo.grid.Grid} grid The grid for this panel
48797 * @param {String/Object} config A string to set only the panel's title, or a config object
48799 Roo.GridPanel = function(grid, config){
48802 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
48803 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
48805 this.wrapper.dom.appendChild(grid.getGridEl().dom);
48807 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
48810 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
48812 // xtype created footer. - not sure if will work as we normally have to render first..
48813 if (this.footer && !this.footer.el && this.footer.xtype) {
48815 this.footer.container = this.grid.getView().getFooterPanel(true);
48816 this.footer.dataSource = this.grid.dataSource;
48817 this.footer = Roo.factory(this.footer, Roo);
48821 grid.monitorWindowResize = false; // turn off autosizing
48822 grid.autoHeight = false;
48823 grid.autoWidth = false;
48825 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
48828 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
48829 getId : function(){
48830 return this.grid.id;
48834 * Returns the grid for this panel
48835 * @return {Roo.grid.Grid}
48837 getGrid : function(){
48841 setSize : function(width, height){
48842 if(!this.ignoreResize(width, height)){
48843 var grid = this.grid;
48844 var size = this.adjustForComponents(width, height);
48845 grid.getGridEl().setSize(size.width, size.height);
48850 beforeSlide : function(){
48851 this.grid.getView().scroller.clip();
48854 afterSlide : function(){
48855 this.grid.getView().scroller.unclip();
48858 destroy : function(){
48859 this.grid.destroy();
48861 Roo.GridPanel.superclass.destroy.call(this);
48867 * @class Roo.NestedLayoutPanel
48868 * @extends Roo.ContentPanel
48870 * Create a new NestedLayoutPanel.
48873 * @param {Roo.BorderLayout} layout The layout for this panel
48874 * @param {String/Object} config A string to set only the title or a config object
48876 Roo.NestedLayoutPanel = function(layout, config)
48878 // construct with only one argument..
48879 /* FIXME - implement nicer consturctors
48880 if (layout.layout) {
48882 layout = config.layout;
48883 delete config.layout;
48885 if (layout.xtype && !layout.getEl) {
48886 // then layout needs constructing..
48887 layout = Roo.factory(layout, Roo);
48892 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
48894 layout.monitorWindowResize = false; // turn off autosizing
48895 this.layout = layout;
48896 this.layout.getEl().addClass("x-layout-nested-layout");
48903 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
48905 setSize : function(width, height){
48906 if(!this.ignoreResize(width, height)){
48907 var size = this.adjustForComponents(width, height);
48908 var el = this.layout.getEl();
48909 el.setSize(size.width, size.height);
48910 var touch = el.dom.offsetWidth;
48911 this.layout.layout();
48912 // ie requires a double layout on the first pass
48913 if(Roo.isIE && !this.initialized){
48914 this.initialized = true;
48915 this.layout.layout();
48920 // activate all subpanels if not currently active..
48922 setActiveState : function(active){
48923 this.active = active;
48925 this.fireEvent("deactivate", this);
48929 this.fireEvent("activate", this);
48930 // not sure if this should happen before or after..
48931 if (!this.layout) {
48932 return; // should not happen..
48935 for (var r in this.layout.regions) {
48936 reg = this.layout.getRegion(r);
48937 if (reg.getActivePanel()) {
48938 //reg.showPanel(reg.getActivePanel()); // force it to activate..
48939 reg.setActivePanel(reg.getActivePanel());
48942 if (!reg.panels.length) {
48945 reg.showPanel(reg.getPanel(0));
48954 * Returns the nested BorderLayout for this panel
48955 * @return {Roo.BorderLayout}
48957 getLayout : function(){
48958 return this.layout;
48962 * Adds a xtype elements to the layout of the nested panel
48966 xtype : 'ContentPanel',
48973 xtype : 'NestedLayoutPanel',
48979 items : [ ... list of content panels or nested layout panels.. ]
48983 * @param {Object} cfg Xtype definition of item to add.
48985 addxtype : function(cfg) {
48986 return this.layout.addxtype(cfg);
48991 Roo.ScrollPanel = function(el, config, content){
48992 config = config || {};
48993 config.fitToFrame = true;
48994 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
48996 this.el.dom.style.overflow = "hidden";
48997 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
48998 this.el.removeClass("x-layout-inactive-content");
48999 this.el.on("mousewheel", this.onWheel, this);
49001 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
49002 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
49003 up.unselectable(); down.unselectable();
49004 up.on("click", this.scrollUp, this);
49005 down.on("click", this.scrollDown, this);
49006 up.addClassOnOver("x-scroller-btn-over");
49007 down.addClassOnOver("x-scroller-btn-over");
49008 up.addClassOnClick("x-scroller-btn-click");
49009 down.addClassOnClick("x-scroller-btn-click");
49010 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
49012 this.resizeEl = this.el;
49013 this.el = wrap; this.up = up; this.down = down;
49016 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
49018 wheelIncrement : 5,
49019 scrollUp : function(){
49020 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
49023 scrollDown : function(){
49024 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
49027 afterScroll : function(){
49028 var el = this.resizeEl;
49029 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
49030 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
49031 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
49034 setSize : function(){
49035 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
49036 this.afterScroll();
49039 onWheel : function(e){
49040 var d = e.getWheelDelta();
49041 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
49042 this.afterScroll();
49046 setContent : function(content, loadScripts){
49047 this.resizeEl.update(content, loadScripts);
49061 * @class Roo.TreePanel
49062 * @extends Roo.ContentPanel
49064 * Create a new TreePanel. - defaults to fit/scoll contents.
49065 * @param {String/Object} config A string to set only the panel's title, or a config object
49066 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
49068 Roo.TreePanel = function(config){
49069 var el = config.el;
49070 var tree = config.tree;
49071 delete config.tree;
49072 delete config.el; // hopefull!
49074 // wrapper for IE7 strict & safari scroll issue
49076 var treeEl = el.createChild();
49077 config.resizeEl = treeEl;
49081 Roo.TreePanel.superclass.constructor.call(this, el, config);
49084 this.tree = new Roo.tree.TreePanel(treeEl , tree);
49085 //console.log(tree);
49086 this.on('activate', function()
49088 if (this.tree.rendered) {
49091 //console.log('render tree');
49092 this.tree.render();
49094 // this should not be needed.. - it's actually the 'el' that resizes?
49095 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
49097 //this.on('resize', function (cp, w, h) {
49098 // this.tree.innerCt.setWidth(w);
49099 // this.tree.innerCt.setHeight(h);
49100 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
49107 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
49124 * Ext JS Library 1.1.1
49125 * Copyright(c) 2006-2007, Ext JS, LLC.
49127 * Originally Released Under LGPL - original licence link has changed is not relivant.
49130 * <script type="text/javascript">
49135 * @class Roo.ReaderLayout
49136 * @extends Roo.BorderLayout
49137 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
49138 * center region containing two nested regions (a top one for a list view and one for item preview below),
49139 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
49140 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
49141 * expedites the setup of the overall layout and regions for this common application style.
49144 var reader = new Roo.ReaderLayout();
49145 var CP = Roo.ContentPanel; // shortcut for adding
49147 reader.beginUpdate();
49148 reader.add("north", new CP("north", "North"));
49149 reader.add("west", new CP("west", {title: "West"}));
49150 reader.add("east", new CP("east", {title: "East"}));
49152 reader.regions.listView.add(new CP("listView", "List"));
49153 reader.regions.preview.add(new CP("preview", "Preview"));
49154 reader.endUpdate();
49157 * Create a new ReaderLayout
49158 * @param {Object} config Configuration options
49159 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
49160 * document.body if omitted)
49162 Roo.ReaderLayout = function(config, renderTo){
49163 var c = config || {size:{}};
49164 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
49165 north: c.north !== false ? Roo.apply({
49169 }, c.north) : false,
49170 west: c.west !== false ? Roo.apply({
49178 margins:{left:5,right:0,bottom:5,top:5},
49179 cmargins:{left:5,right:5,bottom:5,top:5}
49180 }, c.west) : false,
49181 east: c.east !== false ? Roo.apply({
49189 margins:{left:0,right:5,bottom:5,top:5},
49190 cmargins:{left:5,right:5,bottom:5,top:5}
49191 }, c.east) : false,
49192 center: Roo.apply({
49193 tabPosition: 'top',
49197 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
49201 this.el.addClass('x-reader');
49203 this.beginUpdate();
49205 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
49206 south: c.preview !== false ? Roo.apply({
49213 cmargins:{top:5,left:0, right:0, bottom:0}
49214 }, c.preview) : false,
49215 center: Roo.apply({
49221 this.add('center', new Roo.NestedLayoutPanel(inner,
49222 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
49226 this.regions.preview = inner.getRegion('south');
49227 this.regions.listView = inner.getRegion('center');
49230 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
49232 * Ext JS Library 1.1.1
49233 * Copyright(c) 2006-2007, Ext JS, LLC.
49235 * Originally Released Under LGPL - original licence link has changed is not relivant.
49238 * <script type="text/javascript">
49242 * @class Roo.grid.Grid
49243 * @extends Roo.util.Observable
49244 * This class represents the primary interface of a component based grid control.
49245 * <br><br>Usage:<pre><code>
49246 var grid = new Roo.grid.Grid("my-container-id", {
49249 selModel: mySelectionModel,
49250 autoSizeColumns: true,
49251 monitorWindowResize: false,
49252 trackMouseOver: true
49257 * <b>Common Problems:</b><br/>
49258 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
49259 * element will correct this<br/>
49260 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
49261 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
49262 * are unpredictable.<br/>
49263 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
49264 * grid to calculate dimensions/offsets.<br/>
49266 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49267 * The container MUST have some type of size defined for the grid to fill. The container will be
49268 * automatically set to position relative if it isn't already.
49269 * @param {Object} config A config object that sets properties on this grid.
49271 Roo.grid.Grid = function(container, config){
49272 // initialize the container
49273 this.container = Roo.get(container);
49274 this.container.update("");
49275 this.container.setStyle("overflow", "hidden");
49276 this.container.addClass('x-grid-container');
49278 this.id = this.container.id;
49280 Roo.apply(this, config);
49281 // check and correct shorthanded configs
49283 this.dataSource = this.ds;
49287 this.colModel = this.cm;
49291 this.selModel = this.sm;
49295 if (this.selModel) {
49296 this.selModel = Roo.factory(this.selModel, Roo.grid);
49297 this.sm = this.selModel;
49298 this.sm.xmodule = this.xmodule || false;
49300 if (typeof(this.colModel.config) == 'undefined') {
49301 this.colModel = new Roo.grid.ColumnModel(this.colModel);
49302 this.cm = this.colModel;
49303 this.cm.xmodule = this.xmodule || false;
49305 if (this.dataSource) {
49306 this.dataSource= Roo.factory(this.dataSource, Roo.data);
49307 this.ds = this.dataSource;
49308 this.ds.xmodule = this.xmodule || false;
49315 this.container.setWidth(this.width);
49319 this.container.setHeight(this.height);
49326 * The raw click event for the entire grid.
49327 * @param {Roo.EventObject} e
49332 * The raw dblclick event for the entire grid.
49333 * @param {Roo.EventObject} e
49337 * @event contextmenu
49338 * The raw contextmenu event for the entire grid.
49339 * @param {Roo.EventObject} e
49341 "contextmenu" : true,
49344 * The raw mousedown event for the entire grid.
49345 * @param {Roo.EventObject} e
49347 "mousedown" : true,
49350 * The raw mouseup event for the entire grid.
49351 * @param {Roo.EventObject} e
49356 * The raw mouseover event for the entire grid.
49357 * @param {Roo.EventObject} e
49359 "mouseover" : true,
49362 * The raw mouseout event for the entire grid.
49363 * @param {Roo.EventObject} e
49368 * The raw keypress event for the entire grid.
49369 * @param {Roo.EventObject} e
49374 * The raw keydown event for the entire grid.
49375 * @param {Roo.EventObject} e
49383 * Fires when a cell is clicked
49384 * @param {Grid} this
49385 * @param {Number} rowIndex
49386 * @param {Number} columnIndex
49387 * @param {Roo.EventObject} e
49389 "cellclick" : true,
49391 * @event celldblclick
49392 * Fires when a cell is double clicked
49393 * @param {Grid} this
49394 * @param {Number} rowIndex
49395 * @param {Number} columnIndex
49396 * @param {Roo.EventObject} e
49398 "celldblclick" : true,
49401 * Fires when a row is clicked
49402 * @param {Grid} this
49403 * @param {Number} rowIndex
49404 * @param {Roo.EventObject} e
49408 * @event rowdblclick
49409 * Fires when a row is double clicked
49410 * @param {Grid} this
49411 * @param {Number} rowIndex
49412 * @param {Roo.EventObject} e
49414 "rowdblclick" : true,
49416 * @event headerclick
49417 * Fires when a header is clicked
49418 * @param {Grid} this
49419 * @param {Number} columnIndex
49420 * @param {Roo.EventObject} e
49422 "headerclick" : true,
49424 * @event headerdblclick
49425 * Fires when a header cell is double clicked
49426 * @param {Grid} this
49427 * @param {Number} columnIndex
49428 * @param {Roo.EventObject} e
49430 "headerdblclick" : true,
49432 * @event rowcontextmenu
49433 * Fires when a row is right clicked
49434 * @param {Grid} this
49435 * @param {Number} rowIndex
49436 * @param {Roo.EventObject} e
49438 "rowcontextmenu" : true,
49440 * @event cellcontextmenu
49441 * Fires when a cell is right clicked
49442 * @param {Grid} this
49443 * @param {Number} rowIndex
49444 * @param {Number} cellIndex
49445 * @param {Roo.EventObject} e
49447 "cellcontextmenu" : true,
49449 * @event headercontextmenu
49450 * Fires when a header is right clicked
49451 * @param {Grid} this
49452 * @param {Number} columnIndex
49453 * @param {Roo.EventObject} e
49455 "headercontextmenu" : true,
49457 * @event bodyscroll
49458 * Fires when the body element is scrolled
49459 * @param {Number} scrollLeft
49460 * @param {Number} scrollTop
49462 "bodyscroll" : true,
49464 * @event columnresize
49465 * Fires when the user resizes a column
49466 * @param {Number} columnIndex
49467 * @param {Number} newSize
49469 "columnresize" : true,
49471 * @event columnmove
49472 * Fires when the user moves a column
49473 * @param {Number} oldIndex
49474 * @param {Number} newIndex
49476 "columnmove" : true,
49479 * Fires when row(s) start being dragged
49480 * @param {Grid} this
49481 * @param {Roo.GridDD} dd The drag drop object
49482 * @param {event} e The raw browser event
49484 "startdrag" : true,
49487 * Fires when a drag operation is complete
49488 * @param {Grid} this
49489 * @param {Roo.GridDD} dd The drag drop object
49490 * @param {event} e The raw browser event
49495 * Fires when dragged row(s) are dropped on a valid DD target
49496 * @param {Grid} this
49497 * @param {Roo.GridDD} dd The drag drop object
49498 * @param {String} targetId The target drag drop object
49499 * @param {event} e The raw browser event
49504 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
49505 * @param {Grid} this
49506 * @param {Roo.GridDD} dd The drag drop object
49507 * @param {String} targetId The target drag drop object
49508 * @param {event} e The raw browser event
49513 * Fires when the dragged row(s) first cross another DD target while being dragged
49514 * @param {Grid} this
49515 * @param {Roo.GridDD} dd The drag drop object
49516 * @param {String} targetId The target drag drop object
49517 * @param {event} e The raw browser event
49519 "dragenter" : true,
49522 * Fires when the dragged row(s) leave another DD target while being dragged
49523 * @param {Grid} this
49524 * @param {Roo.GridDD} dd The drag drop object
49525 * @param {String} targetId The target drag drop object
49526 * @param {event} e The raw browser event
49531 * Fires when a row is rendered, so you can change add a style to it.
49532 * @param {GridView} gridview The grid view
49533 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
49539 * Fires when the grid is rendered
49540 * @param {Grid} grid
49545 Roo.grid.Grid.superclass.constructor.call(this);
49547 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
49550 * @cfg {String} ddGroup - drag drop group.
49554 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
49556 minColumnWidth : 25,
49559 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
49560 * <b>on initial render.</b> It is more efficient to explicitly size the columns
49561 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
49563 autoSizeColumns : false,
49566 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
49568 autoSizeHeaders : true,
49571 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
49573 monitorWindowResize : true,
49576 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
49577 * rows measured to get a columns size. Default is 0 (all rows).
49579 maxRowsToMeasure : 0,
49582 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
49584 trackMouseOver : true,
49587 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
49591 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
49593 enableDragDrop : false,
49596 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
49598 enableColumnMove : true,
49601 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
49603 enableColumnHide : true,
49606 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
49608 enableRowHeightSync : false,
49611 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
49616 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
49618 autoHeight : false,
49621 * @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.
49623 autoExpandColumn : false,
49626 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
49629 autoExpandMin : 50,
49632 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
49634 autoExpandMax : 1000,
49637 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
49642 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
49646 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
49656 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
49657 * of a fixed width. Default is false.
49660 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
49663 * Called once after all setup has been completed and the grid is ready to be rendered.
49664 * @return {Roo.grid.Grid} this
49666 render : function()
49668 var c = this.container;
49669 // try to detect autoHeight/width mode
49670 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
49671 this.autoHeight = true;
49673 var view = this.getView();
49676 c.on("click", this.onClick, this);
49677 c.on("dblclick", this.onDblClick, this);
49678 c.on("contextmenu", this.onContextMenu, this);
49679 c.on("keydown", this.onKeyDown, this);
49681 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
49683 this.getSelectionModel().init(this);
49688 this.loadMask = new Roo.LoadMask(this.container,
49689 Roo.apply({store:this.dataSource}, this.loadMask));
49693 if (this.toolbar && this.toolbar.xtype) {
49694 this.toolbar.container = this.getView().getHeaderPanel(true);
49695 this.toolbar = new Roo.Toolbar(this.toolbar);
49697 if (this.footer && this.footer.xtype) {
49698 this.footer.dataSource = this.getDataSource();
49699 this.footer.container = this.getView().getFooterPanel(true);
49700 this.footer = Roo.factory(this.footer, Roo);
49702 if (this.dropTarget && this.dropTarget.xtype) {
49703 delete this.dropTarget.xtype;
49704 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
49708 this.rendered = true;
49709 this.fireEvent('render', this);
49714 * Reconfigures the grid to use a different Store and Column Model.
49715 * The View will be bound to the new objects and refreshed.
49716 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
49717 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
49719 reconfigure : function(dataSource, colModel){
49721 this.loadMask.destroy();
49722 this.loadMask = new Roo.LoadMask(this.container,
49723 Roo.apply({store:dataSource}, this.loadMask));
49725 this.view.bind(dataSource, colModel);
49726 this.dataSource = dataSource;
49727 this.colModel = colModel;
49728 this.view.refresh(true);
49732 onKeyDown : function(e){
49733 this.fireEvent("keydown", e);
49737 * Destroy this grid.
49738 * @param {Boolean} removeEl True to remove the element
49740 destroy : function(removeEl, keepListeners){
49742 this.loadMask.destroy();
49744 var c = this.container;
49745 c.removeAllListeners();
49746 this.view.destroy();
49747 this.colModel.purgeListeners();
49748 if(!keepListeners){
49749 this.purgeListeners();
49752 if(removeEl === true){
49758 processEvent : function(name, e){
49759 this.fireEvent(name, e);
49760 var t = e.getTarget();
49762 var header = v.findHeaderIndex(t);
49763 if(header !== false){
49764 this.fireEvent("header" + name, this, header, e);
49766 var row = v.findRowIndex(t);
49767 var cell = v.findCellIndex(t);
49769 this.fireEvent("row" + name, this, row, e);
49770 if(cell !== false){
49771 this.fireEvent("cell" + name, this, row, cell, e);
49778 onClick : function(e){
49779 this.processEvent("click", e);
49783 onContextMenu : function(e, t){
49784 this.processEvent("contextmenu", e);
49788 onDblClick : function(e){
49789 this.processEvent("dblclick", e);
49793 walkCells : function(row, col, step, fn, scope){
49794 var cm = this.colModel, clen = cm.getColumnCount();
49795 var ds = this.dataSource, rlen = ds.getCount(), first = true;
49807 if(fn.call(scope || this, row, col, cm) === true){
49825 if(fn.call(scope || this, row, col, cm) === true){
49837 getSelections : function(){
49838 return this.selModel.getSelections();
49842 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
49843 * but if manual update is required this method will initiate it.
49845 autoSize : function(){
49847 this.view.layout();
49848 if(this.view.adjustForScroll){
49849 this.view.adjustForScroll();
49855 * Returns the grid's underlying element.
49856 * @return {Element} The element
49858 getGridEl : function(){
49859 return this.container;
49862 // private for compatibility, overridden by editor grid
49863 stopEditing : function(){},
49866 * Returns the grid's SelectionModel.
49867 * @return {SelectionModel}
49869 getSelectionModel : function(){
49870 if(!this.selModel){
49871 this.selModel = new Roo.grid.RowSelectionModel();
49873 return this.selModel;
49877 * Returns the grid's DataSource.
49878 * @return {DataSource}
49880 getDataSource : function(){
49881 return this.dataSource;
49885 * Returns the grid's ColumnModel.
49886 * @return {ColumnModel}
49888 getColumnModel : function(){
49889 return this.colModel;
49893 * Returns the grid's GridView object.
49894 * @return {GridView}
49896 getView : function(){
49898 this.view = new Roo.grid.GridView(this.viewConfig);
49903 * Called to get grid's drag proxy text, by default returns this.ddText.
49906 getDragDropText : function(){
49907 var count = this.selModel.getCount();
49908 return String.format(this.ddText, count, count == 1 ? '' : 's');
49912 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
49913 * %0 is replaced with the number of selected rows.
49916 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
49918 * Ext JS Library 1.1.1
49919 * Copyright(c) 2006-2007, Ext JS, LLC.
49921 * Originally Released Under LGPL - original licence link has changed is not relivant.
49924 * <script type="text/javascript">
49927 Roo.grid.AbstractGridView = function(){
49931 "beforerowremoved" : true,
49932 "beforerowsinserted" : true,
49933 "beforerefresh" : true,
49934 "rowremoved" : true,
49935 "rowsinserted" : true,
49936 "rowupdated" : true,
49939 Roo.grid.AbstractGridView.superclass.constructor.call(this);
49942 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
49943 rowClass : "x-grid-row",
49944 cellClass : "x-grid-cell",
49945 tdClass : "x-grid-td",
49946 hdClass : "x-grid-hd",
49947 splitClass : "x-grid-hd-split",
49949 init: function(grid){
49951 var cid = this.grid.getGridEl().id;
49952 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
49953 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
49954 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
49955 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
49958 getColumnRenderers : function(){
49959 var renderers = [];
49960 var cm = this.grid.colModel;
49961 var colCount = cm.getColumnCount();
49962 for(var i = 0; i < colCount; i++){
49963 renderers[i] = cm.getRenderer(i);
49968 getColumnIds : function(){
49970 var cm = this.grid.colModel;
49971 var colCount = cm.getColumnCount();
49972 for(var i = 0; i < colCount; i++){
49973 ids[i] = cm.getColumnId(i);
49978 getDataIndexes : function(){
49979 if(!this.indexMap){
49980 this.indexMap = this.buildIndexMap();
49982 return this.indexMap.colToData;
49985 getColumnIndexByDataIndex : function(dataIndex){
49986 if(!this.indexMap){
49987 this.indexMap = this.buildIndexMap();
49989 return this.indexMap.dataToCol[dataIndex];
49993 * Set a css style for a column dynamically.
49994 * @param {Number} colIndex The index of the column
49995 * @param {String} name The css property name
49996 * @param {String} value The css value
49998 setCSSStyle : function(colIndex, name, value){
49999 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
50000 Roo.util.CSS.updateRule(selector, name, value);
50003 generateRules : function(cm){
50004 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
50005 Roo.util.CSS.removeStyleSheet(rulesId);
50006 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50007 var cid = cm.getColumnId(i);
50008 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
50009 this.tdSelector, cid, " {\n}\n",
50010 this.hdSelector, cid, " {\n}\n",
50011 this.splitSelector, cid, " {\n}\n");
50013 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
50017 * Ext JS Library 1.1.1
50018 * Copyright(c) 2006-2007, Ext JS, LLC.
50020 * Originally Released Under LGPL - original licence link has changed is not relivant.
50023 * <script type="text/javascript">
50027 // This is a support class used internally by the Grid components
50028 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
50030 this.view = grid.getView();
50031 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
50032 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
50034 this.setHandleElId(Roo.id(hd));
50035 this.setOuterHandleElId(Roo.id(hd2));
50037 this.scroll = false;
50039 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
50041 getDragData : function(e){
50042 var t = Roo.lib.Event.getTarget(e);
50043 var h = this.view.findHeaderCell(t);
50045 return {ddel: h.firstChild, header:h};
50050 onInitDrag : function(e){
50051 this.view.headersDisabled = true;
50052 var clone = this.dragData.ddel.cloneNode(true);
50053 clone.id = Roo.id();
50054 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
50055 this.proxy.update(clone);
50059 afterValidDrop : function(){
50061 setTimeout(function(){
50062 v.headersDisabled = false;
50066 afterInvalidDrop : function(){
50068 setTimeout(function(){
50069 v.headersDisabled = false;
50075 * Ext JS Library 1.1.1
50076 * Copyright(c) 2006-2007, Ext JS, LLC.
50078 * Originally Released Under LGPL - original licence link has changed is not relivant.
50081 * <script type="text/javascript">
50084 // This is a support class used internally by the Grid components
50085 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
50087 this.view = grid.getView();
50088 // split the proxies so they don't interfere with mouse events
50089 this.proxyTop = Roo.DomHelper.append(document.body, {
50090 cls:"col-move-top", html:" "
50092 this.proxyBottom = Roo.DomHelper.append(document.body, {
50093 cls:"col-move-bottom", html:" "
50095 this.proxyTop.hide = this.proxyBottom.hide = function(){
50096 this.setLeftTop(-100,-100);
50097 this.setStyle("visibility", "hidden");
50099 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
50100 // temporarily disabled
50101 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
50102 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
50104 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
50105 proxyOffsets : [-4, -9],
50106 fly: Roo.Element.fly,
50108 getTargetFromEvent : function(e){
50109 var t = Roo.lib.Event.getTarget(e);
50110 var cindex = this.view.findCellIndex(t);
50111 if(cindex !== false){
50112 return this.view.getHeaderCell(cindex);
50117 nextVisible : function(h){
50118 var v = this.view, cm = this.grid.colModel;
50121 if(!cm.isHidden(v.getCellIndex(h))){
50129 prevVisible : function(h){
50130 var v = this.view, cm = this.grid.colModel;
50133 if(!cm.isHidden(v.getCellIndex(h))){
50141 positionIndicator : function(h, n, e){
50142 var x = Roo.lib.Event.getPageX(e);
50143 var r = Roo.lib.Dom.getRegion(n.firstChild);
50144 var px, pt, py = r.top + this.proxyOffsets[1];
50145 if((r.right - x) <= (r.right-r.left)/2){
50146 px = r.right+this.view.borderWidth;
50152 var oldIndex = this.view.getCellIndex(h);
50153 var newIndex = this.view.getCellIndex(n);
50155 if(this.grid.colModel.isFixed(newIndex)){
50159 var locked = this.grid.colModel.isLocked(newIndex);
50164 if(oldIndex < newIndex){
50167 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
50170 px += this.proxyOffsets[0];
50171 this.proxyTop.setLeftTop(px, py);
50172 this.proxyTop.show();
50173 if(!this.bottomOffset){
50174 this.bottomOffset = this.view.mainHd.getHeight();
50176 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
50177 this.proxyBottom.show();
50181 onNodeEnter : function(n, dd, e, data){
50182 if(data.header != n){
50183 this.positionIndicator(data.header, n, e);
50187 onNodeOver : function(n, dd, e, data){
50188 var result = false;
50189 if(data.header != n){
50190 result = this.positionIndicator(data.header, n, e);
50193 this.proxyTop.hide();
50194 this.proxyBottom.hide();
50196 return result ? this.dropAllowed : this.dropNotAllowed;
50199 onNodeOut : function(n, dd, e, data){
50200 this.proxyTop.hide();
50201 this.proxyBottom.hide();
50204 onNodeDrop : function(n, dd, e, data){
50205 var h = data.header;
50207 var cm = this.grid.colModel;
50208 var x = Roo.lib.Event.getPageX(e);
50209 var r = Roo.lib.Dom.getRegion(n.firstChild);
50210 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
50211 var oldIndex = this.view.getCellIndex(h);
50212 var newIndex = this.view.getCellIndex(n);
50213 var locked = cm.isLocked(newIndex);
50217 if(oldIndex < newIndex){
50220 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
50223 cm.setLocked(oldIndex, locked, true);
50224 cm.moveColumn(oldIndex, newIndex);
50225 this.grid.fireEvent("columnmove", oldIndex, newIndex);
50233 * Ext JS Library 1.1.1
50234 * Copyright(c) 2006-2007, Ext JS, LLC.
50236 * Originally Released Under LGPL - original licence link has changed is not relivant.
50239 * <script type="text/javascript">
50243 * @class Roo.grid.GridView
50244 * @extends Roo.util.Observable
50247 * @param {Object} config
50249 Roo.grid.GridView = function(config){
50250 Roo.grid.GridView.superclass.constructor.call(this);
50253 Roo.apply(this, config);
50256 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
50258 unselectable : 'unselectable="on"',
50259 unselectableCls : 'x-unselectable',
50262 rowClass : "x-grid-row",
50264 cellClass : "x-grid-col",
50266 tdClass : "x-grid-td",
50268 hdClass : "x-grid-hd",
50270 splitClass : "x-grid-split",
50272 sortClasses : ["sort-asc", "sort-desc"],
50274 enableMoveAnim : false,
50278 dh : Roo.DomHelper,
50280 fly : Roo.Element.fly,
50282 css : Roo.util.CSS,
50288 scrollIncrement : 22,
50290 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
50292 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
50294 bind : function(ds, cm){
50296 this.ds.un("load", this.onLoad, this);
50297 this.ds.un("datachanged", this.onDataChange, this);
50298 this.ds.un("add", this.onAdd, this);
50299 this.ds.un("remove", this.onRemove, this);
50300 this.ds.un("update", this.onUpdate, this);
50301 this.ds.un("clear", this.onClear, this);
50304 ds.on("load", this.onLoad, this);
50305 ds.on("datachanged", this.onDataChange, this);
50306 ds.on("add", this.onAdd, this);
50307 ds.on("remove", this.onRemove, this);
50308 ds.on("update", this.onUpdate, this);
50309 ds.on("clear", this.onClear, this);
50314 this.cm.un("widthchange", this.onColWidthChange, this);
50315 this.cm.un("headerchange", this.onHeaderChange, this);
50316 this.cm.un("hiddenchange", this.onHiddenChange, this);
50317 this.cm.un("columnmoved", this.onColumnMove, this);
50318 this.cm.un("columnlockchange", this.onColumnLock, this);
50321 this.generateRules(cm);
50322 cm.on("widthchange", this.onColWidthChange, this);
50323 cm.on("headerchange", this.onHeaderChange, this);
50324 cm.on("hiddenchange", this.onHiddenChange, this);
50325 cm.on("columnmoved", this.onColumnMove, this);
50326 cm.on("columnlockchange", this.onColumnLock, this);
50331 init: function(grid){
50332 Roo.grid.GridView.superclass.init.call(this, grid);
50334 this.bind(grid.dataSource, grid.colModel);
50336 grid.on("headerclick", this.handleHeaderClick, this);
50338 if(grid.trackMouseOver){
50339 grid.on("mouseover", this.onRowOver, this);
50340 grid.on("mouseout", this.onRowOut, this);
50342 grid.cancelTextSelection = function(){};
50343 this.gridId = grid.id;
50345 var tpls = this.templates || {};
50348 tpls.master = new Roo.Template(
50349 '<div class="x-grid" hidefocus="true">',
50350 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
50351 '<div class="x-grid-topbar"></div>',
50352 '<div class="x-grid-scroller"><div></div></div>',
50353 '<div class="x-grid-locked">',
50354 '<div class="x-grid-header">{lockedHeader}</div>',
50355 '<div class="x-grid-body">{lockedBody}</div>',
50357 '<div class="x-grid-viewport">',
50358 '<div class="x-grid-header">{header}</div>',
50359 '<div class="x-grid-body">{body}</div>',
50361 '<div class="x-grid-bottombar"></div>',
50363 '<div class="x-grid-resize-proxy"> </div>',
50366 tpls.master.disableformats = true;
50370 tpls.header = new Roo.Template(
50371 '<table border="0" cellspacing="0" cellpadding="0">',
50372 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
50375 tpls.header.disableformats = true;
50377 tpls.header.compile();
50380 tpls.hcell = new Roo.Template(
50381 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
50382 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
50385 tpls.hcell.disableFormats = true;
50387 tpls.hcell.compile();
50390 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
50391 this.unselectableCls + '" ' + this.unselectable +'> </div>');
50392 tpls.hsplit.disableFormats = true;
50394 tpls.hsplit.compile();
50397 tpls.body = new Roo.Template(
50398 '<table border="0" cellspacing="0" cellpadding="0">',
50399 "<tbody>{rows}</tbody>",
50402 tpls.body.disableFormats = true;
50404 tpls.body.compile();
50407 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
50408 tpls.row.disableFormats = true;
50410 tpls.row.compile();
50413 tpls.cell = new Roo.Template(
50414 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
50415 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
50416 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
50419 tpls.cell.disableFormats = true;
50421 tpls.cell.compile();
50423 this.templates = tpls;
50426 // remap these for backwards compat
50427 onColWidthChange : function(){
50428 this.updateColumns.apply(this, arguments);
50430 onHeaderChange : function(){
50431 this.updateHeaders.apply(this, arguments);
50433 onHiddenChange : function(){
50434 this.handleHiddenChange.apply(this, arguments);
50436 onColumnMove : function(){
50437 this.handleColumnMove.apply(this, arguments);
50439 onColumnLock : function(){
50440 this.handleLockChange.apply(this, arguments);
50443 onDataChange : function(){
50445 this.updateHeaderSortState();
50448 onClear : function(){
50452 onUpdate : function(ds, record){
50453 this.refreshRow(record);
50456 refreshRow : function(record){
50457 var ds = this.ds, index;
50458 if(typeof record == 'number'){
50460 record = ds.getAt(index);
50462 index = ds.indexOf(record);
50464 this.insertRows(ds, index, index, true);
50465 this.onRemove(ds, record, index+1, true);
50466 this.syncRowHeights(index, index);
50468 this.fireEvent("rowupdated", this, index, record);
50471 onAdd : function(ds, records, index){
50472 this.insertRows(ds, index, index + (records.length-1));
50475 onRemove : function(ds, record, index, isUpdate){
50476 if(isUpdate !== true){
50477 this.fireEvent("beforerowremoved", this, index, record);
50479 var bt = this.getBodyTable(), lt = this.getLockedTable();
50480 if(bt.rows[index]){
50481 bt.firstChild.removeChild(bt.rows[index]);
50483 if(lt.rows[index]){
50484 lt.firstChild.removeChild(lt.rows[index]);
50486 if(isUpdate !== true){
50487 this.stripeRows(index);
50488 this.syncRowHeights(index, index);
50490 this.fireEvent("rowremoved", this, index, record);
50494 onLoad : function(){
50495 this.scrollToTop();
50499 * Scrolls the grid to the top
50501 scrollToTop : function(){
50503 this.scroller.dom.scrollTop = 0;
50509 * Gets a panel in the header of the grid that can be used for toolbars etc.
50510 * After modifying the contents of this panel a call to grid.autoSize() may be
50511 * required to register any changes in size.
50512 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
50513 * @return Roo.Element
50515 getHeaderPanel : function(doShow){
50517 this.headerPanel.show();
50519 return this.headerPanel;
50523 * Gets a panel in the footer of the grid that can be used for toolbars etc.
50524 * After modifying the contents of this panel a call to grid.autoSize() may be
50525 * required to register any changes in size.
50526 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
50527 * @return Roo.Element
50529 getFooterPanel : function(doShow){
50531 this.footerPanel.show();
50533 return this.footerPanel;
50536 initElements : function(){
50537 var E = Roo.Element;
50538 var el = this.grid.getGridEl().dom.firstChild;
50539 var cs = el.childNodes;
50541 this.el = new E(el);
50543 this.focusEl = new E(el.firstChild);
50544 this.focusEl.swallowEvent("click", true);
50546 this.headerPanel = new E(cs[1]);
50547 this.headerPanel.enableDisplayMode("block");
50549 this.scroller = new E(cs[2]);
50550 this.scrollSizer = new E(this.scroller.dom.firstChild);
50552 this.lockedWrap = new E(cs[3]);
50553 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
50554 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
50556 this.mainWrap = new E(cs[4]);
50557 this.mainHd = new E(this.mainWrap.dom.firstChild);
50558 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
50560 this.footerPanel = new E(cs[5]);
50561 this.footerPanel.enableDisplayMode("block");
50563 this.resizeProxy = new E(cs[6]);
50565 this.headerSelector = String.format(
50566 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
50567 this.lockedHd.id, this.mainHd.id
50570 this.splitterSelector = String.format(
50571 '#{0} div.x-grid-split, #{1} div.x-grid-split',
50572 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
50575 idToCssName : function(s)
50577 return s.replace(/[^a-z0-9]+/ig, '-');
50580 getHeaderCell : function(index){
50581 return Roo.DomQuery.select(this.headerSelector)[index];
50584 getHeaderCellMeasure : function(index){
50585 return this.getHeaderCell(index).firstChild;
50588 getHeaderCellText : function(index){
50589 return this.getHeaderCell(index).firstChild.firstChild;
50592 getLockedTable : function(){
50593 return this.lockedBody.dom.firstChild;
50596 getBodyTable : function(){
50597 return this.mainBody.dom.firstChild;
50600 getLockedRow : function(index){
50601 return this.getLockedTable().rows[index];
50604 getRow : function(index){
50605 return this.getBodyTable().rows[index];
50608 getRowComposite : function(index){
50610 this.rowEl = new Roo.CompositeElementLite();
50612 var els = [], lrow, mrow;
50613 if(lrow = this.getLockedRow(index)){
50616 if(mrow = this.getRow(index)){
50619 this.rowEl.elements = els;
50623 * Gets the 'td' of the cell
50625 * @param {Integer} rowIndex row to select
50626 * @param {Integer} colIndex column to select
50630 getCell : function(rowIndex, colIndex){
50631 var locked = this.cm.getLockedCount();
50633 if(colIndex < locked){
50634 source = this.lockedBody.dom.firstChild;
50636 source = this.mainBody.dom.firstChild;
50637 colIndex -= locked;
50639 return source.rows[rowIndex].childNodes[colIndex];
50642 getCellText : function(rowIndex, colIndex){
50643 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
50646 getCellBox : function(cell){
50647 var b = this.fly(cell).getBox();
50648 if(Roo.isOpera){ // opera fails to report the Y
50649 b.y = cell.offsetTop + this.mainBody.getY();
50654 getCellIndex : function(cell){
50655 var id = String(cell.className).match(this.cellRE);
50657 return parseInt(id[1], 10);
50662 findHeaderIndex : function(n){
50663 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
50664 return r ? this.getCellIndex(r) : false;
50667 findHeaderCell : function(n){
50668 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
50669 return r ? r : false;
50672 findRowIndex : function(n){
50676 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
50677 return r ? r.rowIndex : false;
50680 findCellIndex : function(node){
50681 var stop = this.el.dom;
50682 while(node && node != stop){
50683 if(this.findRE.test(node.className)){
50684 return this.getCellIndex(node);
50686 node = node.parentNode;
50691 getColumnId : function(index){
50692 return this.cm.getColumnId(index);
50695 getSplitters : function()
50697 if(this.splitterSelector){
50698 return Roo.DomQuery.select(this.splitterSelector);
50704 getSplitter : function(index){
50705 return this.getSplitters()[index];
50708 onRowOver : function(e, t){
50710 if((row = this.findRowIndex(t)) !== false){
50711 this.getRowComposite(row).addClass("x-grid-row-over");
50715 onRowOut : function(e, t){
50717 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
50718 this.getRowComposite(row).removeClass("x-grid-row-over");
50722 renderHeaders : function(){
50724 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
50725 var cb = [], lb = [], sb = [], lsb = [], p = {};
50726 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50727 p.cellId = "x-grid-hd-0-" + i;
50728 p.splitId = "x-grid-csplit-0-" + i;
50729 p.id = cm.getColumnId(i);
50730 p.title = cm.getColumnTooltip(i) || "";
50731 p.value = cm.getColumnHeader(i) || "";
50732 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
50733 if(!cm.isLocked(i)){
50734 cb[cb.length] = ct.apply(p);
50735 sb[sb.length] = st.apply(p);
50737 lb[lb.length] = ct.apply(p);
50738 lsb[lsb.length] = st.apply(p);
50741 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
50742 ht.apply({cells: cb.join(""), splits:sb.join("")})];
50745 updateHeaders : function(){
50746 var html = this.renderHeaders();
50747 this.lockedHd.update(html[0]);
50748 this.mainHd.update(html[1]);
50752 * Focuses the specified row.
50753 * @param {Number} row The row index
50755 focusRow : function(row)
50757 //Roo.log('GridView.focusRow');
50758 var x = this.scroller.dom.scrollLeft;
50759 this.focusCell(row, 0, false);
50760 this.scroller.dom.scrollLeft = x;
50764 * Focuses the specified cell.
50765 * @param {Number} row The row index
50766 * @param {Number} col The column index
50767 * @param {Boolean} hscroll false to disable horizontal scrolling
50769 focusCell : function(row, col, hscroll)
50771 //Roo.log('GridView.focusCell');
50772 var el = this.ensureVisible(row, col, hscroll);
50773 this.focusEl.alignTo(el, "tl-tl");
50775 this.focusEl.focus();
50777 this.focusEl.focus.defer(1, this.focusEl);
50782 * Scrolls the specified cell into view
50783 * @param {Number} row The row index
50784 * @param {Number} col The column index
50785 * @param {Boolean} hscroll false to disable horizontal scrolling
50787 ensureVisible : function(row, col, hscroll)
50789 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
50790 //return null; //disable for testing.
50791 if(typeof row != "number"){
50792 row = row.rowIndex;
50794 if(row < 0 && row >= this.ds.getCount()){
50797 col = (col !== undefined ? col : 0);
50798 var cm = this.grid.colModel;
50799 while(cm.isHidden(col)){
50803 var el = this.getCell(row, col);
50807 var c = this.scroller.dom;
50809 var ctop = parseInt(el.offsetTop, 10);
50810 var cleft = parseInt(el.offsetLeft, 10);
50811 var cbot = ctop + el.offsetHeight;
50812 var cright = cleft + el.offsetWidth;
50814 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
50815 var stop = parseInt(c.scrollTop, 10);
50816 var sleft = parseInt(c.scrollLeft, 10);
50817 var sbot = stop + ch;
50818 var sright = sleft + c.clientWidth;
50820 Roo.log('GridView.ensureVisible:' +
50822 ' c.clientHeight:' + c.clientHeight +
50823 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
50831 c.scrollTop = ctop;
50832 //Roo.log("set scrolltop to ctop DISABLE?");
50833 }else if(cbot > sbot){
50834 //Roo.log("set scrolltop to cbot-ch");
50835 c.scrollTop = cbot-ch;
50838 if(hscroll !== false){
50840 c.scrollLeft = cleft;
50841 }else if(cright > sright){
50842 c.scrollLeft = cright-c.clientWidth;
50849 updateColumns : function(){
50850 this.grid.stopEditing();
50851 var cm = this.grid.colModel, colIds = this.getColumnIds();
50852 //var totalWidth = cm.getTotalWidth();
50854 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50855 //if(cm.isHidden(i)) continue;
50856 var w = cm.getColumnWidth(i);
50857 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50858 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
50860 this.updateSplitters();
50863 generateRules : function(cm){
50864 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
50865 Roo.util.CSS.removeStyleSheet(rulesId);
50866 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50867 var cid = cm.getColumnId(i);
50869 if(cm.config[i].align){
50870 align = 'text-align:'+cm.config[i].align+';';
50873 if(cm.isHidden(i)){
50874 hidden = 'display:none;';
50876 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
50878 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
50879 this.hdSelector, cid, " {\n", align, width, "}\n",
50880 this.tdSelector, cid, " {\n",hidden,"\n}\n",
50881 this.splitSelector, cid, " {\n", hidden , "\n}\n");
50883 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
50886 updateSplitters : function(){
50887 var cm = this.cm, s = this.getSplitters();
50888 if(s){ // splitters not created yet
50889 var pos = 0, locked = true;
50890 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50891 if(cm.isHidden(i)) continue;
50892 var w = cm.getColumnWidth(i); // make sure it's a number
50893 if(!cm.isLocked(i) && locked){
50898 s[i].style.left = (pos-this.splitOffset) + "px";
50903 handleHiddenChange : function(colModel, colIndex, hidden){
50905 this.hideColumn(colIndex);
50907 this.unhideColumn(colIndex);
50911 hideColumn : function(colIndex){
50912 var cid = this.getColumnId(colIndex);
50913 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
50914 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
50916 this.updateHeaders();
50918 this.updateSplitters();
50922 unhideColumn : function(colIndex){
50923 var cid = this.getColumnId(colIndex);
50924 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
50925 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
50928 this.updateHeaders();
50930 this.updateSplitters();
50934 insertRows : function(dm, firstRow, lastRow, isUpdate){
50935 if(firstRow == 0 && lastRow == dm.getCount()-1){
50939 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
50941 var s = this.getScrollState();
50942 var markup = this.renderRows(firstRow, lastRow);
50943 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
50944 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
50945 this.restoreScroll(s);
50947 this.fireEvent("rowsinserted", this, firstRow, lastRow);
50948 this.syncRowHeights(firstRow, lastRow);
50949 this.stripeRows(firstRow);
50955 bufferRows : function(markup, target, index){
50956 var before = null, trows = target.rows, tbody = target.tBodies[0];
50957 if(index < trows.length){
50958 before = trows[index];
50960 var b = document.createElement("div");
50961 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
50962 var rows = b.firstChild.rows;
50963 for(var i = 0, len = rows.length; i < len; i++){
50965 tbody.insertBefore(rows[0], before);
50967 tbody.appendChild(rows[0]);
50974 deleteRows : function(dm, firstRow, lastRow){
50975 if(dm.getRowCount()<1){
50976 this.fireEvent("beforerefresh", this);
50977 this.mainBody.update("");
50978 this.lockedBody.update("");
50979 this.fireEvent("refresh", this);
50981 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
50982 var bt = this.getBodyTable();
50983 var tbody = bt.firstChild;
50984 var rows = bt.rows;
50985 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
50986 tbody.removeChild(rows[firstRow]);
50988 this.stripeRows(firstRow);
50989 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
50993 updateRows : function(dataSource, firstRow, lastRow){
50994 var s = this.getScrollState();
50996 this.restoreScroll(s);
50999 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
51003 this.updateHeaderSortState();
51006 getScrollState : function(){
51008 var sb = this.scroller.dom;
51009 return {left: sb.scrollLeft, top: sb.scrollTop};
51012 stripeRows : function(startRow){
51013 if(!this.grid.stripeRows || this.ds.getCount() < 1){
51016 startRow = startRow || 0;
51017 var rows = this.getBodyTable().rows;
51018 var lrows = this.getLockedTable().rows;
51019 var cls = ' x-grid-row-alt ';
51020 for(var i = startRow, len = rows.length; i < len; i++){
51021 var row = rows[i], lrow = lrows[i];
51022 var isAlt = ((i+1) % 2 == 0);
51023 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
51024 if(isAlt == hasAlt){
51028 row.className += " x-grid-row-alt";
51030 row.className = row.className.replace("x-grid-row-alt", "");
51033 lrow.className = row.className;
51038 restoreScroll : function(state){
51039 //Roo.log('GridView.restoreScroll');
51040 var sb = this.scroller.dom;
51041 sb.scrollLeft = state.left;
51042 sb.scrollTop = state.top;
51046 syncScroll : function(){
51047 //Roo.log('GridView.syncScroll');
51048 var sb = this.scroller.dom;
51049 var sh = this.mainHd.dom;
51050 var bs = this.mainBody.dom;
51051 var lv = this.lockedBody.dom;
51052 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
51053 lv.scrollTop = bs.scrollTop = sb.scrollTop;
51056 handleScroll : function(e){
51058 var sb = this.scroller.dom;
51059 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
51063 handleWheel : function(e){
51064 var d = e.getWheelDelta();
51065 this.scroller.dom.scrollTop -= d*22;
51066 // set this here to prevent jumpy scrolling on large tables
51067 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
51071 renderRows : function(startRow, endRow){
51072 // pull in all the crap needed to render rows
51073 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
51074 var colCount = cm.getColumnCount();
51076 if(ds.getCount() < 1){
51080 // build a map for all the columns
51082 for(var i = 0; i < colCount; i++){
51083 var name = cm.getDataIndex(i);
51085 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
51086 renderer : cm.getRenderer(i),
51087 id : cm.getColumnId(i),
51088 locked : cm.isLocked(i)
51092 startRow = startRow || 0;
51093 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
51095 // records to render
51096 var rs = ds.getRange(startRow, endRow);
51098 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
51101 // As much as I hate to duplicate code, this was branched because FireFox really hates
51102 // [].join("") on strings. The performance difference was substantial enough to
51103 // branch this function
51104 doRender : Roo.isGecko ?
51105 function(cs, rs, ds, startRow, colCount, stripe){
51106 var ts = this.templates, ct = ts.cell, rt = ts.row;
51108 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
51110 var hasListener = this.grid.hasListener('rowclass');
51112 for(var j = 0, len = rs.length; j < len; j++){
51113 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
51114 for(var i = 0; i < colCount; i++){
51116 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
51118 p.css = p.attr = "";
51119 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
51120 if(p.value == undefined || p.value === "") p.value = " ";
51121 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
51122 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
51124 var markup = ct.apply(p);
51132 if(stripe && ((rowIndex+1) % 2 == 0)){
51133 alt.push("x-grid-row-alt")
51136 alt.push( " x-grid-dirty-row");
51139 if(this.getRowClass){
51140 alt.push(this.getRowClass(r, rowIndex));
51146 rowIndex : rowIndex,
51149 this.grid.fireEvent('rowclass', this, rowcfg);
51150 alt.push(rowcfg.rowClass);
51152 rp.alt = alt.join(" ");
51153 lbuf+= rt.apply(rp);
51155 buf+= rt.apply(rp);
51157 return [lbuf, buf];
51159 function(cs, rs, ds, startRow, colCount, stripe){
51160 var ts = this.templates, ct = ts.cell, rt = ts.row;
51162 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
51163 var hasListener = this.grid.hasListener('rowclass');
51166 for(var j = 0, len = rs.length; j < len; j++){
51167 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
51168 for(var i = 0; i < colCount; i++){
51170 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
51172 p.css = p.attr = "";
51173 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
51174 if(p.value == undefined || p.value === "") p.value = " ";
51175 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
51176 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
51179 var markup = ct.apply(p);
51181 cb[cb.length] = markup;
51183 lcb[lcb.length] = markup;
51187 if(stripe && ((rowIndex+1) % 2 == 0)){
51188 alt.push( "x-grid-row-alt");
51191 alt.push(" x-grid-dirty-row");
51194 if(this.getRowClass){
51195 alt.push( this.getRowClass(r, rowIndex));
51201 rowIndex : rowIndex,
51204 this.grid.fireEvent('rowclass', this, rowcfg);
51205 alt.push(rowcfg.rowClass);
51207 rp.alt = alt.join(" ");
51208 rp.cells = lcb.join("");
51209 lbuf[lbuf.length] = rt.apply(rp);
51210 rp.cells = cb.join("");
51211 buf[buf.length] = rt.apply(rp);
51213 return [lbuf.join(""), buf.join("")];
51216 renderBody : function(){
51217 var markup = this.renderRows();
51218 var bt = this.templates.body;
51219 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
51223 * Refreshes the grid
51224 * @param {Boolean} headersToo
51226 refresh : function(headersToo){
51227 this.fireEvent("beforerefresh", this);
51228 this.grid.stopEditing();
51229 var result = this.renderBody();
51230 this.lockedBody.update(result[0]);
51231 this.mainBody.update(result[1]);
51232 if(headersToo === true){
51233 this.updateHeaders();
51234 this.updateColumns();
51235 this.updateSplitters();
51236 this.updateHeaderSortState();
51238 this.syncRowHeights();
51240 this.fireEvent("refresh", this);
51243 handleColumnMove : function(cm, oldIndex, newIndex){
51244 this.indexMap = null;
51245 var s = this.getScrollState();
51246 this.refresh(true);
51247 this.restoreScroll(s);
51248 this.afterMove(newIndex);
51251 afterMove : function(colIndex){
51252 if(this.enableMoveAnim && Roo.enableFx){
51253 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
51255 // if multisort - fix sortOrder, and reload..
51256 if (this.grid.dataSource.multiSort) {
51257 // the we can call sort again..
51258 var dm = this.grid.dataSource;
51259 var cm = this.grid.colModel;
51261 for(var i = 0; i < cm.config.length; i++ ) {
51263 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
51264 continue; // dont' bother, it's not in sort list or being set.
51267 so.push(cm.config[i].dataIndex);
51270 dm.load(dm.lastOptions);
51277 updateCell : function(dm, rowIndex, dataIndex){
51278 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
51279 if(typeof colIndex == "undefined"){ // not present in grid
51282 var cm = this.grid.colModel;
51283 var cell = this.getCell(rowIndex, colIndex);
51284 var cellText = this.getCellText(rowIndex, colIndex);
51287 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
51288 id : cm.getColumnId(colIndex),
51289 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
51291 var renderer = cm.getRenderer(colIndex);
51292 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
51293 if(typeof val == "undefined" || val === "") val = " ";
51294 cellText.innerHTML = val;
51295 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
51296 this.syncRowHeights(rowIndex, rowIndex);
51299 calcColumnWidth : function(colIndex, maxRowsToMeasure){
51301 if(this.grid.autoSizeHeaders){
51302 var h = this.getHeaderCellMeasure(colIndex);
51303 maxWidth = Math.max(maxWidth, h.scrollWidth);
51306 if(this.cm.isLocked(colIndex)){
51307 tb = this.getLockedTable();
51310 tb = this.getBodyTable();
51311 index = colIndex - this.cm.getLockedCount();
51314 var rows = tb.rows;
51315 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
51316 for(var i = 0; i < stopIndex; i++){
51317 var cell = rows[i].childNodes[index].firstChild;
51318 maxWidth = Math.max(maxWidth, cell.scrollWidth);
51321 return maxWidth + /*margin for error in IE*/ 5;
51324 * Autofit a column to its content.
51325 * @param {Number} colIndex
51326 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
51328 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
51329 if(this.cm.isHidden(colIndex)){
51330 return; // can't calc a hidden column
51333 var cid = this.cm.getColumnId(colIndex);
51334 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
51335 if(this.grid.autoSizeHeaders){
51336 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
51339 var newWidth = this.calcColumnWidth(colIndex);
51340 this.cm.setColumnWidth(colIndex,
51341 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
51342 if(!suppressEvent){
51343 this.grid.fireEvent("columnresize", colIndex, newWidth);
51348 * Autofits all columns to their content and then expands to fit any extra space in the grid
51350 autoSizeColumns : function(){
51351 var cm = this.grid.colModel;
51352 var colCount = cm.getColumnCount();
51353 for(var i = 0; i < colCount; i++){
51354 this.autoSizeColumn(i, true, true);
51356 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
51359 this.updateColumns();
51365 * Autofits all columns to the grid's width proportionate with their current size
51366 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
51368 fitColumns : function(reserveScrollSpace){
51369 var cm = this.grid.colModel;
51370 var colCount = cm.getColumnCount();
51374 for (i = 0; i < colCount; i++){
51375 if(!cm.isHidden(i) && !cm.isFixed(i)){
51376 w = cm.getColumnWidth(i);
51382 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
51383 if(reserveScrollSpace){
51386 var frac = (avail - cm.getTotalWidth())/width;
51387 while (cols.length){
51390 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
51392 this.updateColumns();
51396 onRowSelect : function(rowIndex){
51397 var row = this.getRowComposite(rowIndex);
51398 row.addClass("x-grid-row-selected");
51401 onRowDeselect : function(rowIndex){
51402 var row = this.getRowComposite(rowIndex);
51403 row.removeClass("x-grid-row-selected");
51406 onCellSelect : function(row, col){
51407 var cell = this.getCell(row, col);
51409 Roo.fly(cell).addClass("x-grid-cell-selected");
51413 onCellDeselect : function(row, col){
51414 var cell = this.getCell(row, col);
51416 Roo.fly(cell).removeClass("x-grid-cell-selected");
51420 updateHeaderSortState : function(){
51422 // sort state can be single { field: xxx, direction : yyy}
51423 // or { xxx=>ASC , yyy : DESC ..... }
51426 if (!this.ds.multiSort) {
51427 var state = this.ds.getSortState();
51431 mstate[state.field] = state.direction;
51432 // FIXME... - this is not used here.. but might be elsewhere..
51433 this.sortState = state;
51436 mstate = this.ds.sortToggle;
51438 //remove existing sort classes..
51440 var sc = this.sortClasses;
51441 var hds = this.el.select(this.headerSelector).removeClass(sc);
51443 for(var f in mstate) {
51445 var sortColumn = this.cm.findColumnIndex(f);
51447 if(sortColumn != -1){
51448 var sortDir = mstate[f];
51449 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
51458 handleHeaderClick : function(g, index){
51459 if(this.headersDisabled){
51462 var dm = g.dataSource, cm = g.colModel;
51463 if(!cm.isSortable(index)){
51468 if (dm.multiSort) {
51469 // update the sortOrder
51471 for(var i = 0; i < cm.config.length; i++ ) {
51473 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
51474 continue; // dont' bother, it's not in sort list or being set.
51477 so.push(cm.config[i].dataIndex);
51483 dm.sort(cm.getDataIndex(index));
51487 destroy : function(){
51489 this.colMenu.removeAll();
51490 Roo.menu.MenuMgr.unregister(this.colMenu);
51491 this.colMenu.getEl().remove();
51492 delete this.colMenu;
51495 this.hmenu.removeAll();
51496 Roo.menu.MenuMgr.unregister(this.hmenu);
51497 this.hmenu.getEl().remove();
51500 if(this.grid.enableColumnMove){
51501 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51503 for(var dd in dds){
51504 if(!dds[dd].config.isTarget && dds[dd].dragElId){
51505 var elid = dds[dd].dragElId;
51507 Roo.get(elid).remove();
51508 } else if(dds[dd].config.isTarget){
51509 dds[dd].proxyTop.remove();
51510 dds[dd].proxyBottom.remove();
51513 if(Roo.dd.DDM.locationCache[dd]){
51514 delete Roo.dd.DDM.locationCache[dd];
51517 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
51520 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
51521 this.bind(null, null);
51522 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
51525 handleLockChange : function(){
51526 this.refresh(true);
51529 onDenyColumnLock : function(){
51533 onDenyColumnHide : function(){
51537 handleHdMenuClick : function(item){
51538 var index = this.hdCtxIndex;
51539 var cm = this.cm, ds = this.ds;
51542 ds.sort(cm.getDataIndex(index), "ASC");
51545 ds.sort(cm.getDataIndex(index), "DESC");
51548 var lc = cm.getLockedCount();
51549 if(cm.getColumnCount(true) <= lc+1){
51550 this.onDenyColumnLock();
51554 cm.setLocked(index, true, true);
51555 cm.moveColumn(index, lc);
51556 this.grid.fireEvent("columnmove", index, lc);
51558 cm.setLocked(index, true);
51562 var lc = cm.getLockedCount();
51563 if((lc-1) != index){
51564 cm.setLocked(index, false, true);
51565 cm.moveColumn(index, lc-1);
51566 this.grid.fireEvent("columnmove", index, lc-1);
51568 cm.setLocked(index, false);
51572 index = cm.getIndexById(item.id.substr(4));
51574 if(item.checked && cm.getColumnCount(true) <= 1){
51575 this.onDenyColumnHide();
51578 cm.setHidden(index, item.checked);
51584 beforeColMenuShow : function(){
51585 var cm = this.cm, colCount = cm.getColumnCount();
51586 this.colMenu.removeAll();
51587 for(var i = 0; i < colCount; i++){
51588 this.colMenu.add(new Roo.menu.CheckItem({
51589 id: "col-"+cm.getColumnId(i),
51590 text: cm.getColumnHeader(i),
51591 checked: !cm.isHidden(i),
51597 handleHdCtx : function(g, index, e){
51599 var hd = this.getHeaderCell(index);
51600 this.hdCtxIndex = index;
51601 var ms = this.hmenu.items, cm = this.cm;
51602 ms.get("asc").setDisabled(!cm.isSortable(index));
51603 ms.get("desc").setDisabled(!cm.isSortable(index));
51604 if(this.grid.enableColLock !== false){
51605 ms.get("lock").setDisabled(cm.isLocked(index));
51606 ms.get("unlock").setDisabled(!cm.isLocked(index));
51608 this.hmenu.show(hd, "tl-bl");
51611 handleHdOver : function(e){
51612 var hd = this.findHeaderCell(e.getTarget());
51613 if(hd && !this.headersDisabled){
51614 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
51615 this.fly(hd).addClass("x-grid-hd-over");
51620 handleHdOut : function(e){
51621 var hd = this.findHeaderCell(e.getTarget());
51623 this.fly(hd).removeClass("x-grid-hd-over");
51627 handleSplitDblClick : function(e, t){
51628 var i = this.getCellIndex(t);
51629 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
51630 this.autoSizeColumn(i, true);
51635 render : function(){
51638 var colCount = cm.getColumnCount();
51640 if(this.grid.monitorWindowResize === true){
51641 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51643 var header = this.renderHeaders();
51644 var body = this.templates.body.apply({rows:""});
51645 var html = this.templates.master.apply({
51648 lockedHeader: header[0],
51652 //this.updateColumns();
51654 this.grid.getGridEl().dom.innerHTML = html;
51656 this.initElements();
51658 // a kludge to fix the random scolling effect in webkit
51659 this.el.on("scroll", function() {
51660 this.el.dom.scrollTop=0; // hopefully not recursive..
51663 this.scroller.on("scroll", this.handleScroll, this);
51664 this.lockedBody.on("mousewheel", this.handleWheel, this);
51665 this.mainBody.on("mousewheel", this.handleWheel, this);
51667 this.mainHd.on("mouseover", this.handleHdOver, this);
51668 this.mainHd.on("mouseout", this.handleHdOut, this);
51669 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
51670 {delegate: "."+this.splitClass});
51672 this.lockedHd.on("mouseover", this.handleHdOver, this);
51673 this.lockedHd.on("mouseout", this.handleHdOut, this);
51674 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
51675 {delegate: "."+this.splitClass});
51677 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
51678 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51681 this.updateSplitters();
51683 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
51684 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51685 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
51688 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
51689 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
51691 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
51692 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
51694 if(this.grid.enableColLock !== false){
51695 this.hmenu.add('-',
51696 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
51697 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
51700 if(this.grid.enableColumnHide !== false){
51702 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
51703 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
51704 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
51706 this.hmenu.add('-',
51707 {id:"columns", text: this.columnsText, menu: this.colMenu}
51710 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
51712 this.grid.on("headercontextmenu", this.handleHdCtx, this);
51715 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
51716 this.dd = new Roo.grid.GridDragZone(this.grid, {
51717 ddGroup : this.grid.ddGroup || 'GridDD'
51723 for(var i = 0; i < colCount; i++){
51724 if(cm.isHidden(i)){
51725 this.hideColumn(i);
51727 if(cm.config[i].align){
51728 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
51729 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
51733 this.updateHeaderSortState();
51735 this.beforeInitialResize();
51738 // two part rendering gives faster view to the user
51739 this.renderPhase2.defer(1, this);
51742 renderPhase2 : function(){
51743 // render the rows now
51745 if(this.grid.autoSizeColumns){
51746 this.autoSizeColumns();
51750 beforeInitialResize : function(){
51754 onColumnSplitterMoved : function(i, w){
51755 this.userResized = true;
51756 var cm = this.grid.colModel;
51757 cm.setColumnWidth(i, w, true);
51758 var cid = cm.getColumnId(i);
51759 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51760 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
51761 this.updateSplitters();
51763 this.grid.fireEvent("columnresize", i, w);
51766 syncRowHeights : function(startIndex, endIndex){
51767 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
51768 startIndex = startIndex || 0;
51769 var mrows = this.getBodyTable().rows;
51770 var lrows = this.getLockedTable().rows;
51771 var len = mrows.length-1;
51772 endIndex = Math.min(endIndex || len, len);
51773 for(var i = startIndex; i <= endIndex; i++){
51774 var m = mrows[i], l = lrows[i];
51775 var h = Math.max(m.offsetHeight, l.offsetHeight);
51776 m.style.height = l.style.height = h + "px";
51781 layout : function(initialRender, is2ndPass){
51783 var auto = g.autoHeight;
51784 var scrollOffset = 16;
51785 var c = g.getGridEl(), cm = this.cm,
51786 expandCol = g.autoExpandColumn,
51788 //c.beginMeasure();
51790 if(!c.dom.offsetWidth){ // display:none?
51792 this.lockedWrap.show();
51793 this.mainWrap.show();
51798 var hasLock = this.cm.isLocked(0);
51800 var tbh = this.headerPanel.getHeight();
51801 var bbh = this.footerPanel.getHeight();
51804 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
51805 var newHeight = ch + c.getBorderWidth("tb");
51807 newHeight = Math.min(g.maxHeight, newHeight);
51809 c.setHeight(newHeight);
51813 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
51816 var s = this.scroller;
51818 var csize = c.getSize(true);
51820 this.el.setSize(csize.width, csize.height);
51822 this.headerPanel.setWidth(csize.width);
51823 this.footerPanel.setWidth(csize.width);
51825 var hdHeight = this.mainHd.getHeight();
51826 var vw = csize.width;
51827 var vh = csize.height - (tbh + bbh);
51831 var bt = this.getBodyTable();
51832 var ltWidth = hasLock ?
51833 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
51835 var scrollHeight = bt.offsetHeight;
51836 var scrollWidth = ltWidth + bt.offsetWidth;
51837 var vscroll = false, hscroll = false;
51839 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
51841 var lw = this.lockedWrap, mw = this.mainWrap;
51842 var lb = this.lockedBody, mb = this.mainBody;
51844 setTimeout(function(){
51845 var t = s.dom.offsetTop;
51846 var w = s.dom.clientWidth,
51847 h = s.dom.clientHeight;
51850 lw.setSize(ltWidth, h);
51852 mw.setLeftTop(ltWidth, t);
51853 mw.setSize(w-ltWidth, h);
51855 lb.setHeight(h-hdHeight);
51856 mb.setHeight(h-hdHeight);
51858 if(is2ndPass !== true && !gv.userResized && expandCol){
51859 // high speed resize without full column calculation
51861 var ci = cm.getIndexById(expandCol);
51863 ci = cm.findColumnIndex(expandCol);
51865 ci = Math.max(0, ci); // make sure it's got at least the first col.
51866 var expandId = cm.getColumnId(ci);
51867 var tw = cm.getTotalWidth(false);
51868 var currentWidth = cm.getColumnWidth(ci);
51869 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
51870 if(currentWidth != cw){
51871 cm.setColumnWidth(ci, cw, true);
51872 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51873 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
51874 gv.updateSplitters();
51875 gv.layout(false, true);
51887 onWindowResize : function(){
51888 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
51894 appendFooter : function(parentEl){
51898 sortAscText : "Sort Ascending",
51899 sortDescText : "Sort Descending",
51900 lockText : "Lock Column",
51901 unlockText : "Unlock Column",
51902 columnsText : "Columns"
51906 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
51907 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
51908 this.proxy.el.addClass('x-grid3-col-dd');
51911 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
51912 handleMouseDown : function(e){
51916 callHandleMouseDown : function(e){
51917 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
51922 * Ext JS Library 1.1.1
51923 * Copyright(c) 2006-2007, Ext JS, LLC.
51925 * Originally Released Under LGPL - original licence link has changed is not relivant.
51928 * <script type="text/javascript">
51932 // This is a support class used internally by the Grid components
51933 Roo.grid.SplitDragZone = function(grid, hd, hd2){
51935 this.view = grid.getView();
51936 this.proxy = this.view.resizeProxy;
51937 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
51938 "gridSplitters" + this.grid.getGridEl().id, {
51939 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
51941 this.setHandleElId(Roo.id(hd));
51942 this.setOuterHandleElId(Roo.id(hd2));
51943 this.scroll = false;
51945 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
51946 fly: Roo.Element.fly,
51948 b4StartDrag : function(x, y){
51949 this.view.headersDisabled = true;
51950 this.proxy.setHeight(this.view.mainWrap.getHeight());
51951 var w = this.cm.getColumnWidth(this.cellIndex);
51952 var minw = Math.max(w-this.grid.minColumnWidth, 0);
51953 this.resetConstraints();
51954 this.setXConstraint(minw, 1000);
51955 this.setYConstraint(0, 0);
51956 this.minX = x - minw;
51957 this.maxX = x + 1000;
51959 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
51963 handleMouseDown : function(e){
51964 ev = Roo.EventObject.setEvent(e);
51965 var t = this.fly(ev.getTarget());
51966 if(t.hasClass("x-grid-split")){
51967 this.cellIndex = this.view.getCellIndex(t.dom);
51968 this.split = t.dom;
51969 this.cm = this.grid.colModel;
51970 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
51971 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
51976 endDrag : function(e){
51977 this.view.headersDisabled = false;
51978 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
51979 var diff = endX - this.startPos;
51980 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
51983 autoOffset : function(){
51984 this.setDelta(0,0);
51988 * Ext JS Library 1.1.1
51989 * Copyright(c) 2006-2007, Ext JS, LLC.
51991 * Originally Released Under LGPL - original licence link has changed is not relivant.
51994 * <script type="text/javascript">
51998 // This is a support class used internally by the Grid components
51999 Roo.grid.GridDragZone = function(grid, config){
52000 this.view = grid.getView();
52001 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
52002 if(this.view.lockedBody){
52003 this.setHandleElId(Roo.id(this.view.mainBody.dom));
52004 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
52006 this.scroll = false;
52008 this.ddel = document.createElement('div');
52009 this.ddel.className = 'x-grid-dd-wrap';
52012 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
52013 ddGroup : "GridDD",
52015 getDragData : function(e){
52016 var t = Roo.lib.Event.getTarget(e);
52017 var rowIndex = this.view.findRowIndex(t);
52018 var sm = this.grid.selModel;
52020 //Roo.log(rowIndex);
52022 if (sm.getSelectedCell) {
52023 // cell selection..
52024 if (!sm.getSelectedCell()) {
52027 if (rowIndex != sm.getSelectedCell()[0]) {
52033 if(rowIndex !== false){
52038 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
52040 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
52043 if (e.hasModifier()){
52044 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
52047 Roo.log("getDragData");
52052 rowIndex: rowIndex,
52053 selections:sm.getSelections ? sm.getSelections() : (
52054 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
52061 onInitDrag : function(e){
52062 var data = this.dragData;
52063 this.ddel.innerHTML = this.grid.getDragDropText();
52064 this.proxy.update(this.ddel);
52065 // fire start drag?
52068 afterRepair : function(){
52069 this.dragging = false;
52072 getRepairXY : function(e, data){
52076 onEndDrag : function(data, e){
52080 onValidDrop : function(dd, e, id){
52085 beforeInvalidDrop : function(e, id){
52090 * Ext JS Library 1.1.1
52091 * Copyright(c) 2006-2007, Ext JS, LLC.
52093 * Originally Released Under LGPL - original licence link has changed is not relivant.
52096 * <script type="text/javascript">
52101 * @class Roo.grid.ColumnModel
52102 * @extends Roo.util.Observable
52103 * This is the default implementation of a ColumnModel used by the Grid. It defines
52104 * the columns in the grid.
52107 var colModel = new Roo.grid.ColumnModel([
52108 {header: "Ticker", width: 60, sortable: true, locked: true},
52109 {header: "Company Name", width: 150, sortable: true},
52110 {header: "Market Cap.", width: 100, sortable: true},
52111 {header: "$ Sales", width: 100, sortable: true, renderer: money},
52112 {header: "Employees", width: 100, sortable: true, resizable: false}
52117 * The config options listed for this class are options which may appear in each
52118 * individual column definition.
52119 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
52121 * @param {Object} config An Array of column config objects. See this class's
52122 * config objects for details.
52124 Roo.grid.ColumnModel = function(config){
52126 * The config passed into the constructor
52128 this.config = config;
52131 // if no id, create one
52132 // if the column does not have a dataIndex mapping,
52133 // map it to the order it is in the config
52134 for(var i = 0, len = config.length; i < len; i++){
52136 if(typeof c.dataIndex == "undefined"){
52139 if(typeof c.renderer == "string"){
52140 c.renderer = Roo.util.Format[c.renderer];
52142 if(typeof c.id == "undefined"){
52145 if(c.editor && c.editor.xtype){
52146 c.editor = Roo.factory(c.editor, Roo.grid);
52148 if(c.editor && c.editor.isFormField){
52149 c.editor = new Roo.grid.GridEditor(c.editor);
52151 this.lookup[c.id] = c;
52155 * The width of columns which have no width specified (defaults to 100)
52158 this.defaultWidth = 100;
52161 * Default sortable of columns which have no sortable specified (defaults to false)
52164 this.defaultSortable = false;
52168 * @event widthchange
52169 * Fires when the width of a column changes.
52170 * @param {ColumnModel} this
52171 * @param {Number} columnIndex The column index
52172 * @param {Number} newWidth The new width
52174 "widthchange": true,
52176 * @event headerchange
52177 * Fires when the text of a header changes.
52178 * @param {ColumnModel} this
52179 * @param {Number} columnIndex The column index
52180 * @param {Number} newText The new header text
52182 "headerchange": true,
52184 * @event hiddenchange
52185 * Fires when a column is hidden or "unhidden".
52186 * @param {ColumnModel} this
52187 * @param {Number} columnIndex The column index
52188 * @param {Boolean} hidden true if hidden, false otherwise
52190 "hiddenchange": true,
52192 * @event columnmoved
52193 * Fires when a column is moved.
52194 * @param {ColumnModel} this
52195 * @param {Number} oldIndex
52196 * @param {Number} newIndex
52198 "columnmoved" : true,
52200 * @event columlockchange
52201 * Fires when a column's locked state is changed
52202 * @param {ColumnModel} this
52203 * @param {Number} colIndex
52204 * @param {Boolean} locked true if locked
52206 "columnlockchange" : true
52208 Roo.grid.ColumnModel.superclass.constructor.call(this);
52210 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
52212 * @cfg {String} header The header text to display in the Grid view.
52215 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
52216 * {@link Roo.data.Record} definition from which to draw the column's value. If not
52217 * specified, the column's index is used as an index into the Record's data Array.
52220 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
52221 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
52224 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
52225 * Defaults to the value of the {@link #defaultSortable} property.
52226 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
52229 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
52232 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
52235 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
52238 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
52241 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
52242 * given the cell's data value. See {@link #setRenderer}. If not specified, the
52243 * default renderer uses the raw data value.
52246 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
52249 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
52253 * Returns the id of the column at the specified index.
52254 * @param {Number} index The column index
52255 * @return {String} the id
52257 getColumnId : function(index){
52258 return this.config[index].id;
52262 * Returns the column for a specified id.
52263 * @param {String} id The column id
52264 * @return {Object} the column
52266 getColumnById : function(id){
52267 return this.lookup[id];
52272 * Returns the column for a specified dataIndex.
52273 * @param {String} dataIndex The column dataIndex
52274 * @return {Object|Boolean} the column or false if not found
52276 getColumnByDataIndex: function(dataIndex){
52277 var index = this.findColumnIndex(dataIndex);
52278 return index > -1 ? this.config[index] : false;
52282 * Returns the index for a specified column id.
52283 * @param {String} id The column id
52284 * @return {Number} the index, or -1 if not found
52286 getIndexById : function(id){
52287 for(var i = 0, len = this.config.length; i < len; i++){
52288 if(this.config[i].id == id){
52296 * Returns the index for a specified column dataIndex.
52297 * @param {String} dataIndex The column dataIndex
52298 * @return {Number} the index, or -1 if not found
52301 findColumnIndex : function(dataIndex){
52302 for(var i = 0, len = this.config.length; i < len; i++){
52303 if(this.config[i].dataIndex == dataIndex){
52311 moveColumn : function(oldIndex, newIndex){
52312 var c = this.config[oldIndex];
52313 this.config.splice(oldIndex, 1);
52314 this.config.splice(newIndex, 0, c);
52315 this.dataMap = null;
52316 this.fireEvent("columnmoved", this, oldIndex, newIndex);
52319 isLocked : function(colIndex){
52320 return this.config[colIndex].locked === true;
52323 setLocked : function(colIndex, value, suppressEvent){
52324 if(this.isLocked(colIndex) == value){
52327 this.config[colIndex].locked = value;
52328 if(!suppressEvent){
52329 this.fireEvent("columnlockchange", this, colIndex, value);
52333 getTotalLockedWidth : function(){
52334 var totalWidth = 0;
52335 for(var i = 0; i < this.config.length; i++){
52336 if(this.isLocked(i) && !this.isHidden(i)){
52337 this.totalWidth += this.getColumnWidth(i);
52343 getLockedCount : function(){
52344 for(var i = 0, len = this.config.length; i < len; i++){
52345 if(!this.isLocked(i)){
52352 * Returns the number of columns.
52355 getColumnCount : function(visibleOnly){
52356 if(visibleOnly === true){
52358 for(var i = 0, len = this.config.length; i < len; i++){
52359 if(!this.isHidden(i)){
52365 return this.config.length;
52369 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
52370 * @param {Function} fn
52371 * @param {Object} scope (optional)
52372 * @return {Array} result
52374 getColumnsBy : function(fn, scope){
52376 for(var i = 0, len = this.config.length; i < len; i++){
52377 var c = this.config[i];
52378 if(fn.call(scope||this, c, i) === true){
52386 * Returns true if the specified column is sortable.
52387 * @param {Number} col The column index
52388 * @return {Boolean}
52390 isSortable : function(col){
52391 if(typeof this.config[col].sortable == "undefined"){
52392 return this.defaultSortable;
52394 return this.config[col].sortable;
52398 * Returns the rendering (formatting) function defined for the column.
52399 * @param {Number} col The column index.
52400 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
52402 getRenderer : function(col){
52403 if(!this.config[col].renderer){
52404 return Roo.grid.ColumnModel.defaultRenderer;
52406 return this.config[col].renderer;
52410 * Sets the rendering (formatting) function for a column.
52411 * @param {Number} col The column index
52412 * @param {Function} fn The function to use to process the cell's raw data
52413 * to return HTML markup for the grid view. The render function is called with
52414 * the following parameters:<ul>
52415 * <li>Data value.</li>
52416 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
52417 * <li>css A CSS style string to apply to the table cell.</li>
52418 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
52419 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
52420 * <li>Row index</li>
52421 * <li>Column index</li>
52422 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
52424 setRenderer : function(col, fn){
52425 this.config[col].renderer = fn;
52429 * Returns the width for the specified column.
52430 * @param {Number} col The column index
52433 getColumnWidth : function(col){
52434 return this.config[col].width * 1 || this.defaultWidth;
52438 * Sets the width for a column.
52439 * @param {Number} col The column index
52440 * @param {Number} width The new width
52442 setColumnWidth : function(col, width, suppressEvent){
52443 this.config[col].width = width;
52444 this.totalWidth = null;
52445 if(!suppressEvent){
52446 this.fireEvent("widthchange", this, col, width);
52451 * Returns the total width of all columns.
52452 * @param {Boolean} includeHidden True to include hidden column widths
52455 getTotalWidth : function(includeHidden){
52456 if(!this.totalWidth){
52457 this.totalWidth = 0;
52458 for(var i = 0, len = this.config.length; i < len; i++){
52459 if(includeHidden || !this.isHidden(i)){
52460 this.totalWidth += this.getColumnWidth(i);
52464 return this.totalWidth;
52468 * Returns the header for the specified column.
52469 * @param {Number} col The column index
52472 getColumnHeader : function(col){
52473 return this.config[col].header;
52477 * Sets the header for a column.
52478 * @param {Number} col The column index
52479 * @param {String} header The new header
52481 setColumnHeader : function(col, header){
52482 this.config[col].header = header;
52483 this.fireEvent("headerchange", this, col, header);
52487 * Returns the tooltip for the specified column.
52488 * @param {Number} col The column index
52491 getColumnTooltip : function(col){
52492 return this.config[col].tooltip;
52495 * Sets the tooltip for a column.
52496 * @param {Number} col The column index
52497 * @param {String} tooltip The new tooltip
52499 setColumnTooltip : function(col, tooltip){
52500 this.config[col].tooltip = tooltip;
52504 * Returns the dataIndex for the specified column.
52505 * @param {Number} col The column index
52508 getDataIndex : function(col){
52509 return this.config[col].dataIndex;
52513 * Sets the dataIndex for a column.
52514 * @param {Number} col The column index
52515 * @param {Number} dataIndex The new dataIndex
52517 setDataIndex : function(col, dataIndex){
52518 this.config[col].dataIndex = dataIndex;
52524 * Returns true if the cell is editable.
52525 * @param {Number} colIndex The column index
52526 * @param {Number} rowIndex The row index
52527 * @return {Boolean}
52529 isCellEditable : function(colIndex, rowIndex){
52530 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
52534 * Returns the editor defined for the cell/column.
52535 * return false or null to disable editing.
52536 * @param {Number} colIndex The column index
52537 * @param {Number} rowIndex The row index
52540 getCellEditor : function(colIndex, rowIndex){
52541 return this.config[colIndex].editor;
52545 * Sets if a column is editable.
52546 * @param {Number} col The column index
52547 * @param {Boolean} editable True if the column is editable
52549 setEditable : function(col, editable){
52550 this.config[col].editable = editable;
52555 * Returns true if the column is hidden.
52556 * @param {Number} colIndex The column index
52557 * @return {Boolean}
52559 isHidden : function(colIndex){
52560 return this.config[colIndex].hidden;
52565 * Returns true if the column width cannot be changed
52567 isFixed : function(colIndex){
52568 return this.config[colIndex].fixed;
52572 * Returns true if the column can be resized
52573 * @return {Boolean}
52575 isResizable : function(colIndex){
52576 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
52579 * Sets if a column is hidden.
52580 * @param {Number} colIndex The column index
52581 * @param {Boolean} hidden True if the column is hidden
52583 setHidden : function(colIndex, hidden){
52584 this.config[colIndex].hidden = hidden;
52585 this.totalWidth = null;
52586 this.fireEvent("hiddenchange", this, colIndex, hidden);
52590 * Sets the editor for a column.
52591 * @param {Number} col The column index
52592 * @param {Object} editor The editor object
52594 setEditor : function(col, editor){
52595 this.config[col].editor = editor;
52599 Roo.grid.ColumnModel.defaultRenderer = function(value){
52600 if(typeof value == "string" && value.length < 1){
52606 // Alias for backwards compatibility
52607 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
52610 * Ext JS Library 1.1.1
52611 * Copyright(c) 2006-2007, Ext JS, LLC.
52613 * Originally Released Under LGPL - original licence link has changed is not relivant.
52616 * <script type="text/javascript">
52620 * @class Roo.grid.AbstractSelectionModel
52621 * @extends Roo.util.Observable
52622 * Abstract base class for grid SelectionModels. It provides the interface that should be
52623 * implemented by descendant classes. This class should not be directly instantiated.
52626 Roo.grid.AbstractSelectionModel = function(){
52627 this.locked = false;
52628 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
52631 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
52632 /** @ignore Called by the grid automatically. Do not call directly. */
52633 init : function(grid){
52639 * Locks the selections.
52642 this.locked = true;
52646 * Unlocks the selections.
52648 unlock : function(){
52649 this.locked = false;
52653 * Returns true if the selections are locked.
52654 * @return {Boolean}
52656 isLocked : function(){
52657 return this.locked;
52661 * Ext JS Library 1.1.1
52662 * Copyright(c) 2006-2007, Ext JS, LLC.
52664 * Originally Released Under LGPL - original licence link has changed is not relivant.
52667 * <script type="text/javascript">
52670 * @extends Roo.grid.AbstractSelectionModel
52671 * @class Roo.grid.RowSelectionModel
52672 * The default SelectionModel used by {@link Roo.grid.Grid}.
52673 * It supports multiple selections and keyboard selection/navigation.
52675 * @param {Object} config
52677 Roo.grid.RowSelectionModel = function(config){
52678 Roo.apply(this, config);
52679 this.selections = new Roo.util.MixedCollection(false, function(o){
52684 this.lastActive = false;
52688 * @event selectionchange
52689 * Fires when the selection changes
52690 * @param {SelectionModel} this
52692 "selectionchange" : true,
52694 * @event afterselectionchange
52695 * Fires after the selection changes (eg. by key press or clicking)
52696 * @param {SelectionModel} this
52698 "afterselectionchange" : true,
52700 * @event beforerowselect
52701 * Fires when a row is selected being selected, return false to cancel.
52702 * @param {SelectionModel} this
52703 * @param {Number} rowIndex The selected index
52704 * @param {Boolean} keepExisting False if other selections will be cleared
52706 "beforerowselect" : true,
52709 * Fires when a row is selected.
52710 * @param {SelectionModel} this
52711 * @param {Number} rowIndex The selected index
52712 * @param {Roo.data.Record} r The record
52714 "rowselect" : true,
52716 * @event rowdeselect
52717 * Fires when a row is deselected.
52718 * @param {SelectionModel} this
52719 * @param {Number} rowIndex The selected index
52721 "rowdeselect" : true
52723 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
52724 this.locked = false;
52727 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
52729 * @cfg {Boolean} singleSelect
52730 * True to allow selection of only one row at a time (defaults to false)
52732 singleSelect : false,
52735 initEvents : function(){
52737 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
52738 this.grid.on("mousedown", this.handleMouseDown, this);
52739 }else{ // allow click to work like normal
52740 this.grid.on("rowclick", this.handleDragableRowClick, this);
52743 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
52744 "up" : function(e){
52746 this.selectPrevious(e.shiftKey);
52747 }else if(this.last !== false && this.lastActive !== false){
52748 var last = this.last;
52749 this.selectRange(this.last, this.lastActive-1);
52750 this.grid.getView().focusRow(this.lastActive);
52751 if(last !== false){
52755 this.selectFirstRow();
52757 this.fireEvent("afterselectionchange", this);
52759 "down" : function(e){
52761 this.selectNext(e.shiftKey);
52762 }else if(this.last !== false && this.lastActive !== false){
52763 var last = this.last;
52764 this.selectRange(this.last, this.lastActive+1);
52765 this.grid.getView().focusRow(this.lastActive);
52766 if(last !== false){
52770 this.selectFirstRow();
52772 this.fireEvent("afterselectionchange", this);
52777 var view = this.grid.view;
52778 view.on("refresh", this.onRefresh, this);
52779 view.on("rowupdated", this.onRowUpdated, this);
52780 view.on("rowremoved", this.onRemove, this);
52784 onRefresh : function(){
52785 var ds = this.grid.dataSource, i, v = this.grid.view;
52786 var s = this.selections;
52787 s.each(function(r){
52788 if((i = ds.indexOfId(r.id)) != -1){
52797 onRemove : function(v, index, r){
52798 this.selections.remove(r);
52802 onRowUpdated : function(v, index, r){
52803 if(this.isSelected(r)){
52804 v.onRowSelect(index);
52810 * @param {Array} records The records to select
52811 * @param {Boolean} keepExisting (optional) True to keep existing selections
52813 selectRecords : function(records, keepExisting){
52815 this.clearSelections();
52817 var ds = this.grid.dataSource;
52818 for(var i = 0, len = records.length; i < len; i++){
52819 this.selectRow(ds.indexOf(records[i]), true);
52824 * Gets the number of selected rows.
52827 getCount : function(){
52828 return this.selections.length;
52832 * Selects the first row in the grid.
52834 selectFirstRow : function(){
52839 * Select the last row.
52840 * @param {Boolean} keepExisting (optional) True to keep existing selections
52842 selectLastRow : function(keepExisting){
52843 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
52847 * Selects the row immediately following the last selected row.
52848 * @param {Boolean} keepExisting (optional) True to keep existing selections
52850 selectNext : function(keepExisting){
52851 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
52852 this.selectRow(this.last+1, keepExisting);
52853 this.grid.getView().focusRow(this.last);
52858 * Selects the row that precedes the last selected row.
52859 * @param {Boolean} keepExisting (optional) True to keep existing selections
52861 selectPrevious : function(keepExisting){
52863 this.selectRow(this.last-1, keepExisting);
52864 this.grid.getView().focusRow(this.last);
52869 * Returns the selected records
52870 * @return {Array} Array of selected records
52872 getSelections : function(){
52873 return [].concat(this.selections.items);
52877 * Returns the first selected record.
52880 getSelected : function(){
52881 return this.selections.itemAt(0);
52886 * Clears all selections.
52888 clearSelections : function(fast){
52889 if(this.locked) return;
52891 var ds = this.grid.dataSource;
52892 var s = this.selections;
52893 s.each(function(r){
52894 this.deselectRow(ds.indexOfId(r.id));
52898 this.selections.clear();
52905 * Selects all rows.
52907 selectAll : function(){
52908 if(this.locked) return;
52909 this.selections.clear();
52910 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
52911 this.selectRow(i, true);
52916 * Returns True if there is a selection.
52917 * @return {Boolean}
52919 hasSelection : function(){
52920 return this.selections.length > 0;
52924 * Returns True if the specified row is selected.
52925 * @param {Number/Record} record The record or index of the record to check
52926 * @return {Boolean}
52928 isSelected : function(index){
52929 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
52930 return (r && this.selections.key(r.id) ? true : false);
52934 * Returns True if the specified record id is selected.
52935 * @param {String} id The id of record to check
52936 * @return {Boolean}
52938 isIdSelected : function(id){
52939 return (this.selections.key(id) ? true : false);
52943 handleMouseDown : function(e, t){
52944 var view = this.grid.getView(), rowIndex;
52945 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
52948 if(e.shiftKey && this.last !== false){
52949 var last = this.last;
52950 this.selectRange(last, rowIndex, e.ctrlKey);
52951 this.last = last; // reset the last
52952 view.focusRow(rowIndex);
52954 var isSelected = this.isSelected(rowIndex);
52955 if(e.button !== 0 && isSelected){
52956 view.focusRow(rowIndex);
52957 }else if(e.ctrlKey && isSelected){
52958 this.deselectRow(rowIndex);
52959 }else if(!isSelected){
52960 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
52961 view.focusRow(rowIndex);
52964 this.fireEvent("afterselectionchange", this);
52967 handleDragableRowClick : function(grid, rowIndex, e)
52969 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
52970 this.selectRow(rowIndex, false);
52971 grid.view.focusRow(rowIndex);
52972 this.fireEvent("afterselectionchange", this);
52977 * Selects multiple rows.
52978 * @param {Array} rows Array of the indexes of the row to select
52979 * @param {Boolean} keepExisting (optional) True to keep existing selections
52981 selectRows : function(rows, keepExisting){
52983 this.clearSelections();
52985 for(var i = 0, len = rows.length; i < len; i++){
52986 this.selectRow(rows[i], true);
52991 * Selects a range of rows. All rows in between startRow and endRow are also selected.
52992 * @param {Number} startRow The index of the first row in the range
52993 * @param {Number} endRow The index of the last row in the range
52994 * @param {Boolean} keepExisting (optional) True to retain existing selections
52996 selectRange : function(startRow, endRow, keepExisting){
52997 if(this.locked) return;
52999 this.clearSelections();
53001 if(startRow <= endRow){
53002 for(var i = startRow; i <= endRow; i++){
53003 this.selectRow(i, true);
53006 for(var i = startRow; i >= endRow; i--){
53007 this.selectRow(i, true);
53013 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
53014 * @param {Number} startRow The index of the first row in the range
53015 * @param {Number} endRow The index of the last row in the range
53017 deselectRange : function(startRow, endRow, preventViewNotify){
53018 if(this.locked) return;
53019 for(var i = startRow; i <= endRow; i++){
53020 this.deselectRow(i, preventViewNotify);
53026 * @param {Number} row The index of the row to select
53027 * @param {Boolean} keepExisting (optional) True to keep existing selections
53029 selectRow : function(index, keepExisting, preventViewNotify){
53030 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
53031 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
53032 if(!keepExisting || this.singleSelect){
53033 this.clearSelections();
53035 var r = this.grid.dataSource.getAt(index);
53036 this.selections.add(r);
53037 this.last = this.lastActive = index;
53038 if(!preventViewNotify){
53039 this.grid.getView().onRowSelect(index);
53041 this.fireEvent("rowselect", this, index, r);
53042 this.fireEvent("selectionchange", this);
53048 * @param {Number} row The index of the row to deselect
53050 deselectRow : function(index, preventViewNotify){
53051 if(this.locked) return;
53052 if(this.last == index){
53055 if(this.lastActive == index){
53056 this.lastActive = false;
53058 var r = this.grid.dataSource.getAt(index);
53059 this.selections.remove(r);
53060 if(!preventViewNotify){
53061 this.grid.getView().onRowDeselect(index);
53063 this.fireEvent("rowdeselect", this, index);
53064 this.fireEvent("selectionchange", this);
53068 restoreLast : function(){
53070 this.last = this._last;
53075 acceptsNav : function(row, col, cm){
53076 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53080 onEditorKey : function(field, e){
53081 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
53086 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53088 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53090 }else if(k == e.ENTER && !e.ctrlKey){
53094 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
53096 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
53098 }else if(k == e.ESC){
53102 g.startEditing(newCell[0], newCell[1]);
53107 * Ext JS Library 1.1.1
53108 * Copyright(c) 2006-2007, Ext JS, LLC.
53110 * Originally Released Under LGPL - original licence link has changed is not relivant.
53113 * <script type="text/javascript">
53116 * @class Roo.grid.CellSelectionModel
53117 * @extends Roo.grid.AbstractSelectionModel
53118 * This class provides the basic implementation for cell selection in a grid.
53120 * @param {Object} config The object containing the configuration of this model.
53121 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
53123 Roo.grid.CellSelectionModel = function(config){
53124 Roo.apply(this, config);
53126 this.selection = null;
53130 * @event beforerowselect
53131 * Fires before a cell is selected.
53132 * @param {SelectionModel} this
53133 * @param {Number} rowIndex The selected row index
53134 * @param {Number} colIndex The selected cell index
53136 "beforecellselect" : true,
53138 * @event cellselect
53139 * Fires when a cell is selected.
53140 * @param {SelectionModel} this
53141 * @param {Number} rowIndex The selected row index
53142 * @param {Number} colIndex The selected cell index
53144 "cellselect" : true,
53146 * @event selectionchange
53147 * Fires when the active selection changes.
53148 * @param {SelectionModel} this
53149 * @param {Object} selection null for no selection or an object (o) with two properties
53151 <li>o.record: the record object for the row the selection is in</li>
53152 <li>o.cell: An array of [rowIndex, columnIndex]</li>
53155 "selectionchange" : true,
53158 * Fires when the tab (or enter) was pressed on the last editable cell
53159 * You can use this to trigger add new row.
53160 * @param {SelectionModel} this
53164 * @event beforeeditnext
53165 * Fires before the next editable sell is made active
53166 * You can use this to skip to another cell or fire the tabend
53167 * if you set cell to false
53168 * @param {Object} eventdata object : { cell : [ row, col ] }
53170 "beforeeditnext" : true
53172 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
53175 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
53177 enter_is_tab: false,
53180 initEvents : function(){
53181 this.grid.on("mousedown", this.handleMouseDown, this);
53182 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
53183 var view = this.grid.view;
53184 view.on("refresh", this.onViewChange, this);
53185 view.on("rowupdated", this.onRowUpdated, this);
53186 view.on("beforerowremoved", this.clearSelections, this);
53187 view.on("beforerowsinserted", this.clearSelections, this);
53188 if(this.grid.isEditor){
53189 this.grid.on("beforeedit", this.beforeEdit, this);
53194 beforeEdit : function(e){
53195 this.select(e.row, e.column, false, true, e.record);
53199 onRowUpdated : function(v, index, r){
53200 if(this.selection && this.selection.record == r){
53201 v.onCellSelect(index, this.selection.cell[1]);
53206 onViewChange : function(){
53207 this.clearSelections(true);
53211 * Returns the currently selected cell,.
53212 * @return {Array} The selected cell (row, column) or null if none selected.
53214 getSelectedCell : function(){
53215 return this.selection ? this.selection.cell : null;
53219 * Clears all selections.
53220 * @param {Boolean} true to prevent the gridview from being notified about the change.
53222 clearSelections : function(preventNotify){
53223 var s = this.selection;
53225 if(preventNotify !== true){
53226 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
53228 this.selection = null;
53229 this.fireEvent("selectionchange", this, null);
53234 * Returns true if there is a selection.
53235 * @return {Boolean}
53237 hasSelection : function(){
53238 return this.selection ? true : false;
53242 handleMouseDown : function(e, t){
53243 var v = this.grid.getView();
53244 if(this.isLocked()){
53247 var row = v.findRowIndex(t);
53248 var cell = v.findCellIndex(t);
53249 if(row !== false && cell !== false){
53250 this.select(row, cell);
53256 * @param {Number} rowIndex
53257 * @param {Number} collIndex
53259 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
53260 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
53261 this.clearSelections();
53262 r = r || this.grid.dataSource.getAt(rowIndex);
53265 cell : [rowIndex, colIndex]
53267 if(!preventViewNotify){
53268 var v = this.grid.getView();
53269 v.onCellSelect(rowIndex, colIndex);
53270 if(preventFocus !== true){
53271 v.focusCell(rowIndex, colIndex);
53274 this.fireEvent("cellselect", this, rowIndex, colIndex);
53275 this.fireEvent("selectionchange", this, this.selection);
53280 isSelectable : function(rowIndex, colIndex, cm){
53281 return !cm.isHidden(colIndex);
53285 handleKeyDown : function(e){
53286 //Roo.log('Cell Sel Model handleKeyDown');
53287 if(!e.isNavKeyPress()){
53290 var g = this.grid, s = this.selection;
53293 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
53295 this.select(cell[0], cell[1]);
53300 var walk = function(row, col, step){
53301 return g.walkCells(row, col, step, sm.isSelectable, sm);
53303 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
53310 // handled by onEditorKey
53311 if (g.isEditor && g.editing) {
53315 newCell = walk(r, c-1, -1);
53317 newCell = walk(r, c+1, 1);
53322 newCell = walk(r+1, c, 1);
53326 newCell = walk(r-1, c, -1);
53330 newCell = walk(r, c+1, 1);
53334 newCell = walk(r, c-1, -1);
53339 if(g.isEditor && !g.editing){
53340 g.startEditing(r, c);
53349 this.select(newCell[0], newCell[1]);
53355 acceptsNav : function(row, col, cm){
53356 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53360 * @param {Number} field (not used) - as it's normally used as a listener
53361 * @param {Number} e - event - fake it by using
53363 * var e = Roo.EventObjectImpl.prototype;
53364 * e.keyCode = e.TAB
53368 onEditorKey : function(field, e){
53370 var k = e.getKey(),
53373 ed = g.activeEditor,
53375 ///Roo.log('onEditorKey' + k);
53378 if (this.enter_is_tab && k == e.ENTER) {
53384 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53386 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53392 } else if(k == e.ENTER && !e.ctrlKey){
53395 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53397 } else if(k == e.ESC){
53402 var ecall = { cell : newCell, forward : forward };
53403 this.fireEvent('beforeeditnext', ecall );
53404 newCell = ecall.cell;
53405 forward = ecall.forward;
53409 //Roo.log('next cell after edit');
53410 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
53411 } else if (forward) {
53412 // tabbed past last
53413 this.fireEvent.defer(100, this, ['tabend',this]);
53418 * Ext JS Library 1.1.1
53419 * Copyright(c) 2006-2007, Ext JS, LLC.
53421 * Originally Released Under LGPL - original licence link has changed is not relivant.
53424 * <script type="text/javascript">
53428 * @class Roo.grid.EditorGrid
53429 * @extends Roo.grid.Grid
53430 * Class for creating and editable grid.
53431 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53432 * The container MUST have some type of size defined for the grid to fill. The container will be
53433 * automatically set to position relative if it isn't already.
53434 * @param {Object} dataSource The data model to bind to
53435 * @param {Object} colModel The column model with info about this grid's columns
53437 Roo.grid.EditorGrid = function(container, config){
53438 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
53439 this.getGridEl().addClass("xedit-grid");
53441 if(!this.selModel){
53442 this.selModel = new Roo.grid.CellSelectionModel();
53445 this.activeEditor = null;
53449 * @event beforeedit
53450 * Fires before cell editing is triggered. The edit event object has the following properties <br />
53451 * <ul style="padding:5px;padding-left:16px;">
53452 * <li>grid - This grid</li>
53453 * <li>record - The record being edited</li>
53454 * <li>field - The field name being edited</li>
53455 * <li>value - The value for the field being edited.</li>
53456 * <li>row - The grid row index</li>
53457 * <li>column - The grid column index</li>
53458 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53460 * @param {Object} e An edit event (see above for description)
53462 "beforeedit" : true,
53465 * Fires after a cell is edited. <br />
53466 * <ul style="padding:5px;padding-left:16px;">
53467 * <li>grid - This grid</li>
53468 * <li>record - The record being edited</li>
53469 * <li>field - The field name being edited</li>
53470 * <li>value - The value being set</li>
53471 * <li>originalValue - The original value for the field, before the edit.</li>
53472 * <li>row - The grid row index</li>
53473 * <li>column - The grid column index</li>
53475 * @param {Object} e An edit event (see above for description)
53477 "afteredit" : true,
53479 * @event validateedit
53480 * Fires after a cell is edited, but before the value is set in the record.
53481 * You can use this to modify the value being set in the field, Return false
53482 * to cancel the change. The edit event object has the following properties <br />
53483 * <ul style="padding:5px;padding-left:16px;">
53484 * <li>editor - This editor</li>
53485 * <li>grid - This grid</li>
53486 * <li>record - The record being edited</li>
53487 * <li>field - The field name being edited</li>
53488 * <li>value - The value being set</li>
53489 * <li>originalValue - The original value for the field, before the edit.</li>
53490 * <li>row - The grid row index</li>
53491 * <li>column - The grid column index</li>
53492 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
53494 * @param {Object} e An edit event (see above for description)
53496 "validateedit" : true
53498 this.on("bodyscroll", this.stopEditing, this);
53499 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
53502 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
53504 * @cfg {Number} clicksToEdit
53505 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
53512 trackMouseOver: false, // causes very odd FF errors
53514 onCellDblClick : function(g, row, col){
53515 this.startEditing(row, col);
53518 onEditComplete : function(ed, value, startValue){
53519 this.editing = false;
53520 this.activeEditor = null;
53521 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
53523 var field = this.colModel.getDataIndex(ed.col);
53528 originalValue: startValue,
53535 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
53538 if(String(value) !== String(startValue)){
53540 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
53541 r.set(field, e.value);
53542 // if we are dealing with a combo box..
53543 // then we also set the 'name' colum to be the displayField
53544 if (ed.field.displayField && ed.field.name) {
53545 r.set(ed.field.name, ed.field.el.dom.value);
53548 delete e.cancel; //?? why!!!
53549 this.fireEvent("afteredit", e);
53552 this.fireEvent("afteredit", e); // always fire it!
53554 this.view.focusCell(ed.row, ed.col);
53558 * Starts editing the specified for the specified row/column
53559 * @param {Number} rowIndex
53560 * @param {Number} colIndex
53562 startEditing : function(row, col){
53563 this.stopEditing();
53564 if(this.colModel.isCellEditable(col, row)){
53565 this.view.ensureVisible(row, col, true);
53567 var r = this.dataSource.getAt(row);
53568 var field = this.colModel.getDataIndex(col);
53569 var cell = Roo.get(this.view.getCell(row,col));
53574 value: r.data[field],
53579 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
53580 this.editing = true;
53581 var ed = this.colModel.getCellEditor(col, row);
53587 ed.render(ed.parentEl || document.body);
53593 (function(){ // complex but required for focus issues in safari, ie and opera
53597 ed.on("complete", this.onEditComplete, this, {single: true});
53598 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
53599 this.activeEditor = ed;
53600 var v = r.data[field];
53601 ed.startEdit(this.view.getCell(row, col), v);
53602 // combo's with 'displayField and name set
53603 if (ed.field.displayField && ed.field.name) {
53604 ed.field.el.dom.value = r.data[ed.field.name];
53608 }).defer(50, this);
53614 * Stops any active editing
53616 stopEditing : function(){
53617 if(this.activeEditor){
53618 this.activeEditor.completeEdit();
53620 this.activeEditor = null;
53624 * Called to get grid's drag proxy text, by default returns this.ddText.
53627 getDragDropText : function(){
53628 var count = this.selModel.getSelectedCell() ? 1 : 0;
53629 return String.format(this.ddText, count, count == 1 ? '' : 's');
53634 * Ext JS Library 1.1.1
53635 * Copyright(c) 2006-2007, Ext JS, LLC.
53637 * Originally Released Under LGPL - original licence link has changed is not relivant.
53640 * <script type="text/javascript">
53643 // private - not really -- you end up using it !
53644 // This is a support class used internally by the Grid components
53647 * @class Roo.grid.GridEditor
53648 * @extends Roo.Editor
53649 * Class for creating and editable grid elements.
53650 * @param {Object} config any settings (must include field)
53652 Roo.grid.GridEditor = function(field, config){
53653 if (!config && field.field) {
53655 field = Roo.factory(config.field, Roo.form);
53657 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
53658 field.monitorTab = false;
53661 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
53664 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
53667 alignment: "tl-tl",
53670 cls: "x-small-editor x-grid-editor",
53675 * Ext JS Library 1.1.1
53676 * Copyright(c) 2006-2007, Ext JS, LLC.
53678 * Originally Released Under LGPL - original licence link has changed is not relivant.
53681 * <script type="text/javascript">
53686 Roo.grid.PropertyRecord = Roo.data.Record.create([
53687 {name:'name',type:'string'}, 'value'
53691 Roo.grid.PropertyStore = function(grid, source){
53693 this.store = new Roo.data.Store({
53694 recordType : Roo.grid.PropertyRecord
53696 this.store.on('update', this.onUpdate, this);
53698 this.setSource(source);
53700 Roo.grid.PropertyStore.superclass.constructor.call(this);
53705 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
53706 setSource : function(o){
53708 this.store.removeAll();
53711 if(this.isEditableValue(o[k])){
53712 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
53715 this.store.loadRecords({records: data}, {}, true);
53718 onUpdate : function(ds, record, type){
53719 if(type == Roo.data.Record.EDIT){
53720 var v = record.data['value'];
53721 var oldValue = record.modified['value'];
53722 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
53723 this.source[record.id] = v;
53725 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
53732 getProperty : function(row){
53733 return this.store.getAt(row);
53736 isEditableValue: function(val){
53737 if(val && val instanceof Date){
53739 }else if(typeof val == 'object' || typeof val == 'function'){
53745 setValue : function(prop, value){
53746 this.source[prop] = value;
53747 this.store.getById(prop).set('value', value);
53750 getSource : function(){
53751 return this.source;
53755 Roo.grid.PropertyColumnModel = function(grid, store){
53758 g.PropertyColumnModel.superclass.constructor.call(this, [
53759 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
53760 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
53762 this.store = store;
53763 this.bselect = Roo.DomHelper.append(document.body, {
53764 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
53765 {tag: 'option', value: 'true', html: 'true'},
53766 {tag: 'option', value: 'false', html: 'false'}
53769 Roo.id(this.bselect);
53772 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
53773 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
53774 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
53775 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
53776 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
53778 this.renderCellDelegate = this.renderCell.createDelegate(this);
53779 this.renderPropDelegate = this.renderProp.createDelegate(this);
53782 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
53786 valueText : 'Value',
53788 dateFormat : 'm/j/Y',
53791 renderDate : function(dateVal){
53792 return dateVal.dateFormat(this.dateFormat);
53795 renderBool : function(bVal){
53796 return bVal ? 'true' : 'false';
53799 isCellEditable : function(colIndex, rowIndex){
53800 return colIndex == 1;
53803 getRenderer : function(col){
53805 this.renderCellDelegate : this.renderPropDelegate;
53808 renderProp : function(v){
53809 return this.getPropertyName(v);
53812 renderCell : function(val){
53814 if(val instanceof Date){
53815 rv = this.renderDate(val);
53816 }else if(typeof val == 'boolean'){
53817 rv = this.renderBool(val);
53819 return Roo.util.Format.htmlEncode(rv);
53822 getPropertyName : function(name){
53823 var pn = this.grid.propertyNames;
53824 return pn && pn[name] ? pn[name] : name;
53827 getCellEditor : function(colIndex, rowIndex){
53828 var p = this.store.getProperty(rowIndex);
53829 var n = p.data['name'], val = p.data['value'];
53831 if(typeof(this.grid.customEditors[n]) == 'string'){
53832 return this.editors[this.grid.customEditors[n]];
53834 if(typeof(this.grid.customEditors[n]) != 'undefined'){
53835 return this.grid.customEditors[n];
53837 if(val instanceof Date){
53838 return this.editors['date'];
53839 }else if(typeof val == 'number'){
53840 return this.editors['number'];
53841 }else if(typeof val == 'boolean'){
53842 return this.editors['boolean'];
53844 return this.editors['string'];
53850 * @class Roo.grid.PropertyGrid
53851 * @extends Roo.grid.EditorGrid
53852 * This class represents the interface of a component based property grid control.
53853 * <br><br>Usage:<pre><code>
53854 var grid = new Roo.grid.PropertyGrid("my-container-id", {
53862 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53863 * The container MUST have some type of size defined for the grid to fill. The container will be
53864 * automatically set to position relative if it isn't already.
53865 * @param {Object} config A config object that sets properties on this grid.
53867 Roo.grid.PropertyGrid = function(container, config){
53868 config = config || {};
53869 var store = new Roo.grid.PropertyStore(this);
53870 this.store = store;
53871 var cm = new Roo.grid.PropertyColumnModel(this, store);
53872 store.store.sort('name', 'ASC');
53873 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
53876 enableColLock:false,
53877 enableColumnMove:false,
53879 trackMouseOver: false,
53882 this.getGridEl().addClass('x-props-grid');
53883 this.lastEditRow = null;
53884 this.on('columnresize', this.onColumnResize, this);
53887 * @event beforepropertychange
53888 * Fires before a property changes (return false to stop?)
53889 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53890 * @param {String} id Record Id
53891 * @param {String} newval New Value
53892 * @param {String} oldval Old Value
53894 "beforepropertychange": true,
53896 * @event propertychange
53897 * Fires after a property changes
53898 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
53899 * @param {String} id Record Id
53900 * @param {String} newval New Value
53901 * @param {String} oldval Old Value
53903 "propertychange": true
53905 this.customEditors = this.customEditors || {};
53907 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
53910 * @cfg {Object} customEditors map of colnames=> custom editors.
53911 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
53912 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
53913 * false disables editing of the field.
53917 * @cfg {Object} propertyNames map of property Names to their displayed value
53920 render : function(){
53921 Roo.grid.PropertyGrid.superclass.render.call(this);
53922 this.autoSize.defer(100, this);
53925 autoSize : function(){
53926 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
53928 this.view.fitColumns();
53932 onColumnResize : function(){
53933 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
53937 * Sets the data for the Grid
53938 * accepts a Key => Value object of all the elements avaiable.
53939 * @param {Object} data to appear in grid.
53941 setSource : function(source){
53942 this.store.setSource(source);
53946 * Gets all the data from the grid.
53947 * @return {Object} data data stored in grid
53949 getSource : function(){
53950 return this.store.getSource();
53954 * Ext JS Library 1.1.1
53955 * Copyright(c) 2006-2007, Ext JS, LLC.
53957 * Originally Released Under LGPL - original licence link has changed is not relivant.
53960 * <script type="text/javascript">
53964 * @class Roo.LoadMask
53965 * A simple utility class for generically masking elements while loading data. If the element being masked has
53966 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
53967 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
53968 * element's UpdateManager load indicator and will be destroyed after the initial load.
53970 * Create a new LoadMask
53971 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
53972 * @param {Object} config The config object
53974 Roo.LoadMask = function(el, config){
53975 this.el = Roo.get(el);
53976 Roo.apply(this, config);
53978 this.store.on('beforeload', this.onBeforeLoad, this);
53979 this.store.on('load', this.onLoad, this);
53980 this.store.on('loadexception', this.onLoadException, this);
53981 this.removeMask = false;
53983 var um = this.el.getUpdateManager();
53984 um.showLoadIndicator = false; // disable the default indicator
53985 um.on('beforeupdate', this.onBeforeLoad, this);
53986 um.on('update', this.onLoad, this);
53987 um.on('failure', this.onLoad, this);
53988 this.removeMask = true;
53992 Roo.LoadMask.prototype = {
53994 * @cfg {Boolean} removeMask
53995 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
53996 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
53999 * @cfg {String} msg
54000 * The text to display in a centered loading message box (defaults to 'Loading...')
54002 msg : 'Loading...',
54004 * @cfg {String} msgCls
54005 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
54007 msgCls : 'x-mask-loading',
54010 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
54016 * Disables the mask to prevent it from being displayed
54018 disable : function(){
54019 this.disabled = true;
54023 * Enables the mask so that it can be displayed
54025 enable : function(){
54026 this.disabled = false;
54029 onLoadException : function()
54031 Roo.log(arguments);
54033 if (typeof(arguments[3]) != 'undefined') {
54034 Roo.MessageBox.alert("Error loading",arguments[3]);
54038 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
54039 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
54048 this.el.unmask(this.removeMask);
54051 onLoad : function()
54053 this.el.unmask(this.removeMask);
54057 onBeforeLoad : function(){
54058 if(!this.disabled){
54059 this.el.mask(this.msg, this.msgCls);
54064 destroy : function(){
54066 this.store.un('beforeload', this.onBeforeLoad, this);
54067 this.store.un('load', this.onLoad, this);
54068 this.store.un('loadexception', this.onLoadException, this);
54070 var um = this.el.getUpdateManager();
54071 um.un('beforeupdate', this.onBeforeLoad, this);
54072 um.un('update', this.onLoad, this);
54073 um.un('failure', this.onLoad, this);
54078 * Ext JS Library 1.1.1
54079 * Copyright(c) 2006-2007, Ext JS, LLC.
54081 * Originally Released Under LGPL - original licence link has changed is not relivant.
54084 * <script type="text/javascript">
54089 * @class Roo.XTemplate
54090 * @extends Roo.Template
54091 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
54093 var t = new Roo.XTemplate(
54094 '<select name="{name}">',
54095 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
54099 // then append, applying the master template values
54102 * Supported features:
54107 {a_variable} - output encoded.
54108 {a_variable.format:("Y-m-d")} - call a method on the variable
54109 {a_variable:raw} - unencoded output
54110 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
54111 {a_variable:this.method_on_template(...)} - call a method on the template object.
54116 <tpl for="a_variable or condition.."></tpl>
54117 <tpl if="a_variable or condition"></tpl>
54118 <tpl exec="some javascript"></tpl>
54119 <tpl name="named_template"></tpl> (experimental)
54121 <tpl for="."></tpl> - just iterate the property..
54122 <tpl for=".."></tpl> - iterates with the parent (probably the template)
54126 Roo.XTemplate = function()
54128 Roo.XTemplate.superclass.constructor.apply(this, arguments);
54135 Roo.extend(Roo.XTemplate, Roo.Template, {
54138 * The various sub templates
54143 * basic tag replacing syntax
54146 * // you can fake an object call by doing this
54150 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
54153 * compile the template
54155 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
54158 compile: function()
54162 s = ['<tpl>', s, '</tpl>'].join('');
54164 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
54165 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
54166 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
54167 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
54168 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
54173 while(true == !!(m = s.match(re))){
54174 var forMatch = m[0].match(nameRe),
54175 ifMatch = m[0].match(ifRe),
54176 execMatch = m[0].match(execRe),
54177 namedMatch = m[0].match(namedRe),
54182 name = forMatch && forMatch[1] ? forMatch[1] : '';
54185 // if - puts fn into test..
54186 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
54188 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
54193 // exec - calls a function... returns empty if true is returned.
54194 exp = execMatch && execMatch[1] ? execMatch[1] : null;
54196 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
54204 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
54205 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
54206 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
54209 var uid = namedMatch ? namedMatch[1] : id;
54213 id: namedMatch ? namedMatch[1] : id,
54220 s = s.replace(m[0], '');
54222 s = s.replace(m[0], '{xtpl'+ id + '}');
54227 for(var i = tpls.length-1; i >= 0; --i){
54228 this.compileTpl(tpls[i]);
54229 this.tpls[tpls[i].id] = tpls[i];
54231 this.master = tpls[tpls.length-1];
54235 * same as applyTemplate, except it's done to one of the subTemplates
54236 * when using named templates, you can do:
54238 * var str = pl.applySubTemplate('your-name', values);
54241 * @param {Number} id of the template
54242 * @param {Object} values to apply to template
54243 * @param {Object} parent (normaly the instance of this object)
54245 applySubTemplate : function(id, values, parent)
54249 var t = this.tpls[id];
54253 if(t.test && !t.test.call(this, values, parent)){
54257 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
54258 Roo.log(e.toString());
54264 if(t.exec && t.exec.call(this, values, parent)){
54268 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
54269 Roo.log(e.toString());
54274 var vs = t.target ? t.target.call(this, values, parent) : values;
54275 parent = t.target ? values : parent;
54276 if(t.target && vs instanceof Array){
54278 for(var i = 0, len = vs.length; i < len; i++){
54279 buf[buf.length] = t.compiled.call(this, vs[i], parent);
54281 return buf.join('');
54283 return t.compiled.call(this, vs, parent);
54285 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
54286 Roo.log(e.toString());
54287 Roo.log(t.compiled);
54292 compileTpl : function(tpl)
54294 var fm = Roo.util.Format;
54295 var useF = this.disableFormats !== true;
54296 var sep = Roo.isGecko ? "+" : ",";
54297 var undef = function(str) {
54298 Roo.log("Property not found :" + str);
54302 var fn = function(m, name, format, args)
54304 //Roo.log(arguments);
54305 args = args ? args.replace(/\\'/g,"'") : args;
54306 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
54307 if (typeof(format) == 'undefined') {
54308 format= 'htmlEncode';
54310 if (format == 'raw' ) {
54314 if(name.substr(0, 4) == 'xtpl'){
54315 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
54318 // build an array of options to determine if value is undefined..
54320 // basically get 'xxxx.yyyy' then do
54321 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
54322 // (function () { Roo.log("Property not found"); return ''; })() :
54327 Roo.each(name.split('.'), function(st) {
54328 lookfor += (lookfor.length ? '.': '') + st;
54329 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
54332 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
54335 if(format && useF){
54337 args = args ? ',' + args : "";
54339 if(format.substr(0, 5) != "this."){
54340 format = "fm." + format + '(';
54342 format = 'this.call("'+ format.substr(5) + '", ';
54346 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
54350 // called with xxyx.yuu:(test,test)
54352 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
54354 // raw.. - :raw modifier..
54355 return "'"+ sep + udef_st + name + ")"+sep+"'";
54359 // branched to use + in gecko and [].join() in others
54361 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
54362 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
54365 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
54366 body.push(tpl.body.replace(/(\r\n|\n)/g,
54367 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
54368 body.push("'].join('');};};");
54369 body = body.join('');
54372 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
54374 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
54380 applyTemplate : function(values){
54381 return this.master.compiled.call(this, values, {});
54382 //var s = this.subs;
54385 apply : function(){
54386 return this.applyTemplate.apply(this, arguments);
54391 Roo.XTemplate.from = function(el){
54392 el = Roo.getDom(el);
54393 return new Roo.XTemplate(el.value || el.innerHTML);
54395 * Original code for Roojs - LGPL
54396 * <script type="text/javascript">
54400 * @class Roo.XComponent
54401 * A delayed Element creator...
54402 * Or a way to group chunks of interface together.
54404 * Mypart.xyx = new Roo.XComponent({
54406 parent : 'Mypart.xyz', // empty == document.element.!!
54410 disabled : function() {}
54412 tree : function() { // return an tree of xtype declared components
54416 xtype : 'NestedLayoutPanel',
54423 * It can be used to build a big heiracy, with parent etc.
54424 * or you can just use this to render a single compoent to a dom element
54425 * MYPART.render(Roo.Element | String(id) | dom_element )
54427 * @extends Roo.util.Observable
54429 * @param cfg {Object} configuration of component
54432 Roo.XComponent = function(cfg) {
54433 Roo.apply(this, cfg);
54437 * Fires when this the componnt is built
54438 * @param {Roo.XComponent} c the component
54443 this.region = this.region || 'center'; // default..
54444 Roo.XComponent.register(this);
54445 this.modules = false;
54446 this.el = false; // where the layout goes..
54450 Roo.extend(Roo.XComponent, Roo.util.Observable, {
54453 * The created element (with Roo.factory())
54454 * @type {Roo.Layout}
54460 * for BC - use el in new code
54461 * @type {Roo.Layout}
54467 * for BC - use el in new code
54468 * @type {Roo.Layout}
54473 * @cfg {Function|boolean} disabled
54474 * If this module is disabled by some rule, return true from the funtion
54479 * @cfg {String} parent
54480 * Name of parent element which it get xtype added to..
54485 * @cfg {String} order
54486 * Used to set the order in which elements are created (usefull for multiple tabs)
54491 * @cfg {String} name
54492 * String to display while loading.
54496 * @cfg {String} region
54497 * Region to render component to (defaults to center)
54502 * @cfg {Array} items
54503 * A single item array - the first element is the root of the tree..
54504 * It's done this way to stay compatible with the Xtype system...
54510 * The method that retuns the tree of parts that make up this compoennt
54517 * render element to dom or tree
54518 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
54521 render : function(el)
54525 var hp = this.parent ? 1 : 0;
54527 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
54528 // if parent is a '#.....' string, then let's use that..
54529 var ename = this.parent.substr(1)
54530 this.parent = false;
54531 el = Roo.get(ename);
54533 Roo.log("Warning - element can not be found :#" + ename );
54539 if (!this.parent) {
54541 el = el ? Roo.get(el) : false;
54543 // it's a top level one..
54545 el : new Roo.BorderLayout(el || document.body, {
54551 tabPosition: 'top',
54552 //resizeTabs: true,
54553 alwaysShowTabs: el && hp? false : true,
54554 hideTabs: el || !hp ? true : false,
54561 if (!this.parent.el) {
54562 // probably an old style ctor, which has been disabled.
54566 // The 'tree' method is '_tree now'
54568 var tree = this._tree ? this._tree() : this.tree();
54569 tree.region = tree.region || this.region;
54570 this.el = this.parent.el.addxtype(tree);
54571 this.fireEvent('built', this);
54573 this.panel = this.el;
54574 this.layout = this.panel.layout;
54575 this.parentLayout = this.parent.layout || false;
54581 Roo.apply(Roo.XComponent, {
54583 * @property hideProgress
54584 * true to disable the building progress bar.. usefull on single page renders.
54587 hideProgress : false,
54589 * @property buildCompleted
54590 * True when the builder has completed building the interface.
54593 buildCompleted : false,
54596 * @property topModule
54597 * the upper most module - uses document.element as it's constructor.
54604 * @property modules
54605 * array of modules to be created by registration system.
54606 * @type {Array} of Roo.XComponent
54611 * @property elmodules
54612 * array of modules to be created by which use #ID
54613 * @type {Array} of Roo.XComponent
54620 * Register components to be built later.
54622 * This solves the following issues
54623 * - Building is not done on page load, but after an authentication process has occured.
54624 * - Interface elements are registered on page load
54625 * - Parent Interface elements may not be loaded before child, so this handles that..
54632 module : 'Pman.Tab.projectMgr',
54634 parent : 'Pman.layout',
54635 disabled : false, // or use a function..
54638 * * @param {Object} details about module
54640 register : function(obj) {
54642 Roo.XComponent.event.fireEvent('register', obj);
54643 switch(typeof(obj.disabled) ) {
54649 if ( obj.disabled() ) {
54655 if (obj.disabled) {
54661 this.modules.push(obj);
54665 * convert a string to an object..
54666 * eg. 'AAA.BBB' -> finds AAA.BBB
54670 toObject : function(str)
54672 if (!str || typeof(str) == 'object') {
54675 if (str.substring(0,1) == '#') {
54679 var ar = str.split('.');
54684 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
54686 throw "Module not found : " + str;
54690 throw "Module not found : " + str;
54692 Roo.each(ar, function(e) {
54693 if (typeof(o[e]) == 'undefined') {
54694 throw "Module not found : " + str;
54705 * move modules into their correct place in the tree..
54708 preBuild : function ()
54711 Roo.each(this.modules , function (obj)
54713 Roo.XComponent.event.fireEvent('beforebuild', obj);
54715 var opar = obj.parent;
54717 obj.parent = this.toObject(opar);
54719 Roo.log("parent:toObject failed: " + e.toString());
54724 Roo.debug && Roo.log("GOT top level module");
54725 Roo.debug && Roo.log(obj);
54726 obj.modules = new Roo.util.MixedCollection(false,
54727 function(o) { return o.order + '' }
54729 this.topModule = obj;
54732 // parent is a string (usually a dom element name..)
54733 if (typeof(obj.parent) == 'string') {
54734 this.elmodules.push(obj);
54737 if (obj.parent.constructor != Roo.XComponent) {
54738 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
54740 if (!obj.parent.modules) {
54741 obj.parent.modules = new Roo.util.MixedCollection(false,
54742 function(o) { return o.order + '' }
54745 if (obj.parent.disabled) {
54746 obj.disabled = true;
54748 obj.parent.modules.add(obj);
54753 * make a list of modules to build.
54754 * @return {Array} list of modules.
54757 buildOrder : function()
54760 var cmp = function(a,b) {
54761 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
54763 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
54764 throw "No top level modules to build";
54767 // make a flat list in order of modules to build.
54768 var mods = this.topModule ? [ this.topModule ] : [];
54770 // elmodules (is a list of DOM based modules )
54771 Roo.each(this.elmodules, function(e) {
54776 // add modules to their parents..
54777 var addMod = function(m) {
54778 Roo.debug && Roo.log("build Order: add: " + m.name);
54781 if (m.modules && !m.disabled) {
54782 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
54783 m.modules.keySort('ASC', cmp );
54784 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
54786 m.modules.each(addMod);
54788 Roo.debug && Roo.log("build Order: no child modules");
54790 // not sure if this is used any more..
54792 m.finalize.name = m.name + " (clean up) ";
54793 mods.push(m.finalize);
54797 if (this.topModule) {
54798 this.topModule.modules.keySort('ASC', cmp );
54799 this.topModule.modules.each(addMod);
54805 * Build the registered modules.
54806 * @param {Object} parent element.
54807 * @param {Function} optional method to call after module has been added.
54815 var mods = this.buildOrder();
54817 //this.allmods = mods;
54818 //Roo.debug && Roo.log(mods);
54820 if (!mods.length) { // should not happen
54821 throw "NO modules!!!";
54825 var msg = "Building Interface...";
54826 // flash it up as modal - so we store the mask!?
54827 if (!this.hideProgress) {
54828 Roo.MessageBox.show({ title: 'loading' });
54829 Roo.MessageBox.show({
54830 title: "Please wait...",
54839 var total = mods.length;
54842 var progressRun = function() {
54843 if (!mods.length) {
54844 Roo.debug && Roo.log('hide?');
54845 if (!this.hideProgress) {
54846 Roo.MessageBox.hide();
54848 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
54854 var m = mods.shift();
54857 Roo.debug && Roo.log(m);
54858 // not sure if this is supported any more.. - modules that are are just function
54859 if (typeof(m) == 'function') {
54861 return progressRun.defer(10, _this);
54865 msg = "Building Interface " + (total - mods.length) +
54867 (m.name ? (' - ' + m.name) : '');
54868 Roo.debug && Roo.log(msg);
54869 if (!this.hideProgress) {
54870 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
54874 // is the module disabled?
54875 var disabled = (typeof(m.disabled) == 'function') ?
54876 m.disabled.call(m.module.disabled) : m.disabled;
54880 return progressRun(); // we do not update the display!
54888 // it's 10 on top level, and 1 on others??? why...
54889 return progressRun.defer(10, _this);
54892 progressRun.defer(1, _this);
54906 * wrapper for event.on - aliased later..
54907 * Typically use to register a event handler for register:
54909 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
54918 Roo.XComponent.event = new Roo.util.Observable({
54922 * Fires when an Component is registered,
54923 * set the disable property on the Component to stop registration.
54924 * @param {Roo.XComponent} c the component being registerd.
54929 * @event beforebuild
54930 * Fires before each Component is built
54931 * can be used to apply permissions.
54932 * @param {Roo.XComponent} c the component being registerd.
54935 'beforebuild' : true,
54937 * @event buildcomplete
54938 * Fires on the top level element when all elements have been built
54939 * @param {Roo.XComponent} the top level component.
54941 'buildcomplete' : true
54946 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
54947 //<script type="text/javascript">
54952 * @extends Roo.LayoutDialog
54953 * A generic Login Dialog..... - only one needed in theory!?!?
54955 * Fires XComponent builder on success...
54958 * username,password, lang = for login actions.
54959 * check = 1 for periodic checking that sesion is valid.
54960 * passwordRequest = email request password
54961 * logout = 1 = to logout
54963 * Affects: (this id="????" elements)
54964 * loading (removed) (used to indicate application is loading)
54965 * loading-mask (hides) (used to hide application when it's building loading)
54971 * Myapp.login = Roo.Login({
54987 Roo.Login = function(cfg)
54993 Roo.apply(this,cfg);
54995 Roo.onReady(function() {
55001 Roo.Login.superclass.constructor.call(this, this);
55002 //this.addxtype(this.items[0]);
55008 Roo.extend(Roo.Login, Roo.LayoutDialog, {
55011 * @cfg {String} method
55012 * Method used to query for login details.
55017 * @cfg {String} url
55018 * URL to query login data. - eg. baseURL + '/Login.php'
55024 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
55029 * @property checkFails
55030 * Number of times we have attempted to get authentication check, and failed.
55035 * @property intervalID
55036 * The window interval that does the constant login checking.
55042 onLoad : function() // called on page load...
55046 if (Roo.get('loading')) { // clear any loading indicator..
55047 Roo.get('loading').remove();
55050 //this.switchLang('en'); // set the language to english..
55053 success: function(response, opts) { // check successfull...
55055 var res = this.processResponse(response);
55056 this.checkFails =0;
55057 if (!res.success) { // error!
55058 this.checkFails = 5;
55059 //console.log('call failure');
55060 return this.failure(response,opts);
55063 if (!res.data.id) { // id=0 == login failure.
55064 return this.show();
55068 //console.log(success);
55069 this.fillAuth(res.data);
55070 this.checkFails =0;
55071 Roo.XComponent.build();
55073 failure : this.show
55079 check: function(cfg) // called every so often to refresh cookie etc..
55081 if (cfg.again) { // could be undefined..
55084 this.checkFails = 0;
55087 if (this.sending) {
55088 if ( this.checkFails > 4) {
55089 Roo.MessageBox.alert("Error",
55090 "Error getting authentication status. - try reloading, or wait a while", function() {
55091 _this.sending = false;
55096 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
55099 this.sending = true;
55106 method: this.method,
55107 success: cfg.success || this.success,
55108 failure : cfg.failure || this.failure,
55118 window.onbeforeunload = function() { }; // false does not work for IE..
55128 failure : function() {
55129 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
55130 document.location = document.location.toString() + '?ts=' + Math.random();
55134 success : function() {
55135 _this.user = false;
55136 this.checkFails =0;
55138 document.location = document.location.toString() + '?ts=' + Math.random();
55145 processResponse : function (response)
55149 res = Roo.decode(response.responseText);
55151 if (typeof(res) != 'object') {
55152 res = { success : false, errorMsg : res, errors : true };
55154 if (typeof(res.success) == 'undefined') {
55155 res.success = false;
55159 res = { success : false, errorMsg : response.responseText, errors : true };
55164 success : function(response, opts) // check successfull...
55166 this.sending = false;
55167 var res = this.processResponse(response);
55168 if (!res.success) {
55169 return this.failure(response, opts);
55171 if (!res.data || !res.data.id) {
55172 return this.failure(response,opts);
55174 //console.log(res);
55175 this.fillAuth(res.data);
55177 this.checkFails =0;
55182 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
55184 this.authUser = -1;
55185 this.sending = false;
55186 var res = this.processResponse(response);
55187 //console.log(res);
55188 if ( this.checkFails > 2) {
55190 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
55191 "Error getting authentication status. - try reloading");
55194 opts.callCfg.again = true;
55195 this.check.defer(1000, this, [ opts.callCfg ]);
55201 fillAuth: function(au) {
55202 this.startAuthCheck();
55203 this.authUserId = au.id;
55204 this.authUser = au;
55205 this.lastChecked = new Date();
55206 this.fireEvent('refreshed', au);
55207 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
55208 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
55209 au.lang = au.lang || 'en';
55210 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
55211 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
55212 this.switchLang(au.lang );
55215 // open system... - -on setyp..
55216 if (this.authUserId < 0) {
55217 Roo.MessageBox.alert("Warning",
55218 "This is an open system - please set up a admin user with a password.");
55221 //Pman.onload(); // which should do nothing if it's a re-auth result...
55226 startAuthCheck : function() // starter for timeout checking..
55228 if (this.intervalID) { // timer already in place...
55232 this.intervalID = window.setInterval(function() {
55233 _this.check(false);
55234 }, 120000); // every 120 secs = 2mins..
55240 switchLang : function (lang)
55242 _T = typeof(_T) == 'undefined' ? false : _T;
55243 if (!_T || !lang.length) {
55247 if (!_T && lang != 'en') {
55248 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
55252 if (typeof(_T.en) == 'undefined') {
55254 Roo.apply(_T.en, _T);
55257 if (typeof(_T[lang]) == 'undefined') {
55258 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
55263 Roo.apply(_T, _T[lang]);
55264 // just need to set the text values for everything...
55266 /* this will not work ...
55270 function formLabel(name, val) {
55271 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
55274 formLabel('password', "Password"+':');
55275 formLabel('username', "Email Address"+':');
55276 formLabel('lang', "Language"+':');
55277 this.dialog.setTitle("Login");
55278 this.dialog.buttons[0].setText("Forgot Password");
55279 this.dialog.buttons[1].setText("Login");
55298 collapsible: false,
55300 center: { // needed??
55303 // tabPosition: 'top',
55306 alwaysShowTabs: false
55310 show : function(dlg)
55312 //console.log(this);
55313 this.form = this.layout.getRegion('center').activePanel.form;
55314 this.form.dialog = dlg;
55315 this.buttons[0].form = this.form;
55316 this.buttons[0].dialog = dlg;
55317 this.buttons[1].form = this.form;
55318 this.buttons[1].dialog = dlg;
55320 //this.resizeToLogo.defer(1000,this);
55321 // this is all related to resizing for logos..
55322 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
55324 // this.resizeToLogo.defer(1000,this);
55327 //var w = Ext.lib.Dom.getViewWidth() - 100;
55328 //var h = Ext.lib.Dom.getViewHeight() - 100;
55329 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
55331 if (this.disabled) {
55336 if (this.user.id < 0) { // used for inital setup situations.
55340 if (this.intervalID) {
55341 // remove the timer
55342 window.clearInterval(this.intervalID);
55343 this.intervalID = false;
55347 if (Roo.get('loading')) {
55348 Roo.get('loading').remove();
55350 if (Roo.get('loading-mask')) {
55351 Roo.get('loading-mask').hide();
55354 //incomming._node = tnode;
55356 //this.dialog.modal = !modal;
55357 //this.dialog.show();
55361 this.form.setValues({
55362 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
55363 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
55366 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
55367 if (this.form.findField('username').getValue().length > 0 ){
55368 this.form.findField('password').focus();
55370 this.form.findField('username').focus();
55378 xtype : 'ContentPanel',
55390 style : 'margin: 10px;',
55393 actionfailed : function(f, act) {
55394 // form can return { errors: .... }
55396 //act.result.errors // invalid form element list...
55397 //act.result.errorMsg// invalid form element list...
55399 this.dialog.el.unmask();
55400 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
55401 "Login failed - communication error - try again.");
55404 actioncomplete: function(re, act) {
55406 Roo.state.Manager.set(
55407 this.dialog.realm + '.username',
55408 this.findField('username').getValue()
55410 Roo.state.Manager.set(
55411 this.dialog.realm + '.lang',
55412 this.findField('lang').getValue()
55415 this.dialog.fillAuth(act.result.data);
55417 this.dialog.hide();
55419 if (Roo.get('loading-mask')) {
55420 Roo.get('loading-mask').show();
55422 Roo.XComponent.build();
55430 xtype : 'TextField',
55432 fieldLabel: "Email Address",
55435 autoCreate : {tag: "input", type: "text", size: "20"}
55438 xtype : 'TextField',
55440 fieldLabel: "Password",
55441 inputType: 'password',
55444 autoCreate : {tag: "input", type: "text", size: "20"},
55446 specialkey : function(e,ev) {
55447 if (ev.keyCode == 13) {
55448 this.form.dialog.el.mask("Logging in");
55449 this.form.doAction('submit', {
55450 url: this.form.dialog.url,
55451 method: this.form.dialog.method
55458 xtype : 'ComboBox',
55460 fieldLabel: "Language",
55463 xtype : 'SimpleStore',
55464 fields: ['lang', 'ldisp'],
55466 [ 'en', 'English' ],
55467 [ 'zh_HK' , '\u7E41\u4E2D' ],
55468 [ 'zh_CN', '\u7C21\u4E2D' ]
55472 valueField : 'lang',
55473 hiddenName: 'lang',
55475 displayField:'ldisp',
55479 triggerAction: 'all',
55480 emptyText:'Select a Language...',
55481 selectOnFocus:true,
55483 select : function(cb, rec, ix) {
55484 this.form.switchLang(rec.data.lang);
55500 text : "Forgot Password",
55502 click : function() {
55503 //console.log(this);
55504 var n = this.form.findField('username').getValue();
55506 Roo.MessageBox.alert("Error", "Fill in your email address");
55510 url: this.dialog.url,
55514 method: this.dialog.method,
55515 success: function(response, opts) { // check successfull...
55517 var res = this.dialog.processResponse(response);
55518 if (!res.success) { // error!
55519 Roo.MessageBox.alert("Error" ,
55520 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
55523 Roo.MessageBox.alert("Notice" ,
55524 "Please check you email for the Password Reset message");
55526 failure : function() {
55527 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
55540 click : function () {
55542 this.dialog.el.mask("Logging in");
55543 this.form.doAction('submit', {
55544 url: this.dialog.url,
55545 method: this.dialog.method