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 getViewWidth : function(full) {
1779 return full ? this.getDocumentWidth() : this.getViewportWidth();
1782 getViewHeight : function(full) {
1783 return full ? this.getDocumentHeight() : this.getViewportHeight();
1786 getDocumentHeight: function() {
1787 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1788 return Math.max(scrollHeight, this.getViewportHeight());
1791 getDocumentWidth: function() {
1792 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1793 return Math.max(scrollWidth, this.getViewportWidth());
1796 getViewportHeight: function() {
1797 var height = self.innerHeight;
1798 var mode = document.compatMode;
1800 if ((mode || Roo.isIE) && !Roo.isOpera) {
1801 height = (mode == "CSS1Compat") ?
1802 document.documentElement.clientHeight :
1803 document.body.clientHeight;
1809 getViewportWidth: function() {
1810 var width = self.innerWidth;
1811 var mode = document.compatMode;
1813 if (mode || Roo.isIE) {
1814 width = (mode == "CSS1Compat") ?
1815 document.documentElement.clientWidth :
1816 document.body.clientWidth;
1821 isAncestor : function(p, c) {
1828 if (p.contains && !Roo.isSafari) {
1829 return p.contains(c);
1830 } else if (p.compareDocumentPosition) {
1831 return !!(p.compareDocumentPosition(c) & 16);
1833 var parent = c.parentNode;
1838 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1841 parent = parent.parentNode;
1847 getRegion : function(el) {
1848 return Roo.lib.Region.getRegion(el);
1851 getY : function(el) {
1852 return this.getXY(el)[1];
1855 getX : function(el) {
1856 return this.getXY(el)[0];
1859 getXY : function(el) {
1860 var p, pe, b, scroll, bd = document.body;
1861 el = Roo.getDom(el);
1862 var fly = Roo.lib.AnimBase.fly;
1863 if (el.getBoundingClientRect) {
1864 b = el.getBoundingClientRect();
1865 scroll = fly(document).getScroll();
1866 return [b.left + scroll.left, b.top + scroll.top];
1872 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1879 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1886 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1887 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1894 if (p != el && pe.getStyle('overflow') != 'visible') {
1902 if (Roo.isSafari && hasAbsolute) {
1907 if (Roo.isGecko && !hasAbsolute) {
1909 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1910 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1914 while (p && p != bd) {
1915 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1927 setXY : function(el, xy) {
1928 el = Roo.fly(el, '_setXY');
1930 var pts = el.translatePoints(xy);
1931 if (xy[0] !== false) {
1932 el.dom.style.left = pts.left + "px";
1934 if (xy[1] !== false) {
1935 el.dom.style.top = pts.top + "px";
1939 setX : function(el, x) {
1940 this.setXY(el, [x, false]);
1943 setY : function(el, y) {
1944 this.setXY(el, [false, y]);
1948 * Portions of this file are based on pieces of Yahoo User Interface Library
1949 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1950 * YUI licensed under the BSD License:
1951 * http://developer.yahoo.net/yui/license.txt
1952 * <script type="text/javascript">
1956 Roo.lib.Event = function() {
1957 var loadComplete = false;
1959 var unloadListeners = [];
1961 var onAvailStack = [];
1963 var lastError = null;
1976 startInterval: function() {
1977 if (!this._interval) {
1979 var callback = function() {
1980 self._tryPreloadAttach();
1982 this._interval = setInterval(callback, this.POLL_INTERVAL);
1987 onAvailable: function(p_id, p_fn, p_obj, p_override) {
1988 onAvailStack.push({ id: p_id,
1991 override: p_override,
1992 checkReady: false });
1994 retryCount = this.POLL_RETRYS;
1995 this.startInterval();
1999 addListener: function(el, eventName, fn) {
2000 el = Roo.getDom(el);
2005 if ("unload" == eventName) {
2006 unloadListeners[unloadListeners.length] =
2007 [el, eventName, fn];
2011 var wrappedFn = function(e) {
2012 return fn(Roo.lib.Event.getEvent(e));
2015 var li = [el, eventName, fn, wrappedFn];
2017 var index = listeners.length;
2018 listeners[index] = li;
2020 this.doAdd(el, eventName, wrappedFn, false);
2026 removeListener: function(el, eventName, fn) {
2029 el = Roo.getDom(el);
2032 return this.purgeElement(el, false, eventName);
2036 if ("unload" == eventName) {
2038 for (i = 0,len = unloadListeners.length; i < len; i++) {
2039 var li = unloadListeners[i];
2042 li[1] == eventName &&
2044 unloadListeners.splice(i, 1);
2052 var cacheItem = null;
2055 var index = arguments[3];
2057 if ("undefined" == typeof index) {
2058 index = this._getCacheIndex(el, eventName, fn);
2062 cacheItem = listeners[index];
2065 if (!el || !cacheItem) {
2069 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2071 delete listeners[index][this.WFN];
2072 delete listeners[index][this.FN];
2073 listeners.splice(index, 1);
2080 getTarget: function(ev, resolveTextNode) {
2081 ev = ev.browserEvent || ev;
2082 var t = ev.target || ev.srcElement;
2083 return this.resolveTextNode(t);
2087 resolveTextNode: function(node) {
2088 if (Roo.isSafari && node && 3 == node.nodeType) {
2089 return node.parentNode;
2096 getPageX: function(ev) {
2097 ev = ev.browserEvent || ev;
2099 if (!x && 0 !== x) {
2100 x = ev.clientX || 0;
2103 x += this.getScroll()[1];
2111 getPageY: function(ev) {
2112 ev = ev.browserEvent || ev;
2114 if (!y && 0 !== y) {
2115 y = ev.clientY || 0;
2118 y += this.getScroll()[0];
2127 getXY: function(ev) {
2128 ev = ev.browserEvent || ev;
2129 return [this.getPageX(ev), this.getPageY(ev)];
2133 getRelatedTarget: function(ev) {
2134 ev = ev.browserEvent || ev;
2135 var t = ev.relatedTarget;
2137 if (ev.type == "mouseout") {
2139 } else if (ev.type == "mouseover") {
2144 return this.resolveTextNode(t);
2148 getTime: function(ev) {
2149 ev = ev.browserEvent || ev;
2151 var t = new Date().getTime();
2155 this.lastError = ex;
2164 stopEvent: function(ev) {
2165 this.stopPropagation(ev);
2166 this.preventDefault(ev);
2170 stopPropagation: function(ev) {
2171 ev = ev.browserEvent || ev;
2172 if (ev.stopPropagation) {
2173 ev.stopPropagation();
2175 ev.cancelBubble = true;
2180 preventDefault: function(ev) {
2181 ev = ev.browserEvent || ev;
2182 if(ev.preventDefault) {
2183 ev.preventDefault();
2185 ev.returnValue = false;
2190 getEvent: function(e) {
2191 var ev = e || window.event;
2193 var c = this.getEvent.caller;
2195 ev = c.arguments[0];
2196 if (ev && Event == ev.constructor) {
2206 getCharCode: function(ev) {
2207 ev = ev.browserEvent || ev;
2208 return ev.charCode || ev.keyCode || 0;
2212 _getCacheIndex: function(el, eventName, fn) {
2213 for (var i = 0,len = listeners.length; i < len; ++i) {
2214 var li = listeners[i];
2216 li[this.FN] == fn &&
2217 li[this.EL] == el &&
2218 li[this.TYPE] == eventName) {
2230 getEl: function(id) {
2231 return document.getElementById(id);
2235 clearCache: function() {
2239 _load: function(e) {
2240 loadComplete = true;
2241 var EU = Roo.lib.Event;
2245 EU.doRemove(window, "load", EU._load);
2250 _tryPreloadAttach: function() {
2259 var tryAgain = !loadComplete;
2261 tryAgain = (retryCount > 0);
2266 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2267 var item = onAvailStack[i];
2269 var el = this.getEl(item.id);
2272 if (!item.checkReady ||
2275 (document && document.body)) {
2278 if (item.override) {
2279 if (item.override === true) {
2282 scope = item.override;
2285 item.fn.call(scope, item.obj);
2286 onAvailStack[i] = null;
2289 notAvail.push(item);
2294 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2298 this.startInterval();
2300 clearInterval(this._interval);
2301 this._interval = null;
2304 this.locked = false;
2311 purgeElement: function(el, recurse, eventName) {
2312 var elListeners = this.getListeners(el, eventName);
2314 for (var i = 0,len = elListeners.length; i < len; ++i) {
2315 var l = elListeners[i];
2316 this.removeListener(el, l.type, l.fn);
2320 if (recurse && el && el.childNodes) {
2321 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2322 this.purgeElement(el.childNodes[i], recurse, eventName);
2328 getListeners: function(el, eventName) {
2329 var results = [], searchLists;
2331 searchLists = [listeners, unloadListeners];
2332 } else if (eventName == "unload") {
2333 searchLists = [unloadListeners];
2335 searchLists = [listeners];
2338 for (var j = 0; j < searchLists.length; ++j) {
2339 var searchList = searchLists[j];
2340 if (searchList && searchList.length > 0) {
2341 for (var i = 0,len = searchList.length; i < len; ++i) {
2342 var l = searchList[i];
2343 if (l && l[this.EL] === el &&
2344 (!eventName || eventName === l[this.TYPE])) {
2349 adjust: l[this.ADJ_SCOPE],
2357 return (results.length) ? results : null;
2361 _unload: function(e) {
2363 var EU = Roo.lib.Event, i, j, l, len, index;
2365 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2366 l = unloadListeners[i];
2369 if (l[EU.ADJ_SCOPE]) {
2370 if (l[EU.ADJ_SCOPE] === true) {
2373 scope = l[EU.ADJ_SCOPE];
2376 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2377 unloadListeners[i] = null;
2383 unloadListeners = null;
2385 if (listeners && listeners.length > 0) {
2386 j = listeners.length;
2389 l = listeners[index];
2391 EU.removeListener(l[EU.EL], l[EU.TYPE],
2401 EU.doRemove(window, "unload", EU._unload);
2406 getScroll: function() {
2407 var dd = document.documentElement, db = document.body;
2408 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2409 return [dd.scrollTop, dd.scrollLeft];
2411 return [db.scrollTop, db.scrollLeft];
2418 doAdd: function () {
2419 if (window.addEventListener) {
2420 return function(el, eventName, fn, capture) {
2421 el.addEventListener(eventName, fn, (capture));
2423 } else if (window.attachEvent) {
2424 return function(el, eventName, fn, capture) {
2425 el.attachEvent("on" + eventName, fn);
2434 doRemove: function() {
2435 if (window.removeEventListener) {
2436 return function (el, eventName, fn, capture) {
2437 el.removeEventListener(eventName, fn, (capture));
2439 } else if (window.detachEvent) {
2440 return function (el, eventName, fn) {
2441 el.detachEvent("on" + eventName, fn);
2453 var E = Roo.lib.Event;
2454 E.on = E.addListener;
2455 E.un = E.removeListener;
2457 if (document && document.body) {
2460 E.doAdd(window, "load", E._load);
2462 E.doAdd(window, "unload", E._unload);
2463 E._tryPreloadAttach();
2467 * Portions of this file are based on pieces of Yahoo User Interface Library
2468 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2469 * YUI licensed under the BSD License:
2470 * http://developer.yahoo.net/yui/license.txt
2471 * <script type="text/javascript">
2477 * @class Roo.lib.Ajax
2484 request : function(method, uri, cb, data, options) {
2486 var hs = options.headers;
2489 if(hs.hasOwnProperty(h)){
2490 this.initHeader(h, hs[h], false);
2494 if(options.xmlData){
2495 this.initHeader('Content-Type', 'text/xml', false);
2497 data = options.xmlData;
2501 return this.asyncRequest(method, uri, cb, data);
2504 serializeForm : function(form) {
2505 if(typeof form == 'string') {
2506 form = (document.getElementById(form) || document.forms[form]);
2509 var el, name, val, disabled, data = '', hasSubmit = false;
2510 for (var i = 0; i < form.elements.length; i++) {
2511 el = form.elements[i];
2512 disabled = form.elements[i].disabled;
2513 name = form.elements[i].name;
2514 val = form.elements[i].value;
2516 if (!disabled && name){
2520 case 'select-multiple':
2521 for (var j = 0; j < el.options.length; j++) {
2522 if (el.options[j].selected) {
2524 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2527 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2535 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2548 if(hasSubmit == false) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2554 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2559 data = data.substr(0, data.length - 1);
2567 useDefaultHeader:true,
2569 defaultPostHeader:'application/x-www-form-urlencoded',
2571 useDefaultXhrHeader:true,
2573 defaultXhrHeader:'XMLHttpRequest',
2575 hasDefaultHeaders:true,
2587 setProgId:function(id)
2589 this.activeX.unshift(id);
2592 setDefaultPostHeader:function(b)
2594 this.useDefaultHeader = b;
2597 setDefaultXhrHeader:function(b)
2599 this.useDefaultXhrHeader = b;
2602 setPollingInterval:function(i)
2604 if (typeof i == 'number' && isFinite(i)) {
2605 this.pollInterval = i;
2609 createXhrObject:function(transactionId)
2615 http = new XMLHttpRequest();
2617 obj = { conn:http, tId:transactionId };
2621 for (var i = 0; i < this.activeX.length; ++i) {
2625 http = new ActiveXObject(this.activeX[i]);
2627 obj = { conn:http, tId:transactionId };
2640 getConnectionObject:function()
2643 var tId = this.transactionId;
2647 o = this.createXhrObject(tId);
2649 this.transactionId++;
2660 asyncRequest:function(method, uri, callback, postData)
2662 var o = this.getConnectionObject();
2668 o.conn.open(method, uri, true);
2670 if (this.useDefaultXhrHeader) {
2671 if (!this.defaultHeaders['X-Requested-With']) {
2672 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2676 if(postData && this.useDefaultHeader){
2677 this.initHeader('Content-Type', this.defaultPostHeader);
2680 if (this.hasDefaultHeaders || this.hasHeaders) {
2684 this.handleReadyState(o, callback);
2685 o.conn.send(postData || null);
2691 handleReadyState:function(o, callback)
2695 if (callback && callback.timeout) {
2696 this.timeout[o.tId] = window.setTimeout(function() {
2697 oConn.abort(o, callback, true);
2698 }, callback.timeout);
2701 this.poll[o.tId] = window.setInterval(
2703 if (o.conn && o.conn.readyState == 4) {
2704 window.clearInterval(oConn.poll[o.tId]);
2705 delete oConn.poll[o.tId];
2707 if(callback && callback.timeout) {
2708 window.clearTimeout(oConn.timeout[o.tId]);
2709 delete oConn.timeout[o.tId];
2712 oConn.handleTransactionResponse(o, callback);
2715 , this.pollInterval);
2718 handleTransactionResponse:function(o, callback, isAbort)
2722 this.releaseObject(o);
2726 var httpStatus, responseObject;
2730 if (o.conn.status !== undefined && o.conn.status != 0) {
2731 httpStatus = o.conn.status;
2743 if (httpStatus >= 200 && httpStatus < 300) {
2744 responseObject = this.createResponseObject(o, callback.argument);
2745 if (callback.success) {
2746 if (!callback.scope) {
2747 callback.success(responseObject);
2752 callback.success.apply(callback.scope, [responseObject]);
2757 switch (httpStatus) {
2765 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2766 if (callback.failure) {
2767 if (!callback.scope) {
2768 callback.failure(responseObject);
2771 callback.failure.apply(callback.scope, [responseObject]);
2776 responseObject = this.createResponseObject(o, callback.argument);
2777 if (callback.failure) {
2778 if (!callback.scope) {
2779 callback.failure(responseObject);
2782 callback.failure.apply(callback.scope, [responseObject]);
2788 this.releaseObject(o);
2789 responseObject = null;
2792 createResponseObject:function(o, callbackArg)
2799 var headerStr = o.conn.getAllResponseHeaders();
2800 var header = headerStr.split('\n');
2801 for (var i = 0; i < header.length; i++) {
2802 var delimitPos = header[i].indexOf(':');
2803 if (delimitPos != -1) {
2804 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2812 obj.status = o.conn.status;
2813 obj.statusText = o.conn.statusText;
2814 obj.getResponseHeader = headerObj;
2815 obj.getAllResponseHeaders = headerStr;
2816 obj.responseText = o.conn.responseText;
2817 obj.responseXML = o.conn.responseXML;
2819 if (typeof callbackArg !== undefined) {
2820 obj.argument = callbackArg;
2826 createExceptionObject:function(tId, callbackArg, isAbort)
2829 var COMM_ERROR = 'communication failure';
2830 var ABORT_CODE = -1;
2831 var ABORT_ERROR = 'transaction aborted';
2837 obj.status = ABORT_CODE;
2838 obj.statusText = ABORT_ERROR;
2841 obj.status = COMM_CODE;
2842 obj.statusText = COMM_ERROR;
2846 obj.argument = callbackArg;
2852 initHeader:function(label, value, isDefault)
2854 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2856 if (headerObj[label] === undefined) {
2857 headerObj[label] = value;
2862 headerObj[label] = value + "," + headerObj[label];
2866 this.hasDefaultHeaders = true;
2869 this.hasHeaders = true;
2874 setHeader:function(o)
2876 if (this.hasDefaultHeaders) {
2877 for (var prop in this.defaultHeaders) {
2878 if (this.defaultHeaders.hasOwnProperty(prop)) {
2879 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2884 if (this.hasHeaders) {
2885 for (var prop in this.headers) {
2886 if (this.headers.hasOwnProperty(prop)) {
2887 o.conn.setRequestHeader(prop, this.headers[prop]);
2891 this.hasHeaders = false;
2895 resetDefaultHeaders:function() {
2896 delete this.defaultHeaders;
2897 this.defaultHeaders = {};
2898 this.hasDefaultHeaders = false;
2901 abort:function(o, callback, isTimeout)
2903 if(this.isCallInProgress(o)) {
2905 window.clearInterval(this.poll[o.tId]);
2906 delete this.poll[o.tId];
2908 delete this.timeout[o.tId];
2911 this.handleTransactionResponse(o, callback, true);
2921 isCallInProgress:function(o)
2924 return o.conn.readyState != 4 && o.conn.readyState != 0;
2933 releaseObject:function(o)
2942 'MSXML2.XMLHTTP.3.0',
2950 * Portions of this file are based on pieces of Yahoo User Interface Library
2951 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2952 * YUI licensed under the BSD License:
2953 * http://developer.yahoo.net/yui/license.txt
2954 * <script type="text/javascript">
2958 Roo.lib.Region = function(t, r, b, l) {
2968 Roo.lib.Region.prototype = {
2969 contains : function(region) {
2970 return ( region.left >= this.left &&
2971 region.right <= this.right &&
2972 region.top >= this.top &&
2973 region.bottom <= this.bottom );
2977 getArea : function() {
2978 return ( (this.bottom - this.top) * (this.right - this.left) );
2981 intersect : function(region) {
2982 var t = Math.max(this.top, region.top);
2983 var r = Math.min(this.right, region.right);
2984 var b = Math.min(this.bottom, region.bottom);
2985 var l = Math.max(this.left, region.left);
2987 if (b >= t && r >= l) {
2988 return new Roo.lib.Region(t, r, b, l);
2993 union : function(region) {
2994 var t = Math.min(this.top, region.top);
2995 var r = Math.max(this.right, region.right);
2996 var b = Math.max(this.bottom, region.bottom);
2997 var l = Math.min(this.left, region.left);
2999 return new Roo.lib.Region(t, r, b, l);
3002 adjust : function(t, l, b, r) {
3011 Roo.lib.Region.getRegion = function(el) {
3012 var p = Roo.lib.Dom.getXY(el);
3015 var r = p[0] + el.offsetWidth;
3016 var b = p[1] + el.offsetHeight;
3019 return new Roo.lib.Region(t, r, b, l);
3022 * Portions of this file are based on pieces of Yahoo User Interface Library
3023 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3024 * YUI licensed under the BSD License:
3025 * http://developer.yahoo.net/yui/license.txt
3026 * <script type="text/javascript">
3029 //@@dep Roo.lib.Region
3032 Roo.lib.Point = function(x, y) {
3033 if (x instanceof Array) {
3037 this.x = this.right = this.left = this[0] = x;
3038 this.y = this.top = this.bottom = this[1] = y;
3041 Roo.lib.Point.prototype = new Roo.lib.Region();
3043 * Portions of this file are based on pieces of Yahoo User Interface Library
3044 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3045 * YUI licensed under the BSD License:
3046 * http://developer.yahoo.net/yui/license.txt
3047 * <script type="text/javascript">
3054 scroll : function(el, args, duration, easing, cb, scope) {
3055 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3058 motion : function(el, args, duration, easing, cb, scope) {
3059 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3062 color : function(el, args, duration, easing, cb, scope) {
3063 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3066 run : function(el, args, duration, easing, cb, scope, type) {
3067 type = type || Roo.lib.AnimBase;
3068 if (typeof easing == "string") {
3069 easing = Roo.lib.Easing[easing];
3071 var anim = new type(el, args, duration, easing);
3072 anim.animateX(function() {
3073 Roo.callback(cb, scope);
3079 * Portions of this file are based on pieces of Yahoo User Interface Library
3080 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3081 * YUI licensed under the BSD License:
3082 * http://developer.yahoo.net/yui/license.txt
3083 * <script type="text/javascript">
3091 if (!libFlyweight) {
3092 libFlyweight = new Roo.Element.Flyweight();
3094 libFlyweight.dom = el;
3095 return libFlyweight;
3098 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3102 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3104 this.init(el, attributes, duration, method);
3108 Roo.lib.AnimBase.fly = fly;
3112 Roo.lib.AnimBase.prototype = {
3114 toString: function() {
3115 var el = this.getEl();
3116 var id = el.id || el.tagName;
3117 return ("Anim " + id);
3121 noNegatives: /width|height|opacity|padding/i,
3122 offsetAttribute: /^((width|height)|(top|left))$/,
3123 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3124 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3128 doMethod: function(attr, start, end) {
3129 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3133 setAttribute: function(attr, val, unit) {
3134 if (this.patterns.noNegatives.test(attr)) {
3135 val = (val > 0) ? val : 0;
3138 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3142 getAttribute: function(attr) {
3143 var el = this.getEl();
3144 var val = fly(el).getStyle(attr);
3146 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3147 return parseFloat(val);
3150 var a = this.patterns.offsetAttribute.exec(attr) || [];
3151 var pos = !!( a[3] );
3152 var box = !!( a[2] );
3155 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3156 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3165 getDefaultUnit: function(attr) {
3166 if (this.patterns.defaultUnit.test(attr)) {
3173 animateX : function(callback, scope) {
3174 var f = function() {
3175 this.onComplete.removeListener(f);
3176 if (typeof callback == "function") {
3177 callback.call(scope || this, this);
3180 this.onComplete.addListener(f, this);
3185 setRuntimeAttribute: function(attr) {
3188 var attributes = this.attributes;
3190 this.runtimeAttributes[attr] = {};
3192 var isset = function(prop) {
3193 return (typeof prop !== 'undefined');
3196 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3200 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3203 if (isset(attributes[attr]['to'])) {
3204 end = attributes[attr]['to'];
3205 } else if (isset(attributes[attr]['by'])) {
3206 if (start.constructor == Array) {
3208 for (var i = 0, len = start.length; i < len; ++i) {
3209 end[i] = start[i] + attributes[attr]['by'][i];
3212 end = start + attributes[attr]['by'];
3216 this.runtimeAttributes[attr].start = start;
3217 this.runtimeAttributes[attr].end = end;
3220 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3224 init: function(el, attributes, duration, method) {
3226 var isAnimated = false;
3229 var startTime = null;
3232 var actualFrames = 0;
3235 el = Roo.getDom(el);
3238 this.attributes = attributes || {};
3241 this.duration = duration || 1;
3244 this.method = method || Roo.lib.Easing.easeNone;
3247 this.useSeconds = true;
3250 this.currentFrame = 0;
3253 this.totalFrames = Roo.lib.AnimMgr.fps;
3256 this.getEl = function() {
3261 this.isAnimated = function() {
3266 this.getStartTime = function() {
3270 this.runtimeAttributes = {};
3273 this.animate = function() {
3274 if (this.isAnimated()) {
3278 this.currentFrame = 0;
3280 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3282 Roo.lib.AnimMgr.registerElement(this);
3286 this.stop = function(finish) {
3288 this.currentFrame = this.totalFrames;
3289 this._onTween.fire();
3291 Roo.lib.AnimMgr.stop(this);
3294 var onStart = function() {
3295 this.onStart.fire();
3297 this.runtimeAttributes = {};
3298 for (var attr in this.attributes) {
3299 this.setRuntimeAttribute(attr);
3304 startTime = new Date();
3308 var onTween = function() {
3310 duration: new Date() - this.getStartTime(),
3311 currentFrame: this.currentFrame
3314 data.toString = function() {
3316 'duration: ' + data.duration +
3317 ', currentFrame: ' + data.currentFrame
3321 this.onTween.fire(data);
3323 var runtimeAttributes = this.runtimeAttributes;
3325 for (var attr in runtimeAttributes) {
3326 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3332 var onComplete = function() {
3333 var actual_duration = (new Date() - startTime) / 1000 ;
3336 duration: actual_duration,
3337 frames: actualFrames,
3338 fps: actualFrames / actual_duration
3341 data.toString = function() {
3343 'duration: ' + data.duration +
3344 ', frames: ' + data.frames +
3345 ', fps: ' + data.fps
3351 this.onComplete.fire(data);
3355 this._onStart = new Roo.util.Event(this);
3356 this.onStart = new Roo.util.Event(this);
3357 this.onTween = new Roo.util.Event(this);
3358 this._onTween = new Roo.util.Event(this);
3359 this.onComplete = new Roo.util.Event(this);
3360 this._onComplete = new Roo.util.Event(this);
3361 this._onStart.addListener(onStart);
3362 this._onTween.addListener(onTween);
3363 this._onComplete.addListener(onComplete);
3368 * Portions of this file are based on pieces of Yahoo User Interface Library
3369 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3370 * YUI licensed under the BSD License:
3371 * http://developer.yahoo.net/yui/license.txt
3372 * <script type="text/javascript">
3376 Roo.lib.AnimMgr = new function() {
3393 this.registerElement = function(tween) {
3394 queue[queue.length] = tween;
3396 tween._onStart.fire();
3401 this.unRegister = function(tween, index) {
3402 tween._onComplete.fire();
3403 index = index || getIndex(tween);
3405 queue.splice(index, 1);
3409 if (tweenCount <= 0) {
3415 this.start = function() {
3416 if (thread === null) {
3417 thread = setInterval(this.run, this.delay);
3422 this.stop = function(tween) {
3424 clearInterval(thread);
3426 for (var i = 0, len = queue.length; i < len; ++i) {
3427 if (queue[0].isAnimated()) {
3428 this.unRegister(queue[0], 0);
3437 this.unRegister(tween);
3442 this.run = function() {
3443 for (var i = 0, len = queue.length; i < len; ++i) {
3444 var tween = queue[i];
3445 if (!tween || !tween.isAnimated()) {
3449 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3451 tween.currentFrame += 1;
3453 if (tween.useSeconds) {
3454 correctFrame(tween);
3456 tween._onTween.fire();
3459 Roo.lib.AnimMgr.stop(tween, i);
3464 var getIndex = function(anim) {
3465 for (var i = 0, len = queue.length; i < len; ++i) {
3466 if (queue[i] == anim) {
3474 var correctFrame = function(tween) {
3475 var frames = tween.totalFrames;
3476 var frame = tween.currentFrame;
3477 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3478 var elapsed = (new Date() - tween.getStartTime());
3481 if (elapsed < tween.duration * 1000) {
3482 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3484 tweak = frames - (frame + 1);
3486 if (tweak > 0 && isFinite(tweak)) {
3487 if (tween.currentFrame + tweak >= frames) {
3488 tweak = frames - (frame + 1);
3491 tween.currentFrame += tweak;
3495 * Portions of this file are based on pieces of Yahoo User Interface Library
3496 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3497 * YUI licensed under the BSD License:
3498 * http://developer.yahoo.net/yui/license.txt
3499 * <script type="text/javascript">
3502 Roo.lib.Bezier = new function() {
3504 this.getPosition = function(points, t) {
3505 var n = points.length;
3508 for (var i = 0; i < n; ++i) {
3509 tmp[i] = [points[i][0], points[i][1]];
3512 for (var j = 1; j < n; ++j) {
3513 for (i = 0; i < n - j; ++i) {
3514 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3515 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3519 return [ tmp[0][0], tmp[0][1] ];
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3532 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3533 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3536 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3538 var fly = Roo.lib.AnimBase.fly;
3540 var superclass = Y.ColorAnim.superclass;
3541 var proto = Y.ColorAnim.prototype;
3543 proto.toString = function() {
3544 var el = this.getEl();
3545 var id = el.id || el.tagName;
3546 return ("ColorAnim " + id);
3549 proto.patterns.color = /color$/i;
3550 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3551 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3552 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3553 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3556 proto.parseColor = function(s) {
3557 if (s.length == 3) {
3561 var c = this.patterns.hex.exec(s);
3562 if (c && c.length == 4) {
3563 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3566 c = this.patterns.rgb.exec(s);
3567 if (c && c.length == 4) {
3568 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3571 c = this.patterns.hex3.exec(s);
3572 if (c && c.length == 4) {
3573 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3578 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3579 proto.getAttribute = function(attr) {
3580 var el = this.getEl();
3581 if (this.patterns.color.test(attr)) {
3582 var val = fly(el).getStyle(attr);
3584 if (this.patterns.transparent.test(val)) {
3585 var parent = el.parentNode;
3586 val = fly(parent).getStyle(attr);
3588 while (parent && this.patterns.transparent.test(val)) {
3589 parent = parent.parentNode;
3590 val = fly(parent).getStyle(attr);
3591 if (parent.tagName.toUpperCase() == 'HTML') {
3597 val = superclass.getAttribute.call(this, attr);
3602 proto.getAttribute = function(attr) {
3603 var el = this.getEl();
3604 if (this.patterns.color.test(attr)) {
3605 var val = fly(el).getStyle(attr);
3607 if (this.patterns.transparent.test(val)) {
3608 var parent = el.parentNode;
3609 val = fly(parent).getStyle(attr);
3611 while (parent && this.patterns.transparent.test(val)) {
3612 parent = parent.parentNode;
3613 val = fly(parent).getStyle(attr);
3614 if (parent.tagName.toUpperCase() == 'HTML') {
3620 val = superclass.getAttribute.call(this, attr);
3626 proto.doMethod = function(attr, start, end) {
3629 if (this.patterns.color.test(attr)) {
3631 for (var i = 0, len = start.length; i < len; ++i) {
3632 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3635 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3638 val = superclass.doMethod.call(this, attr, start, end);
3644 proto.setRuntimeAttribute = function(attr) {
3645 superclass.setRuntimeAttribute.call(this, attr);
3647 if (this.patterns.color.test(attr)) {
3648 var attributes = this.attributes;
3649 var start = this.parseColor(this.runtimeAttributes[attr].start);
3650 var end = this.parseColor(this.runtimeAttributes[attr].end);
3652 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3653 end = this.parseColor(attributes[attr].by);
3655 for (var i = 0, len = start.length; i < len; ++i) {
3656 end[i] = start[i] + end[i];
3660 this.runtimeAttributes[attr].start = start;
3661 this.runtimeAttributes[attr].end = end;
3667 * Portions of this file are based on pieces of Yahoo User Interface Library
3668 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669 * YUI licensed under the BSD License:
3670 * http://developer.yahoo.net/yui/license.txt
3671 * <script type="text/javascript">
3677 easeNone: function (t, b, c, d) {
3678 return c * t / d + b;
3682 easeIn: function (t, b, c, d) {
3683 return c * (t /= d) * t + b;
3687 easeOut: function (t, b, c, d) {
3688 return -c * (t /= d) * (t - 2) + b;
3692 easeBoth: function (t, b, c, d) {
3693 if ((t /= d / 2) < 1) {
3694 return c / 2 * t * t + b;
3697 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3701 easeInStrong: function (t, b, c, d) {
3702 return c * (t /= d) * t * t * t + b;
3706 easeOutStrong: function (t, b, c, d) {
3707 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3711 easeBothStrong: function (t, b, c, d) {
3712 if ((t /= d / 2) < 1) {
3713 return c / 2 * t * t * t * t + b;
3716 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3721 elasticIn: function (t, b, c, d, a, p) {
3725 if ((t /= d) == 1) {
3732 if (!a || a < Math.abs(c)) {
3737 var s = p / (2 * Math.PI) * Math.asin(c / a);
3740 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3744 elasticOut: function (t, b, c, d, a, p) {
3748 if ((t /= d) == 1) {
3755 if (!a || a < Math.abs(c)) {
3760 var s = p / (2 * Math.PI) * Math.asin(c / a);
3763 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3767 elasticBoth: function (t, b, c, d, a, p) {
3772 if ((t /= d / 2) == 2) {
3780 if (!a || a < Math.abs(c)) {
3785 var s = p / (2 * Math.PI) * Math.asin(c / a);
3789 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3790 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3792 return a * Math.pow(2, -10 * (t -= 1)) *
3793 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3798 backIn: function (t, b, c, d, s) {
3799 if (typeof s == 'undefined') {
3802 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3806 backOut: function (t, b, c, d, s) {
3807 if (typeof s == 'undefined') {
3810 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3814 backBoth: function (t, b, c, d, s) {
3815 if (typeof s == 'undefined') {
3819 if ((t /= d / 2 ) < 1) {
3820 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3822 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3826 bounceIn: function (t, b, c, d) {
3827 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3831 bounceOut: function (t, b, c, d) {
3832 if ((t /= d) < (1 / 2.75)) {
3833 return c * (7.5625 * t * t) + b;
3834 } else if (t < (2 / 2.75)) {
3835 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3836 } else if (t < (2.5 / 2.75)) {
3837 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3839 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3843 bounceBoth: function (t, b, c, d) {
3845 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3847 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3850 * Portions of this file are based on pieces of Yahoo User Interface Library
3851 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3852 * YUI licensed under the BSD License:
3853 * http://developer.yahoo.net/yui/license.txt
3854 * <script type="text/javascript">
3858 Roo.lib.Motion = function(el, attributes, duration, method) {
3860 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3864 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3868 var superclass = Y.Motion.superclass;
3869 var proto = Y.Motion.prototype;
3871 proto.toString = function() {
3872 var el = this.getEl();
3873 var id = el.id || el.tagName;
3874 return ("Motion " + id);
3877 proto.patterns.points = /^points$/i;
3879 proto.setAttribute = function(attr, val, unit) {
3880 if (this.patterns.points.test(attr)) {
3881 unit = unit || 'px';
3882 superclass.setAttribute.call(this, 'left', val[0], unit);
3883 superclass.setAttribute.call(this, 'top', val[1], unit);
3885 superclass.setAttribute.call(this, attr, val, unit);
3889 proto.getAttribute = function(attr) {
3890 if (this.patterns.points.test(attr)) {
3892 superclass.getAttribute.call(this, 'left'),
3893 superclass.getAttribute.call(this, 'top')
3896 val = superclass.getAttribute.call(this, attr);
3902 proto.doMethod = function(attr, start, end) {
3905 if (this.patterns.points.test(attr)) {
3906 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3907 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3909 val = superclass.doMethod.call(this, attr, start, end);
3914 proto.setRuntimeAttribute = function(attr) {
3915 if (this.patterns.points.test(attr)) {
3916 var el = this.getEl();
3917 var attributes = this.attributes;
3919 var control = attributes['points']['control'] || [];
3923 if (control.length > 0 && !(control[0] instanceof Array)) {
3924 control = [control];
3927 for (i = 0,len = control.length; i < len; ++i) {
3928 tmp[i] = control[i];
3933 Roo.fly(el).position();
3935 if (isset(attributes['points']['from'])) {
3936 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3939 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3942 start = this.getAttribute('points');
3945 if (isset(attributes['points']['to'])) {
3946 end = translateValues.call(this, attributes['points']['to'], start);
3948 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3949 for (i = 0,len = control.length; i < len; ++i) {
3950 control[i] = translateValues.call(this, control[i], start);
3954 } else if (isset(attributes['points']['by'])) {
3955 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3957 for (i = 0,len = control.length; i < len; ++i) {
3958 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3962 this.runtimeAttributes[attr] = [start];
3964 if (control.length > 0) {
3965 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3968 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3971 superclass.setRuntimeAttribute.call(this, attr);
3975 var translateValues = function(val, start) {
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
3982 var isset = function(prop) {
3983 return (typeof prop !== 'undefined');
3987 * Portions of this file are based on pieces of Yahoo User Interface Library
3988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3989 * YUI licensed under the BSD License:
3990 * http://developer.yahoo.net/yui/license.txt
3991 * <script type="text/javascript">
3995 Roo.lib.Scroll = function(el, attributes, duration, method) {
3997 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4001 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4005 var superclass = Y.Scroll.superclass;
4006 var proto = Y.Scroll.prototype;
4008 proto.toString = function() {
4009 var el = this.getEl();
4010 var id = el.id || el.tagName;
4011 return ("Scroll " + id);
4014 proto.doMethod = function(attr, start, end) {
4017 if (attr == 'scroll') {
4019 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4020 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4024 val = superclass.doMethod.call(this, attr, start, end);
4029 proto.getAttribute = function(attr) {
4031 var el = this.getEl();
4033 if (attr == 'scroll') {
4034 val = [ el.scrollLeft, el.scrollTop ];
4036 val = superclass.getAttribute.call(this, attr);
4042 proto.setAttribute = function(attr, val, unit) {
4043 var el = this.getEl();
4045 if (attr == 'scroll') {
4046 el.scrollLeft = val[0];
4047 el.scrollTop = val[1];
4049 superclass.setAttribute.call(this, attr, val, unit);
4055 * Ext JS Library 1.1.1
4056 * Copyright(c) 2006-2007, Ext JS, LLC.
4058 * Originally Released Under LGPL - original licence link has changed is not relivant.
4061 * <script type="text/javascript">
4065 // nasty IE9 hack - what a pile of crap that is..
4067 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4068 Range.prototype.createContextualFragment = function (html) {
4069 var doc = window.document;
4070 var container = doc.createElement("div");
4071 container.innerHTML = html;
4072 var frag = doc.createDocumentFragment(), n;
4073 while ((n = container.firstChild)) {
4074 frag.appendChild(n);
4081 * @class Roo.DomHelper
4082 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4083 * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4086 Roo.DomHelper = function(){
4087 var tempTableEl = null;
4088 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4089 var tableRe = /^table|tbody|tr|td$/i;
4091 // build as innerHTML where available
4093 var createHtml = function(o){
4094 if(typeof o == 'string'){
4103 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4104 if(attr == "style"){
4106 if(typeof s == "function"){
4109 if(typeof s == "string"){
4110 b += ' style="' + s + '"';
4111 }else if(typeof s == "object"){
4114 if(typeof s[key] != "function"){
4115 b += key + ":" + s[key] + ";";
4122 b += ' class="' + o["cls"] + '"';
4123 }else if(attr == "htmlFor"){
4124 b += ' for="' + o["htmlFor"] + '"';
4126 b += " " + attr + '="' + o[attr] + '"';
4130 if(emptyTags.test(o.tag)){
4134 var cn = o.children || o.cn;
4136 //http://bugs.kde.org/show_bug.cgi?id=71506
4137 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4138 for(var i = 0, len = cn.length; i < len; i++) {
4139 b += createHtml(cn[i], b);
4142 b += createHtml(cn, b);
4148 b += "</" + o.tag + ">";
4155 var createDom = function(o, parentNode){
4157 // defininition craeted..
4159 if (o.ns && o.ns != 'html') {
4161 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4162 xmlns[o.ns] = o.xmlns;
4165 if (typeof(xmlns[o.ns]) == 'undefined') {
4166 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4172 if (typeof(o) == 'string') {
4173 return parentNode.appendChild(document.createTextNode(o));
4175 o.tag = o.tag || div;
4176 if (o.ns && Roo.isIE) {
4178 o.tag = o.ns + ':' + o.tag;
4181 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4182 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4185 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4186 attr == "style" || typeof o[attr] == "function") continue;
4188 if(attr=="cls" && Roo.isIE){
4189 el.className = o["cls"];
4191 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4192 else el[attr] = o[attr];
4195 Roo.DomHelper.applyStyles(el, o.style);
4196 var cn = o.children || o.cn;
4198 //http://bugs.kde.org/show_bug.cgi?id=71506
4199 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4200 for(var i = 0, len = cn.length; i < len; i++) {
4201 createDom(cn[i], el);
4208 el.innerHTML = o.html;
4211 parentNode.appendChild(el);
4216 var ieTable = function(depth, s, h, e){
4217 tempTableEl.innerHTML = [s, h, e].join('');
4218 var i = -1, el = tempTableEl;
4225 // kill repeat to save bytes
4229 tbe = '</tbody>'+te,
4235 * Nasty code for IE's broken table implementation
4237 var insertIntoTable = function(tag, where, el, html){
4239 tempTableEl = document.createElement('div');
4244 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4247 if(where == 'beforebegin'){
4251 before = el.nextSibling;
4254 node = ieTable(4, trs, html, tre);
4256 else if(tag == 'tr'){
4257 if(where == 'beforebegin'){
4260 node = ieTable(3, tbs, html, tbe);
4261 } else if(where == 'afterend'){
4262 before = el.nextSibling;
4264 node = ieTable(3, tbs, html, tbe);
4265 } else{ // INTO a TR
4266 if(where == 'afterbegin'){
4267 before = el.firstChild;
4269 node = ieTable(4, trs, html, tre);
4271 } else if(tag == 'tbody'){
4272 if(where == 'beforebegin'){
4275 node = ieTable(2, ts, html, te);
4276 } else if(where == 'afterend'){
4277 before = el.nextSibling;
4279 node = ieTable(2, ts, html, te);
4281 if(where == 'afterbegin'){
4282 before = el.firstChild;
4284 node = ieTable(3, tbs, html, tbe);
4287 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4290 if(where == 'afterbegin'){
4291 before = el.firstChild;
4293 node = ieTable(2, ts, html, te);
4295 el.insertBefore(node, before);
4300 /** True to force the use of DOM instead of html fragments @type Boolean */
4304 * Returns the markup for the passed Element(s) config
4305 * @param {Object} o The Dom object spec (and children)
4308 markup : function(o){
4309 return createHtml(o);
4313 * Applies a style specification to an element
4314 * @param {String/HTMLElement} el The element to apply styles to
4315 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4316 * a function which returns such a specification.
4318 applyStyles : function(el, styles){
4321 if(typeof styles == "string"){
4322 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4324 while ((matches = re.exec(styles)) != null){
4325 el.setStyle(matches[1], matches[2]);
4327 }else if (typeof styles == "object"){
4328 for (var style in styles){
4329 el.setStyle(style, styles[style]);
4331 }else if (typeof styles == "function"){
4332 Roo.DomHelper.applyStyles(el, styles.call());
4338 * Inserts an HTML fragment into the Dom
4339 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4340 * @param {HTMLElement} el The context element
4341 * @param {String} html The HTML fragmenet
4342 * @return {HTMLElement} The new node
4344 insertHtml : function(where, el, html){
4345 where = where.toLowerCase();
4346 if(el.insertAdjacentHTML){
4347 if(tableRe.test(el.tagName)){
4349 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4355 el.insertAdjacentHTML('BeforeBegin', html);
4356 return el.previousSibling;
4358 el.insertAdjacentHTML('AfterBegin', html);
4359 return el.firstChild;
4361 el.insertAdjacentHTML('BeforeEnd', html);
4362 return el.lastChild;
4364 el.insertAdjacentHTML('AfterEnd', html);
4365 return el.nextSibling;
4367 throw 'Illegal insertion point -> "' + where + '"';
4369 var range = el.ownerDocument.createRange();
4373 range.setStartBefore(el);
4374 frag = range.createContextualFragment(html);
4375 el.parentNode.insertBefore(frag, el);
4376 return el.previousSibling;
4379 range.setStartBefore(el.firstChild);
4380 frag = range.createContextualFragment(html);
4381 el.insertBefore(frag, el.firstChild);
4382 return el.firstChild;
4384 el.innerHTML = html;
4385 return el.firstChild;
4389 range.setStartAfter(el.lastChild);
4390 frag = range.createContextualFragment(html);
4391 el.appendChild(frag);
4392 return el.lastChild;
4394 el.innerHTML = html;
4395 return el.lastChild;
4398 range.setStartAfter(el);
4399 frag = range.createContextualFragment(html);
4400 el.parentNode.insertBefore(frag, el.nextSibling);
4401 return el.nextSibling;
4403 throw 'Illegal insertion point -> "' + where + '"';
4407 * Creates new Dom element(s) and inserts them before el
4408 * @param {String/HTMLElement/Element} el The context element
4409 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4410 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4411 * @return {HTMLElement/Roo.Element} The new node
4413 insertBefore : function(el, o, returnElement){
4414 return this.doInsert(el, o, returnElement, "beforeBegin");
4418 * Creates new Dom element(s) and inserts them after el
4419 * @param {String/HTMLElement/Element} el The context element
4420 * @param {Object} o The Dom object spec (and children)
4421 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4422 * @return {HTMLElement/Roo.Element} The new node
4424 insertAfter : function(el, o, returnElement){
4425 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4429 * Creates new Dom element(s) and inserts them as the first child of el
4430 * @param {String/HTMLElement/Element} el The context element
4431 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4432 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4433 * @return {HTMLElement/Roo.Element} The new node
4435 insertFirst : function(el, o, returnElement){
4436 return this.doInsert(el, o, returnElement, "afterBegin");
4440 doInsert : function(el, o, returnElement, pos, sibling){
4441 el = Roo.getDom(el);
4443 if(this.useDom || o.ns){
4444 newNode = createDom(o, null);
4445 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4447 var html = createHtml(o);
4448 newNode = this.insertHtml(pos, el, html);
4450 return returnElement ? Roo.get(newNode, true) : newNode;
4454 * Creates new Dom element(s) and appends them to el
4455 * @param {String/HTMLElement/Element} el The context element
4456 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4457 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4458 * @return {HTMLElement/Roo.Element} The new node
4460 append : function(el, o, returnElement){
4461 el = Roo.getDom(el);
4463 if(this.useDom || o.ns){
4464 newNode = createDom(o, null);
4465 el.appendChild(newNode);
4467 var html = createHtml(o);
4468 newNode = this.insertHtml("beforeEnd", el, html);
4470 return returnElement ? Roo.get(newNode, true) : newNode;
4474 * Creates new Dom element(s) and overwrites the contents of el with them
4475 * @param {String/HTMLElement/Element} el The context element
4476 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4477 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4478 * @return {HTMLElement/Roo.Element} The new node
4480 overwrite : function(el, o, returnElement){
4481 el = Roo.getDom(el);
4484 while (el.childNodes.length) {
4485 el.removeChild(el.firstChild);
4489 el.innerHTML = createHtml(o);
4492 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4496 * Creates a new Roo.DomHelper.Template from the Dom object spec
4497 * @param {Object} o The Dom object spec (and children)
4498 * @return {Roo.DomHelper.Template} The new template
4500 createTemplate : function(o){
4501 var html = createHtml(o);
4502 return new Roo.Template(html);
4508 * Ext JS Library 1.1.1
4509 * Copyright(c) 2006-2007, Ext JS, LLC.
4511 * Originally Released Under LGPL - original licence link has changed is not relivant.
4514 * <script type="text/javascript">
4518 * @class Roo.Template
4519 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4520 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4523 var t = new Roo.Template({
4524 html : '<div name="{id}">' +
4525 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4527 myformat: function (value, allValues) {
4528 return 'XX' + value;
4531 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4533 * For more information see this blog post with examples:
4534 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4535 - Create Elements using DOM, HTML fragments and Templates</a>.
4537 * @param {Object} cfg - Configuration object.
4539 Roo.Template = function(cfg){
4541 if(cfg instanceof Array){
4543 }else if(arguments.length > 1){
4544 cfg = Array.prototype.join.call(arguments, "");
4548 if (typeof(cfg) == 'object') {
4559 Roo.Template.prototype = {
4562 * @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..
4563 * it should be fixed so that template is observable...
4567 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4571 * Returns an HTML fragment of this template with the specified values applied.
4572 * @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'})
4573 * @return {String} The HTML fragment
4575 applyTemplate : function(values){
4579 return this.compiled(values);
4581 var useF = this.disableFormats !== true;
4582 var fm = Roo.util.Format, tpl = this;
4583 var fn = function(m, name, format, args){
4585 if(format.substr(0, 5) == "this."){
4586 return tpl.call(format.substr(5), values[name], values);
4589 // quoted values are required for strings in compiled templates,
4590 // but for non compiled we need to strip them
4591 // quoted reversed for jsmin
4592 var re = /^\s*['"](.*)["']\s*$/;
4593 args = args.split(',');
4594 for(var i = 0, len = args.length; i < len; i++){
4595 args[i] = args[i].replace(re, "$1");
4597 args = [values[name]].concat(args);
4599 args = [values[name]];
4601 return fm[format].apply(fm, args);
4604 return values[name] !== undefined ? values[name] : "";
4607 return this.html.replace(this.re, fn);
4625 this.loading = true;
4626 this.compiled = false;
4628 var cx = new Roo.data.Connection();
4632 success : function (response) {
4634 _t.html = response.responseText;
4638 failure : function(response) {
4639 Roo.log("Template failed to load from " + url);
4646 * Sets the HTML used as the template and optionally compiles it.
4647 * @param {String} html
4648 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4649 * @return {Roo.Template} this
4651 set : function(html, compile){
4653 this.compiled = null;
4661 * True to disable format functions (defaults to false)
4664 disableFormats : false,
4667 * The regular expression used to match template variables
4671 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4674 * Compiles the template into an internal function, eliminating the RegEx overhead.
4675 * @return {Roo.Template} this
4677 compile : function(){
4678 var fm = Roo.util.Format;
4679 var useF = this.disableFormats !== true;
4680 var sep = Roo.isGecko ? "+" : ",";
4681 var fn = function(m, name, format, args){
4683 args = args ? ',' + args : "";
4684 if(format.substr(0, 5) != "this."){
4685 format = "fm." + format + '(';
4687 format = 'this.call("'+ format.substr(5) + '", ';
4691 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4693 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4696 // branched to use + in gecko and [].join() in others
4698 body = "this.compiled = function(values){ return '" +
4699 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4702 body = ["this.compiled = function(values){ return ['"];
4703 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4704 body.push("'].join('');};");
4705 body = body.join('');
4715 // private function used to call members
4716 call : function(fnName, value, allValues){
4717 return this[fnName](value, allValues);
4721 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4722 * @param {String/HTMLElement/Roo.Element} el The context element
4723 * @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'})
4724 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4725 * @return {HTMLElement/Roo.Element} The new node or Element
4727 insertFirst: function(el, values, returnElement){
4728 return this.doInsert('afterBegin', el, values, returnElement);
4732 * Applies the supplied values to the template and inserts the new node(s) before el.
4733 * @param {String/HTMLElement/Roo.Element} el The context element
4734 * @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'})
4735 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4736 * @return {HTMLElement/Roo.Element} The new node or Element
4738 insertBefore: function(el, values, returnElement){
4739 return this.doInsert('beforeBegin', el, values, returnElement);
4743 * Applies the supplied values to the template and inserts the new node(s) after el.
4744 * @param {String/HTMLElement/Roo.Element} el The context element
4745 * @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'})
4746 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4747 * @return {HTMLElement/Roo.Element} The new node or Element
4749 insertAfter : function(el, values, returnElement){
4750 return this.doInsert('afterEnd', el, values, returnElement);
4754 * Applies the supplied values to the template and appends the new node(s) to el.
4755 * @param {String/HTMLElement/Roo.Element} el The context element
4756 * @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'})
4757 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4758 * @return {HTMLElement/Roo.Element} The new node or Element
4760 append : function(el, values, returnElement){
4761 return this.doInsert('beforeEnd', el, values, returnElement);
4764 doInsert : function(where, el, values, returnEl){
4765 el = Roo.getDom(el);
4766 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4767 return returnEl ? Roo.get(newNode, true) : newNode;
4771 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 overwrite : function(el, values, returnElement){
4778 el = Roo.getDom(el);
4779 el.innerHTML = this.applyTemplate(values);
4780 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4784 * Alias for {@link #applyTemplate}
4787 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4790 Roo.DomHelper.Template = Roo.Template;
4793 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4794 * @param {String/HTMLElement} el A DOM element or its id
4795 * @returns {Roo.Template} The created template
4798 Roo.Template.from = function(el){
4799 el = Roo.getDom(el);
4800 return new Roo.Template(el.value || el.innerHTML);
4803 * Ext JS Library 1.1.1
4804 * Copyright(c) 2006-2007, Ext JS, LLC.
4806 * Originally Released Under LGPL - original licence link has changed is not relivant.
4809 * <script type="text/javascript">
4814 * This is code is also distributed under MIT license for use
4815 * with jQuery and prototype JavaScript libraries.
4818 * @class Roo.DomQuery
4819 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).
4821 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>
4824 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.
4826 <h4>Element Selectors:</h4>
4828 <li> <b>*</b> any element</li>
4829 <li> <b>E</b> an element with the tag E</li>
4830 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4831 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4832 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4833 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4835 <h4>Attribute Selectors:</h4>
4836 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4838 <li> <b>E[foo]</b> has an attribute "foo"</li>
4839 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4840 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4841 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4842 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4843 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4844 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4846 <h4>Pseudo Classes:</h4>
4848 <li> <b>E:first-child</b> E is the first child of its parent</li>
4849 <li> <b>E:last-child</b> E is the last child of its parent</li>
4850 <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>
4851 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4852 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4853 <li> <b>E:only-child</b> E is the only child of its parent</li>
4854 <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>
4855 <li> <b>E:first</b> the first E in the resultset</li>
4856 <li> <b>E:last</b> the last E in the resultset</li>
4857 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4858 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4859 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4860 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4861 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4862 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4863 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4864 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4865 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4867 <h4>CSS Value Selectors:</h4>
4869 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4870 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4871 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4872 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4873 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4874 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4878 Roo.DomQuery = function(){
4879 var cache = {}, simpleCache = {}, valueCache = {};
4880 var nonSpace = /\S/;
4881 var trimRe = /^\s+|\s+$/g;
4882 var tplRe = /\{(\d+)\}/g;
4883 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4884 var tagTokenRe = /^(#)?([\w-\*]+)/;
4885 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4887 function child(p, index){
4889 var n = p.firstChild;
4891 if(n.nodeType == 1){
4902 while((n = n.nextSibling) && n.nodeType != 1);
4907 while((n = n.previousSibling) && n.nodeType != 1);
4911 function children(d){
4912 var n = d.firstChild, ni = -1;
4914 var nx = n.nextSibling;
4915 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4925 function byClassName(c, a, v){
4929 var r = [], ri = -1, cn;
4930 for(var i = 0, ci; ci = c[i]; i++){
4931 if((' '+ci.className+' ').indexOf(v) != -1){
4938 function attrValue(n, attr){
4939 if(!n.tagName && typeof n.length != "undefined"){
4948 if(attr == "class" || attr == "className"){
4951 return n.getAttribute(attr) || n[attr];
4955 function getNodes(ns, mode, tagName){
4956 var result = [], ri = -1, cs;
4960 tagName = tagName || "*";
4961 if(typeof ns.getElementsByTagName != "undefined"){
4965 for(var i = 0, ni; ni = ns[i]; i++){
4966 cs = ni.getElementsByTagName(tagName);
4967 for(var j = 0, ci; ci = cs[j]; j++){
4971 }else if(mode == "/" || mode == ">"){
4972 var utag = tagName.toUpperCase();
4973 for(var i = 0, ni, cn; ni = ns[i]; i++){
4974 cn = ni.children || ni.childNodes;
4975 for(var j = 0, cj; cj = cn[j]; j++){
4976 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
4981 }else if(mode == "+"){
4982 var utag = tagName.toUpperCase();
4983 for(var i = 0, n; n = ns[i]; i++){
4984 while((n = n.nextSibling) && n.nodeType != 1);
4985 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
4989 }else if(mode == "~"){
4990 for(var i = 0, n; n = ns[i]; i++){
4991 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5000 function concat(a, b){
5004 for(var i = 0, l = b.length; i < l; i++){
5010 function byTag(cs, tagName){
5011 if(cs.tagName || cs == document){
5017 var r = [], ri = -1;
5018 tagName = tagName.toLowerCase();
5019 for(var i = 0, ci; ci = cs[i]; i++){
5020 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5027 function byId(cs, attr, id){
5028 if(cs.tagName || cs == document){
5034 var r = [], ri = -1;
5035 for(var i = 0,ci; ci = cs[i]; i++){
5036 if(ci && ci.id == id){
5044 function byAttribute(cs, attr, value, op, custom){
5045 var r = [], ri = -1, st = custom=="{";
5046 var f = Roo.DomQuery.operators[op];
5047 for(var i = 0, ci; ci = cs[i]; i++){
5050 a = Roo.DomQuery.getStyle(ci, attr);
5052 else if(attr == "class" || attr == "className"){
5054 }else if(attr == "for"){
5056 }else if(attr == "href"){
5057 a = ci.getAttribute("href", 2);
5059 a = ci.getAttribute(attr);
5061 if((f && f(a, value)) || (!f && a)){
5068 function byPseudo(cs, name, value){
5069 return Roo.DomQuery.pseudos[name](cs, value);
5072 // This is for IE MSXML which does not support expandos.
5073 // IE runs the same speed using setAttribute, however FF slows way down
5074 // and Safari completely fails so they need to continue to use expandos.
5075 var isIE = window.ActiveXObject ? true : false;
5077 // this eval is stop the compressor from
5078 // renaming the variable to something shorter
5080 /** eval:var:batch */
5085 function nodupIEXml(cs){
5087 cs[0].setAttribute("_nodup", d);
5089 for(var i = 1, len = cs.length; i < len; i++){
5091 if(!c.getAttribute("_nodup") != d){
5092 c.setAttribute("_nodup", d);
5096 for(var i = 0, len = cs.length; i < len; i++){
5097 cs[i].removeAttribute("_nodup");
5106 var len = cs.length, c, i, r = cs, cj, ri = -1;
5107 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5110 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5111 return nodupIEXml(cs);
5115 for(i = 1; c = cs[i]; i++){
5120 for(var j = 0; j < i; j++){
5123 for(j = i+1; cj = cs[j]; j++){
5135 function quickDiffIEXml(c1, c2){
5137 for(var i = 0, len = c1.length; i < len; i++){
5138 c1[i].setAttribute("_qdiff", d);
5141 for(var i = 0, len = c2.length; i < len; i++){
5142 if(c2[i].getAttribute("_qdiff") != d){
5143 r[r.length] = c2[i];
5146 for(var i = 0, len = c1.length; i < len; i++){
5147 c1[i].removeAttribute("_qdiff");
5152 function quickDiff(c1, c2){
5153 var len1 = c1.length;
5157 if(isIE && c1[0].selectSingleNode){
5158 return quickDiffIEXml(c1, c2);
5161 for(var i = 0; i < len1; i++){
5165 for(var i = 0, len = c2.length; i < len; i++){
5166 if(c2[i]._qdiff != d){
5167 r[r.length] = c2[i];
5173 function quickId(ns, mode, root, id){
5175 var d = root.ownerDocument || root;
5176 return d.getElementById(id);
5178 ns = getNodes(ns, mode, "*");
5179 return byId(ns, null, id);
5183 getStyle : function(el, name){
5184 return Roo.fly(el).getStyle(name);
5187 * Compiles a selector/xpath query into a reusable function. The returned function
5188 * takes one parameter "root" (optional), which is the context node from where the query should start.
5189 * @param {String} selector The selector/xpath query
5190 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5191 * @return {Function}
5193 compile : function(path, type){
5194 type = type || "select";
5196 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5197 var q = path, mode, lq;
5198 var tk = Roo.DomQuery.matchers;
5199 var tklen = tk.length;
5202 // accept leading mode switch
5203 var lmode = q.match(modeRe);
5204 if(lmode && lmode[1]){
5205 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5206 q = q.replace(lmode[1], "");
5208 // strip leading slashes
5209 while(path.substr(0, 1)=="/"){
5210 path = path.substr(1);
5213 while(q && lq != q){
5215 var tm = q.match(tagTokenRe);
5216 if(type == "select"){
5219 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5221 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5223 q = q.replace(tm[0], "");
5224 }else if(q.substr(0, 1) != '@'){
5225 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5230 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5232 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5234 q = q.replace(tm[0], "");
5237 while(!(mm = q.match(modeRe))){
5238 var matched = false;
5239 for(var j = 0; j < tklen; j++){
5241 var m = q.match(t.re);
5243 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5246 q = q.replace(m[0], "");
5251 // prevent infinite loop on bad selector
5253 throw 'Error parsing selector, parsing failed at "' + q + '"';
5257 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5258 q = q.replace(mm[1], "");
5261 fn[fn.length] = "return nodup(n);\n}";
5264 * list of variables that need from compression as they are used by eval.
5274 * eval:var:byClassName
5276 * eval:var:byAttribute
5277 * eval:var:attrValue
5285 * Selects a group of elements.
5286 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5287 * @param {Node} root (optional) The start of the query (defaults to document).
5290 select : function(path, root, type){
5291 if(!root || root == document){
5294 if(typeof root == "string"){
5295 root = document.getElementById(root);
5297 var paths = path.split(",");
5299 for(var i = 0, len = paths.length; i < len; i++){
5300 var p = paths[i].replace(trimRe, "");
5302 cache[p] = Roo.DomQuery.compile(p);
5304 throw p + " is not a valid selector";
5307 var result = cache[p](root);
5308 if(result && result != document){
5309 results = results.concat(result);
5312 if(paths.length > 1){
5313 return nodup(results);
5319 * Selects a single element.
5320 * @param {String} selector The selector/xpath query
5321 * @param {Node} root (optional) The start of the query (defaults to document).
5324 selectNode : function(path, root){
5325 return Roo.DomQuery.select(path, root)[0];
5329 * Selects the value of a node, optionally replacing null with the defaultValue.
5330 * @param {String} selector The selector/xpath query
5331 * @param {Node} root (optional) The start of the query (defaults to document).
5332 * @param {String} defaultValue
5334 selectValue : function(path, root, defaultValue){
5335 path = path.replace(trimRe, "");
5336 if(!valueCache[path]){
5337 valueCache[path] = Roo.DomQuery.compile(path, "select");
5339 var n = valueCache[path](root);
5340 n = n[0] ? n[0] : n;
5341 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5342 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5346 * Selects the value of a node, parsing integers and floats.
5347 * @param {String} selector The selector/xpath query
5348 * @param {Node} root (optional) The start of the query (defaults to document).
5349 * @param {Number} defaultValue
5352 selectNumber : function(path, root, defaultValue){
5353 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5354 return parseFloat(v);
5358 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5359 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5360 * @param {String} selector The simple selector to test
5363 is : function(el, ss){
5364 if(typeof el == "string"){
5365 el = document.getElementById(el);
5367 var isArray = (el instanceof Array);
5368 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5369 return isArray ? (result.length == el.length) : (result.length > 0);
5373 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5374 * @param {Array} el An array of elements to filter
5375 * @param {String} selector The simple selector to test
5376 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5377 * the selector instead of the ones that match
5380 filter : function(els, ss, nonMatches){
5381 ss = ss.replace(trimRe, "");
5382 if(!simpleCache[ss]){
5383 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5385 var result = simpleCache[ss](els);
5386 return nonMatches ? quickDiff(result, els) : result;
5390 * Collection of matching regular expressions and code snippets.
5394 select: 'n = byClassName(n, null, " {1} ");'
5396 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5397 select: 'n = byPseudo(n, "{1}", "{2}");'
5399 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5400 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5403 select: 'n = byId(n, null, "{1}");'
5406 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5411 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5412 * 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, > <.
5415 "=" : function(a, v){
5418 "!=" : function(a, v){
5421 "^=" : function(a, v){
5422 return a && a.substr(0, v.length) == v;
5424 "$=" : function(a, v){
5425 return a && a.substr(a.length-v.length) == v;
5427 "*=" : function(a, v){
5428 return a && a.indexOf(v) !== -1;
5430 "%=" : function(a, v){
5431 return (a % v) == 0;
5433 "|=" : function(a, v){
5434 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5436 "~=" : function(a, v){
5437 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5442 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5443 * and the argument (if any) supplied in the selector.
5446 "first-child" : function(c){
5447 var r = [], ri = -1, n;
5448 for(var i = 0, ci; ci = n = c[i]; i++){
5449 while((n = n.previousSibling) && n.nodeType != 1);
5457 "last-child" : function(c){
5458 var r = [], ri = -1, n;
5459 for(var i = 0, ci; ci = n = c[i]; i++){
5460 while((n = n.nextSibling) && n.nodeType != 1);
5468 "nth-child" : function(c, a) {
5469 var r = [], ri = -1;
5470 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5471 var f = (m[1] || 1) - 0, l = m[2] - 0;
5472 for(var i = 0, n; n = c[i]; i++){
5473 var pn = n.parentNode;
5474 if (batch != pn._batch) {
5476 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5477 if(cn.nodeType == 1){
5484 if (l == 0 || n.nodeIndex == l){
5487 } else if ((n.nodeIndex + l) % f == 0){
5495 "only-child" : function(c){
5496 var r = [], ri = -1;;
5497 for(var i = 0, ci; ci = c[i]; i++){
5498 if(!prev(ci) && !next(ci)){
5505 "empty" : function(c){
5506 var r = [], ri = -1;
5507 for(var i = 0, ci; ci = c[i]; i++){
5508 var cns = ci.childNodes, j = 0, cn, empty = true;
5511 if(cn.nodeType == 1 || cn.nodeType == 3){
5523 "contains" : function(c, v){
5524 var r = [], ri = -1;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5533 "nodeValue" : function(c, v){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 if(ci.firstChild && ci.firstChild.nodeValue == v){
5543 "checked" : function(c){
5544 var r = [], ri = -1;
5545 for(var i = 0, ci; ci = c[i]; i++){
5546 if(ci.checked == true){
5553 "not" : function(c, ss){
5554 return Roo.DomQuery.filter(c, ss, true);
5557 "odd" : function(c){
5558 return this["nth-child"](c, "odd");
5561 "even" : function(c){
5562 return this["nth-child"](c, "even");
5565 "nth" : function(c, a){
5566 return c[a-1] || [];
5569 "first" : function(c){
5573 "last" : function(c){
5574 return c[c.length-1] || [];
5577 "has" : function(c, ss){
5578 var s = Roo.DomQuery.select;
5579 var r = [], ri = -1;
5580 for(var i = 0, ci; ci = c[i]; i++){
5581 if(s(ss, ci).length > 0){
5588 "next" : function(c, ss){
5589 var is = Roo.DomQuery.is;
5590 var r = [], ri = -1;
5591 for(var i = 0, ci; ci = c[i]; i++){
5600 "prev" : function(c, ss){
5601 var is = Roo.DomQuery.is;
5602 var r = [], ri = -1;
5603 for(var i = 0, ci; ci = c[i]; i++){
5616 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5617 * @param {String} path The selector/xpath query
5618 * @param {Node} root (optional) The start of the query (defaults to document).
5623 Roo.query = Roo.DomQuery.select;
5626 * Ext JS Library 1.1.1
5627 * Copyright(c) 2006-2007, Ext JS, LLC.
5629 * Originally Released Under LGPL - original licence link has changed is not relivant.
5632 * <script type="text/javascript">
5636 * @class Roo.util.Observable
5637 * Base class that provides a common interface for publishing events. Subclasses are expected to
5638 * to have a property "events" with all the events defined.<br>
5641 Employee = function(name){
5648 Roo.extend(Employee, Roo.util.Observable);
5650 * @param {Object} config properties to use (incuding events / listeners)
5653 Roo.util.Observable = function(cfg){
5656 this.addEvents(cfg.events || {});
5658 delete cfg.events; // make sure
5661 Roo.apply(this, cfg);
5664 this.on(this.listeners);
5665 delete this.listeners;
5668 Roo.util.Observable.prototype = {
5670 * @cfg {Object} listeners list of events and functions to call for this object,
5674 'click' : function(e) {
5684 * Fires the specified event with the passed parameters (minus the event name).
5685 * @param {String} eventName
5686 * @param {Object...} args Variable number of parameters are passed to handlers
5687 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5689 fireEvent : function(){
5690 var ce = this.events[arguments[0].toLowerCase()];
5691 if(typeof ce == "object"){
5692 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5699 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5702 * Appends an event handler to this component
5703 * @param {String} eventName The type of event to listen for
5704 * @param {Function} handler The method the event invokes
5705 * @param {Object} scope (optional) The scope in which to execute the handler
5706 * function. The handler function's "this" context.
5707 * @param {Object} options (optional) An object containing handler configuration
5708 * properties. This may contain any of the following properties:<ul>
5709 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5710 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5711 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5712 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5713 * by the specified number of milliseconds. If the event fires again within that time, the original
5714 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5717 * <b>Combining Options</b><br>
5718 * Using the options argument, it is possible to combine different types of listeners:<br>
5720 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5722 el.on('click', this.onClick, this, {
5729 * <b>Attaching multiple handlers in 1 call</b><br>
5730 * The method also allows for a single argument to be passed which is a config object containing properties
5731 * which specify multiple handlers.
5740 fn: this.onMouseOver,
5744 fn: this.onMouseOut,
5750 * Or a shorthand syntax which passes the same scope object to all handlers:
5753 'click': this.onClick,
5754 'mouseover': this.onMouseOver,
5755 'mouseout': this.onMouseOut,
5760 addListener : function(eventName, fn, scope, o){
5761 if(typeof eventName == "object"){
5764 if(this.filterOptRe.test(e)){
5767 if(typeof o[e] == "function"){
5769 this.addListener(e, o[e], o.scope, o);
5771 // individual options
5772 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5777 o = (!o || typeof o == "boolean") ? {} : o;
5778 eventName = eventName.toLowerCase();
5779 var ce = this.events[eventName] || true;
5780 if(typeof ce == "boolean"){
5781 ce = new Roo.util.Event(this, eventName);
5782 this.events[eventName] = ce;
5784 ce.addListener(fn, scope, o);
5788 * Removes a listener
5789 * @param {String} eventName The type of event to listen for
5790 * @param {Function} handler The handler to remove
5791 * @param {Object} scope (optional) The scope (this object) for the handler
5793 removeListener : function(eventName, fn, scope){
5794 var ce = this.events[eventName.toLowerCase()];
5795 if(typeof ce == "object"){
5796 ce.removeListener(fn, scope);
5801 * Removes all listeners for this object
5803 purgeListeners : function(){
5804 for(var evt in this.events){
5805 if(typeof this.events[evt] == "object"){
5806 this.events[evt].clearListeners();
5811 relayEvents : function(o, events){
5812 var createHandler = function(ename){
5814 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5817 for(var i = 0, len = events.length; i < len; i++){
5818 var ename = events[i];
5819 if(!this.events[ename]){ this.events[ename] = true; };
5820 o.on(ename, createHandler(ename), this);
5825 * Used to define events on this Observable
5826 * @param {Object} object The object with the events defined
5828 addEvents : function(o){
5832 Roo.applyIf(this.events, o);
5836 * Checks to see if this object has any listeners for a specified event
5837 * @param {String} eventName The name of the event to check for
5838 * @return {Boolean} True if the event is being listened for, else false
5840 hasListener : function(eventName){
5841 var e = this.events[eventName];
5842 return typeof e == "object" && e.listeners.length > 0;
5846 * Appends an event handler to this element (shorthand for addListener)
5847 * @param {String} eventName The type of event to listen for
5848 * @param {Function} handler The method the event invokes
5849 * @param {Object} scope (optional) The scope in which to execute the handler
5850 * function. The handler function's "this" context.
5851 * @param {Object} options (optional)
5854 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5856 * Removes a listener (shorthand for removeListener)
5857 * @param {String} eventName The type of event to listen for
5858 * @param {Function} handler The handler to remove
5859 * @param {Object} scope (optional) The scope (this object) for the handler
5862 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5865 * Starts capture on the specified Observable. All events will be passed
5866 * to the supplied function with the event name + standard signature of the event
5867 * <b>before</b> the event is fired. If the supplied function returns false,
5868 * the event will not fire.
5869 * @param {Observable} o The Observable to capture
5870 * @param {Function} fn The function to call
5871 * @param {Object} scope (optional) The scope (this object) for the fn
5874 Roo.util.Observable.capture = function(o, fn, scope){
5875 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5879 * Removes <b>all</b> added captures from the Observable.
5880 * @param {Observable} o The Observable to release
5883 Roo.util.Observable.releaseCapture = function(o){
5884 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5889 var createBuffered = function(h, o, scope){
5890 var task = new Roo.util.DelayedTask();
5892 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5896 var createSingle = function(h, e, fn, scope){
5898 e.removeListener(fn, scope);
5899 return h.apply(scope, arguments);
5903 var createDelayed = function(h, o, scope){
5905 var args = Array.prototype.slice.call(arguments, 0);
5906 setTimeout(function(){
5907 h.apply(scope, args);
5912 Roo.util.Event = function(obj, name){
5915 this.listeners = [];
5918 Roo.util.Event.prototype = {
5919 addListener : function(fn, scope, options){
5920 var o = options || {};
5921 scope = scope || this.obj;
5922 if(!this.isListening(fn, scope)){
5923 var l = {fn: fn, scope: scope, options: o};
5926 h = createDelayed(h, o, scope);
5929 h = createSingle(h, this, fn, scope);
5932 h = createBuffered(h, o, scope);
5935 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5936 this.listeners.push(l);
5938 this.listeners = this.listeners.slice(0);
5939 this.listeners.push(l);
5944 findListener : function(fn, scope){
5945 scope = scope || this.obj;
5946 var ls = this.listeners;
5947 for(var i = 0, len = ls.length; i < len; i++){
5949 if(l.fn == fn && l.scope == scope){
5956 isListening : function(fn, scope){
5957 return this.findListener(fn, scope) != -1;
5960 removeListener : function(fn, scope){
5962 if((index = this.findListener(fn, scope)) != -1){
5964 this.listeners.splice(index, 1);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.splice(index, 1);
5974 clearListeners : function(){
5975 this.listeners = [];
5979 var ls = this.listeners, scope, len = ls.length;
5982 var args = Array.prototype.slice.call(arguments, 0);
5983 for(var i = 0; i < len; i++){
5985 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
5986 this.firing = false;
5990 this.firing = false;
5997 * Ext JS Library 1.1.1
5998 * Copyright(c) 2006-2007, Ext JS, LLC.
6000 * Originally Released Under LGPL - original licence link has changed is not relivant.
6003 * <script type="text/javascript">
6007 * @class Roo.EventManager
6008 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6009 * several useful events directly.
6010 * See {@link Roo.EventObject} for more details on normalized event objects.
6013 Roo.EventManager = function(){
6014 var docReadyEvent, docReadyProcId, docReadyState = false;
6015 var resizeEvent, resizeTask, textEvent, textSize;
6016 var E = Roo.lib.Event;
6017 var D = Roo.lib.Dom;
6020 var fireDocReady = function(){
6022 docReadyState = true;
6025 clearInterval(docReadyProcId);
6027 if(Roo.isGecko || Roo.isOpera) {
6028 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6031 var defer = document.getElementById("ie-deferred-loader");
6033 defer.onreadystatechange = null;
6034 defer.parentNode.removeChild(defer);
6038 docReadyEvent.fire();
6039 docReadyEvent.clearListeners();
6044 var initDocReady = function(){
6045 docReadyEvent = new Roo.util.Event();
6046 if(Roo.isGecko || Roo.isOpera) {
6047 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6049 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6050 var defer = document.getElementById("ie-deferred-loader");
6051 defer.onreadystatechange = function(){
6052 if(this.readyState == "complete"){
6056 }else if(Roo.isSafari){
6057 docReadyProcId = setInterval(function(){
6058 var rs = document.readyState;
6059 if(rs == "complete") {
6064 // no matter what, make sure it fires on load
6065 E.on(window, "load", fireDocReady);
6068 var createBuffered = function(h, o){
6069 var task = new Roo.util.DelayedTask(h);
6071 // create new event object impl so new events don't wipe out properties
6072 e = new Roo.EventObjectImpl(e);
6073 task.delay(o.buffer, h, null, [e]);
6077 var createSingle = function(h, el, ename, fn){
6079 Roo.EventManager.removeListener(el, ename, fn);
6084 var createDelayed = function(h, o){
6086 // create new event object impl so new events don't wipe out properties
6087 e = new Roo.EventObjectImpl(e);
6088 setTimeout(function(){
6094 var listen = function(element, ename, opt, fn, scope){
6095 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6096 fn = fn || o.fn; scope = scope || o.scope;
6097 var el = Roo.getDom(element);
6099 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6101 var h = function(e){
6102 e = Roo.EventObject.setEvent(e);
6105 t = e.getTarget(o.delegate, el);
6112 if(o.stopEvent === true){
6115 if(o.preventDefault === true){
6118 if(o.stopPropagation === true){
6119 e.stopPropagation();
6122 if(o.normalized === false){
6126 fn.call(scope || el, e, t, o);
6129 h = createDelayed(h, o);
6132 h = createSingle(h, el, ename, fn);
6135 h = createBuffered(h, o);
6137 fn._handlers = fn._handlers || [];
6138 fn._handlers.push([Roo.id(el), ename, h]);
6141 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6142 el.addEventListener("DOMMouseScroll", h, false);
6143 E.on(window, 'unload', function(){
6144 el.removeEventListener("DOMMouseScroll", h, false);
6147 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6148 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6153 var stopListening = function(el, ename, fn){
6154 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6156 for(var i = 0, len = hds.length; i < len; i++){
6158 if(h[0] == id && h[1] == ename){
6165 E.un(el, ename, hd);
6166 el = Roo.getDom(el);
6167 if(ename == "mousewheel" && el.addEventListener){
6168 el.removeEventListener("DOMMouseScroll", hd, false);
6170 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6171 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6175 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6182 * @scope Roo.EventManager
6187 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6188 * object with a Roo.EventObject
6189 * @param {Function} fn The method the event invokes
6190 * @param {Object} scope An object that becomes the scope of the handler
6191 * @param {boolean} override If true, the obj passed in becomes
6192 * the execution scope of the listener
6193 * @return {Function} The wrapped function
6196 wrap : function(fn, scope, override){
6198 Roo.EventObject.setEvent(e);
6199 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6204 * Appends an event handler to an element (shorthand for addListener)
6205 * @param {String/HTMLElement} element The html element or id to assign the
6206 * @param {String} eventName The type of event to listen for
6207 * @param {Function} handler The method the event invokes
6208 * @param {Object} scope (optional) The scope in which to execute the handler
6209 * function. The handler function's "this" context.
6210 * @param {Object} options (optional) An object containing handler configuration
6211 * properties. This may contain any of the following properties:<ul>
6212 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6213 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6214 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6215 * <li>preventDefault {Boolean} True to prevent the default action</li>
6216 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6217 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6218 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6219 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6220 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6221 * by the specified number of milliseconds. If the event fires again within that time, the original
6222 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6225 * <b>Combining Options</b><br>
6226 * Using the options argument, it is possible to combine different types of listeners:<br>
6228 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6230 el.on('click', this.onClick, this, {
6237 * <b>Attaching multiple handlers in 1 call</b><br>
6238 * The method also allows for a single argument to be passed which is a config object containing properties
6239 * which specify multiple handlers.
6249 fn: this.onMouseOver
6258 * Or a shorthand syntax:<br>
6261 'click' : this.onClick,
6262 'mouseover' : this.onMouseOver,
6263 'mouseout' : this.onMouseOut
6267 addListener : function(element, eventName, fn, scope, options){
6268 if(typeof eventName == "object"){
6274 if(typeof o[e] == "function"){
6276 listen(element, e, o, o[e], o.scope);
6278 // individual options
6279 listen(element, e, o[e]);
6284 return listen(element, eventName, options, fn, scope);
6288 * Removes an event handler
6290 * @param {String/HTMLElement} element The id or html element to remove the
6292 * @param {String} eventName The type of event
6293 * @param {Function} fn
6294 * @return {Boolean} True if a listener was actually removed
6296 removeListener : function(element, eventName, fn){
6297 return stopListening(element, eventName, fn);
6301 * Fires when the document is ready (before onload and before images are loaded). Can be
6302 * accessed shorthanded Roo.onReady().
6303 * @param {Function} fn The method the event invokes
6304 * @param {Object} scope An object that becomes the scope of the handler
6305 * @param {boolean} options
6307 onDocumentReady : function(fn, scope, options){
6308 if(docReadyState){ // if it already fired
6309 docReadyEvent.addListener(fn, scope, options);
6310 docReadyEvent.fire();
6311 docReadyEvent.clearListeners();
6317 docReadyEvent.addListener(fn, scope, options);
6321 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6322 * @param {Function} fn The method the event invokes
6323 * @param {Object} scope An object that becomes the scope of the handler
6324 * @param {boolean} options
6326 onWindowResize : function(fn, scope, options){
6328 resizeEvent = new Roo.util.Event();
6329 resizeTask = new Roo.util.DelayedTask(function(){
6330 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6332 E.on(window, "resize", function(){
6334 resizeTask.delay(50);
6336 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6340 resizeEvent.addListener(fn, scope, options);
6344 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6345 * @param {Function} fn The method the event invokes
6346 * @param {Object} scope An object that becomes the scope of the handler
6347 * @param {boolean} options
6349 onTextResize : function(fn, scope, options){
6351 textEvent = new Roo.util.Event();
6352 var textEl = new Roo.Element(document.createElement('div'));
6353 textEl.dom.className = 'x-text-resize';
6354 textEl.dom.innerHTML = 'X';
6355 textEl.appendTo(document.body);
6356 textSize = textEl.dom.offsetHeight;
6357 setInterval(function(){
6358 if(textEl.dom.offsetHeight != textSize){
6359 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6361 }, this.textResizeInterval);
6363 textEvent.addListener(fn, scope, options);
6367 * Removes the passed window resize listener.
6368 * @param {Function} fn The method the event invokes
6369 * @param {Object} scope The scope of handler
6371 removeResizeListener : function(fn, scope){
6373 resizeEvent.removeListener(fn, scope);
6378 fireResize : function(){
6380 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6384 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6388 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6390 textResizeInterval : 50
6395 * @scopeAlias pub=Roo.EventManager
6399 * Appends an event handler to an element (shorthand for addListener)
6400 * @param {String/HTMLElement} element The html element or id to assign the
6401 * @param {String} eventName The type of event to listen for
6402 * @param {Function} handler The method the event invokes
6403 * @param {Object} scope (optional) The scope in which to execute the handler
6404 * function. The handler function's "this" context.
6405 * @param {Object} options (optional) An object containing handler configuration
6406 * properties. This may contain any of the following properties:<ul>
6407 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6408 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6409 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6410 * <li>preventDefault {Boolean} True to prevent the default action</li>
6411 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6412 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6413 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6414 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6415 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6416 * by the specified number of milliseconds. If the event fires again within that time, the original
6417 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6420 * <b>Combining Options</b><br>
6421 * Using the options argument, it is possible to combine different types of listeners:<br>
6423 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6425 el.on('click', this.onClick, this, {
6432 * <b>Attaching multiple handlers in 1 call</b><br>
6433 * The method also allows for a single argument to be passed which is a config object containing properties
6434 * which specify multiple handlers.
6444 fn: this.onMouseOver
6453 * Or a shorthand syntax:<br>
6456 'click' : this.onClick,
6457 'mouseover' : this.onMouseOver,
6458 'mouseout' : this.onMouseOut
6462 pub.on = pub.addListener;
6463 pub.un = pub.removeListener;
6465 pub.stoppedMouseDownEvent = new Roo.util.Event();
6469 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6470 * @param {Function} fn The method the event invokes
6471 * @param {Object} scope An object that becomes the scope of the handler
6472 * @param {boolean} override If true, the obj passed in becomes
6473 * the execution scope of the listener
6477 Roo.onReady = Roo.EventManager.onDocumentReady;
6479 Roo.onReady(function(){
6480 var bd = Roo.get(document.body);
6485 : Roo.isGecko ? "roo-gecko"
6486 : Roo.isOpera ? "roo-opera"
6487 : Roo.isSafari ? "roo-safari" : ""];
6490 cls.push("roo-mac");
6493 cls.push("roo-linux");
6495 if(Roo.isBorderBox){
6496 cls.push('roo-border-box');
6498 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6499 var p = bd.dom.parentNode;
6501 p.className += ' roo-strict';
6504 bd.addClass(cls.join(' '));
6508 * @class Roo.EventObject
6509 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6510 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6513 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6515 var target = e.getTarget();
6518 var myDiv = Roo.get("myDiv");
6519 myDiv.on("click", handleClick);
6521 Roo.EventManager.on("myDiv", 'click', handleClick);
6522 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6526 Roo.EventObject = function(){
6528 var E = Roo.lib.Event;
6530 // safari keypress events for special keys return bad keycodes
6533 63235 : 39, // right
6536 63276 : 33, // page up
6537 63277 : 34, // page down
6538 63272 : 46, // delete
6543 // normalize button clicks
6544 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6545 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6547 Roo.EventObjectImpl = function(e){
6549 this.setEvent(e.browserEvent || e);
6552 Roo.EventObjectImpl.prototype = {
6554 * Used to fix doc tools.
6555 * @scope Roo.EventObject.prototype
6561 /** The normal browser event */
6562 browserEvent : null,
6563 /** The button pressed in a mouse event */
6565 /** True if the shift key was down during the event */
6567 /** True if the control key was down during the event */
6569 /** True if the alt key was down during the event */
6628 setEvent : function(e){
6629 if(e == this || (e && e.browserEvent)){ // already wrapped
6632 this.browserEvent = e;
6634 // normalize buttons
6635 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6636 if(e.type == 'click' && this.button == -1){
6640 this.shiftKey = e.shiftKey;
6641 // mac metaKey behaves like ctrlKey
6642 this.ctrlKey = e.ctrlKey || e.metaKey;
6643 this.altKey = e.altKey;
6644 // in getKey these will be normalized for the mac
6645 this.keyCode = e.keyCode;
6646 // keyup warnings on firefox.
6647 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6648 // cache the target for the delayed and or buffered events
6649 this.target = E.getTarget(e);
6651 this.xy = E.getXY(e);
6654 this.shiftKey = false;
6655 this.ctrlKey = false;
6656 this.altKey = false;
6666 * Stop the event (preventDefault and stopPropagation)
6668 stopEvent : function(){
6669 if(this.browserEvent){
6670 if(this.browserEvent.type == 'mousedown'){
6671 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6673 E.stopEvent(this.browserEvent);
6678 * Prevents the browsers default handling of the event.
6680 preventDefault : function(){
6681 if(this.browserEvent){
6682 E.preventDefault(this.browserEvent);
6687 isNavKeyPress : function(){
6688 var k = this.keyCode;
6689 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6690 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6693 isSpecialKey : function(){
6694 var k = this.keyCode;
6695 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6696 (k == 16) || (k == 17) ||
6697 (k >= 18 && k <= 20) ||
6698 (k >= 33 && k <= 35) ||
6699 (k >= 36 && k <= 39) ||
6700 (k >= 44 && k <= 45);
6703 * Cancels bubbling of the event.
6705 stopPropagation : function(){
6706 if(this.browserEvent){
6707 if(this.type == 'mousedown'){
6708 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6710 E.stopPropagation(this.browserEvent);
6715 * Gets the key code for the event.
6718 getCharCode : function(){
6719 return this.charCode || this.keyCode;
6723 * Returns a normalized keyCode for the event.
6724 * @return {Number} The key code
6726 getKey : function(){
6727 var k = this.keyCode || this.charCode;
6728 return Roo.isSafari ? (safariKeys[k] || k) : k;
6732 * Gets the x coordinate of the event.
6735 getPageX : function(){
6740 * Gets the y coordinate of the event.
6743 getPageY : function(){
6748 * Gets the time of the event.
6751 getTime : function(){
6752 if(this.browserEvent){
6753 return E.getTime(this.browserEvent);
6759 * Gets the page coordinates of the event.
6760 * @return {Array} The xy values like [x, y]
6767 * Gets the target for the event.
6768 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6769 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6770 search as a number or element (defaults to 10 || document.body)
6771 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6772 * @return {HTMLelement}
6774 getTarget : function(selector, maxDepth, returnEl){
6775 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6778 * Gets the related target.
6779 * @return {HTMLElement}
6781 getRelatedTarget : function(){
6782 if(this.browserEvent){
6783 return E.getRelatedTarget(this.browserEvent);
6789 * Normalizes mouse wheel delta across browsers
6790 * @return {Number} The delta
6792 getWheelDelta : function(){
6793 var e = this.browserEvent;
6795 if(e.wheelDelta){ /* IE/Opera. */
6796 delta = e.wheelDelta/120;
6797 }else if(e.detail){ /* Mozilla case. */
6798 delta = -e.detail/3;
6804 * Returns true if the control, meta, shift or alt key was pressed during this event.
6807 hasModifier : function(){
6808 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6812 * Returns true if the target of this event equals el or is a child of el
6813 * @param {String/HTMLElement/Element} el
6814 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6817 within : function(el, related){
6818 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6819 return t && Roo.fly(el).contains(t);
6822 getPoint : function(){
6823 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6827 return new Roo.EventObjectImpl();
6832 * Ext JS Library 1.1.1
6833 * Copyright(c) 2006-2007, Ext JS, LLC.
6835 * Originally Released Under LGPL - original licence link has changed is not relivant.
6838 * <script type="text/javascript">
6842 // was in Composite Element!??!?!
6845 var D = Roo.lib.Dom;
6846 var E = Roo.lib.Event;
6847 var A = Roo.lib.Anim;
6849 // local style camelizing for speed
6851 var camelRe = /(-[a-z])/gi;
6852 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6853 var view = document.defaultView;
6856 * @class Roo.Element
6857 * Represents an Element in the DOM.<br><br>
6860 var el = Roo.get("my-div");
6863 var el = getEl("my-div");
6865 // or with a DOM element
6866 var el = Roo.get(myDivElement);
6868 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6869 * each call instead of constructing a new one.<br><br>
6870 * <b>Animations</b><br />
6871 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6872 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6874 Option Default Description
6875 --------- -------- ---------------------------------------------
6876 duration .35 The duration of the animation in seconds
6877 easing easeOut The YUI easing method
6878 callback none A function to execute when the anim completes
6879 scope this The scope (this) of the callback function
6881 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6882 * manipulate the animation. Here's an example:
6884 var el = Roo.get("my-div");
6889 // default animation
6890 el.setWidth(100, true);
6892 // animation with some options set
6899 // using the "anim" property to get the Anim object
6905 el.setWidth(100, opt);
6907 if(opt.anim.isAnimated()){
6911 * <b> Composite (Collections of) Elements</b><br />
6912 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6913 * @constructor Create a new Element directly.
6914 * @param {String/HTMLElement} element
6915 * @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).
6917 Roo.Element = function(element, forceNew){
6918 var dom = typeof element == "string" ?
6919 document.getElementById(element) : element;
6920 if(!dom){ // invalid id/element
6924 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6925 return Roo.Element.cache[id];
6935 * The DOM element ID
6938 this.id = id || Roo.id(dom);
6941 var El = Roo.Element;
6945 * The element's default display mode (defaults to "")
6948 originalDisplay : "",
6952 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6957 * Sets the element's visibility mode. When setVisible() is called it
6958 * will use this to determine whether to set the visibility or the display property.
6959 * @param visMode Element.VISIBILITY or Element.DISPLAY
6960 * @return {Roo.Element} this
6962 setVisibilityMode : function(visMode){
6963 this.visibilityMode = visMode;
6967 * Convenience method for setVisibilityMode(Element.DISPLAY)
6968 * @param {String} display (optional) What to set display to when visible
6969 * @return {Roo.Element} this
6971 enableDisplayMode : function(display){
6972 this.setVisibilityMode(El.DISPLAY);
6973 if(typeof display != "undefined") this.originalDisplay = display;
6978 * 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)
6979 * @param {String} selector The simple selector to test
6980 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6981 search as a number or element (defaults to 10 || document.body)
6982 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6983 * @return {HTMLElement} The matching DOM node (or null if no match was found)
6985 findParent : function(simpleSelector, maxDepth, returnEl){
6986 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
6987 maxDepth = maxDepth || 50;
6988 if(typeof maxDepth != "number"){
6989 stopEl = Roo.getDom(maxDepth);
6992 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
6993 if(dq.is(p, simpleSelector)){
6994 return returnEl ? Roo.get(p) : p;
7004 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7005 * @param {String} selector The simple selector to test
7006 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7007 search as a number or element (defaults to 10 || document.body)
7008 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7009 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7011 findParentNode : function(simpleSelector, maxDepth, returnEl){
7012 var p = Roo.fly(this.dom.parentNode, '_internal');
7013 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7017 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7018 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7019 * @param {String} selector The simple selector to test
7020 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7021 search as a number or element (defaults to 10 || document.body)
7022 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7024 up : function(simpleSelector, maxDepth){
7025 return this.findParentNode(simpleSelector, maxDepth, true);
7031 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7032 * @param {String} selector The simple selector to test
7033 * @return {Boolean} True if this element matches the selector, else false
7035 is : function(simpleSelector){
7036 return Roo.DomQuery.is(this.dom, simpleSelector);
7040 * Perform animation on this element.
7041 * @param {Object} args The YUI animation control args
7042 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7043 * @param {Function} onComplete (optional) Function to call when animation completes
7044 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7045 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7046 * @return {Roo.Element} this
7048 animate : function(args, duration, onComplete, easing, animType){
7049 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7054 * @private Internal animation call
7056 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7057 animType = animType || 'run';
7059 var anim = Roo.lib.Anim[animType](
7061 (opt.duration || defaultDur) || .35,
7062 (opt.easing || defaultEase) || 'easeOut',
7064 Roo.callback(cb, this);
7065 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7073 // private legacy anim prep
7074 preanim : function(a, i){
7075 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7079 * Removes worthless text nodes
7080 * @param {Boolean} forceReclean (optional) By default the element
7081 * keeps track if it has been cleaned already so
7082 * you can call this over and over. However, if you update the element and
7083 * need to force a reclean, you can pass true.
7085 clean : function(forceReclean){
7086 if(this.isCleaned && forceReclean !== true){
7090 var d = this.dom, n = d.firstChild, ni = -1;
7092 var nx = n.nextSibling;
7093 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7100 this.isCleaned = true;
7105 calcOffsetsTo : function(el){
7108 var restorePos = false;
7109 if(el.getStyle('position') == 'static'){
7110 el.position('relative');
7115 while(op && op != d && op.tagName != 'HTML'){
7118 op = op.offsetParent;
7121 el.position('static');
7127 * Scrolls this element into view within the passed container.
7128 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7129 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7130 * @return {Roo.Element} this
7132 scrollIntoView : function(container, hscroll){
7133 var c = Roo.getDom(container) || document.body;
7136 var o = this.calcOffsetsTo(c),
7139 b = t+el.offsetHeight,
7140 r = l+el.offsetWidth;
7142 var ch = c.clientHeight;
7143 var ct = parseInt(c.scrollTop, 10);
7144 var cl = parseInt(c.scrollLeft, 10);
7146 var cr = cl + c.clientWidth;
7154 if(hscroll !== false){
7158 c.scrollLeft = r-c.clientWidth;
7165 scrollChildIntoView : function(child, hscroll){
7166 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7170 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7171 * the new height may not be available immediately.
7172 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7173 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7174 * @param {Function} onComplete (optional) Function to call when animation completes
7175 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7176 * @return {Roo.Element} this
7178 autoHeight : function(animate, duration, onComplete, easing){
7179 var oldHeight = this.getHeight();
7181 this.setHeight(1); // force clipping
7182 setTimeout(function(){
7183 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7185 this.setHeight(height);
7187 if(typeof onComplete == "function"){
7191 this.setHeight(oldHeight); // restore original height
7192 this.setHeight(height, animate, duration, function(){
7194 if(typeof onComplete == "function") onComplete();
7195 }.createDelegate(this), easing);
7197 }.createDelegate(this), 0);
7202 * Returns true if this element is an ancestor of the passed element
7203 * @param {HTMLElement/String} el The element to check
7204 * @return {Boolean} True if this element is an ancestor of el, else false
7206 contains : function(el){
7207 if(!el){return false;}
7208 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7212 * Checks whether the element is currently visible using both visibility and display properties.
7213 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7214 * @return {Boolean} True if the element is currently visible, else false
7216 isVisible : function(deep) {
7217 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7218 if(deep !== true || !vis){
7221 var p = this.dom.parentNode;
7222 while(p && p.tagName.toLowerCase() != "body"){
7223 if(!Roo.fly(p, '_isVisible').isVisible()){
7232 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7233 * @param {String} selector The CSS selector
7234 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7235 * @return {CompositeElement/CompositeElementLite} The composite element
7237 select : function(selector, unique){
7238 return El.select(selector, unique, this.dom);
7242 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7243 * @param {String} selector The CSS selector
7244 * @return {Array} An array of the matched nodes
7246 query : function(selector, unique){
7247 return Roo.DomQuery.select(selector, this.dom);
7251 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7252 * @param {String} selector The CSS selector
7253 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7254 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7256 child : function(selector, returnDom){
7257 var n = Roo.DomQuery.selectNode(selector, this.dom);
7258 return returnDom ? n : Roo.get(n);
7262 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7263 * @param {String} selector The CSS selector
7264 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7265 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7267 down : function(selector, returnDom){
7268 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7269 return returnDom ? n : Roo.get(n);
7273 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7274 * @param {String} group The group the DD object is member of
7275 * @param {Object} config The DD config object
7276 * @param {Object} overrides An object containing methods to override/implement on the DD object
7277 * @return {Roo.dd.DD} The DD object
7279 initDD : function(group, config, overrides){
7280 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7281 return Roo.apply(dd, overrides);
7285 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7286 * @param {String} group The group the DDProxy object is member of
7287 * @param {Object} config The DDProxy config object
7288 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7289 * @return {Roo.dd.DDProxy} The DDProxy object
7291 initDDProxy : function(group, config, overrides){
7292 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7293 return Roo.apply(dd, overrides);
7297 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7298 * @param {String} group The group the DDTarget object is member of
7299 * @param {Object} config The DDTarget config object
7300 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7301 * @return {Roo.dd.DDTarget} The DDTarget object
7303 initDDTarget : function(group, config, overrides){
7304 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7305 return Roo.apply(dd, overrides);
7309 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7310 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7311 * @param {Boolean} visible Whether the element is visible
7312 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7313 * @return {Roo.Element} this
7315 setVisible : function(visible, animate){
7317 if(this.visibilityMode == El.DISPLAY){
7318 this.setDisplayed(visible);
7321 this.dom.style.visibility = visible ? "visible" : "hidden";
7324 // closure for composites
7326 var visMode = this.visibilityMode;
7328 this.setOpacity(.01);
7329 this.setVisible(true);
7331 this.anim({opacity: { to: (visible?1:0) }},
7332 this.preanim(arguments, 1),
7333 null, .35, 'easeIn', function(){
7335 if(visMode == El.DISPLAY){
7336 dom.style.display = "none";
7338 dom.style.visibility = "hidden";
7340 Roo.get(dom).setOpacity(1);
7348 * Returns true if display is not "none"
7351 isDisplayed : function() {
7352 return this.getStyle("display") != "none";
7356 * Toggles the element's visibility or display, depending on visibility mode.
7357 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7358 * @return {Roo.Element} this
7360 toggle : function(animate){
7361 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7366 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7367 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7368 * @return {Roo.Element} this
7370 setDisplayed : function(value) {
7371 if(typeof value == "boolean"){
7372 value = value ? this.originalDisplay : "none";
7374 this.setStyle("display", value);
7379 * Tries to focus the element. Any exceptions are caught and ignored.
7380 * @return {Roo.Element} this
7382 focus : function() {
7390 * Tries to blur the element. Any exceptions are caught and ignored.
7391 * @return {Roo.Element} this
7401 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7402 * @param {String/Array} className The CSS class to add, or an array of classes
7403 * @return {Roo.Element} this
7405 addClass : function(className){
7406 if(className instanceof Array){
7407 for(var i = 0, len = className.length; i < len; i++) {
7408 this.addClass(className[i]);
7411 if(className && !this.hasClass(className)){
7412 this.dom.className = this.dom.className + " " + className;
7419 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7420 * @param {String/Array} className The CSS class to add, or an array of classes
7421 * @return {Roo.Element} this
7423 radioClass : function(className){
7424 var siblings = this.dom.parentNode.childNodes;
7425 for(var i = 0; i < siblings.length; i++) {
7426 var s = siblings[i];
7427 if(s.nodeType == 1){
7428 Roo.get(s).removeClass(className);
7431 this.addClass(className);
7436 * Removes one or more CSS classes from the element.
7437 * @param {String/Array} className The CSS class to remove, or an array of classes
7438 * @return {Roo.Element} this
7440 removeClass : function(className){
7441 if(!className || !this.dom.className){
7444 if(className instanceof Array){
7445 for(var i = 0, len = className.length; i < len; i++) {
7446 this.removeClass(className[i]);
7449 if(this.hasClass(className)){
7450 var re = this.classReCache[className];
7452 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7453 this.classReCache[className] = re;
7455 this.dom.className =
7456 this.dom.className.replace(re, " ");
7466 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7467 * @param {String} className The CSS class to toggle
7468 * @return {Roo.Element} this
7470 toggleClass : function(className){
7471 if(this.hasClass(className)){
7472 this.removeClass(className);
7474 this.addClass(className);
7480 * Checks if the specified CSS class exists on this element's DOM node.
7481 * @param {String} className The CSS class to check for
7482 * @return {Boolean} True if the class exists, else false
7484 hasClass : function(className){
7485 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7489 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7490 * @param {String} oldClassName The CSS class to replace
7491 * @param {String} newClassName The replacement CSS class
7492 * @return {Roo.Element} this
7494 replaceClass : function(oldClassName, newClassName){
7495 this.removeClass(oldClassName);
7496 this.addClass(newClassName);
7501 * Returns an object with properties matching the styles requested.
7502 * For example, el.getStyles('color', 'font-size', 'width') might return
7503 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7504 * @param {String} style1 A style name
7505 * @param {String} style2 A style name
7506 * @param {String} etc.
7507 * @return {Object} The style object
7509 getStyles : function(){
7510 var a = arguments, len = a.length, r = {};
7511 for(var i = 0; i < len; i++){
7512 r[a[i]] = this.getStyle(a[i]);
7518 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7519 * @param {String} property The style property whose value is returned.
7520 * @return {String} The current value of the style property for this element.
7522 getStyle : function(){
7523 return view && view.getComputedStyle ?
7525 var el = this.dom, v, cs, camel;
7526 if(prop == 'float'){
7529 if(el.style && (v = el.style[prop])){
7532 if(cs = view.getComputedStyle(el, "")){
7533 if(!(camel = propCache[prop])){
7534 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7541 var el = this.dom, v, cs, camel;
7542 if(prop == 'opacity'){
7543 if(typeof el.style.filter == 'string'){
7544 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7546 var fv = parseFloat(m[1]);
7548 return fv ? fv / 100 : 0;
7553 }else if(prop == 'float'){
7554 prop = "styleFloat";
7556 if(!(camel = propCache[prop])){
7557 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7559 if(v = el.style[camel]){
7562 if(cs = el.currentStyle){
7570 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7571 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7572 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7573 * @return {Roo.Element} this
7575 setStyle : function(prop, value){
7576 if(typeof prop == "string"){
7578 if (prop == 'float') {
7579 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7588 if(camel == 'opacity') {
7589 this.setOpacity(value);
7591 this.dom.style[camel] = value;
7594 for(var style in prop){
7595 if(typeof prop[style] != "function"){
7596 this.setStyle(style, prop[style]);
7604 * More flexible version of {@link #setStyle} for setting style properties.
7605 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7606 * a function which returns such a specification.
7607 * @return {Roo.Element} this
7609 applyStyles : function(style){
7610 Roo.DomHelper.applyStyles(this.dom, style);
7615 * 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).
7616 * @return {Number} The X position of the element
7619 return D.getX(this.dom);
7623 * 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).
7624 * @return {Number} The Y position of the element
7627 return D.getY(this.dom);
7631 * 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).
7632 * @return {Array} The XY position of the element
7635 return D.getXY(this.dom);
7639 * 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).
7640 * @param {Number} The X position of the element
7641 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7642 * @return {Roo.Element} this
7644 setX : function(x, animate){
7646 D.setX(this.dom, x);
7648 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7654 * 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).
7655 * @param {Number} The Y position of the element
7656 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7657 * @return {Roo.Element} this
7659 setY : function(y, animate){
7661 D.setY(this.dom, y);
7663 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7669 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7670 * @param {String} left The left CSS property value
7671 * @return {Roo.Element} this
7673 setLeft : function(left){
7674 this.setStyle("left", this.addUnits(left));
7679 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7680 * @param {String} top The top CSS property value
7681 * @return {Roo.Element} this
7683 setTop : function(top){
7684 this.setStyle("top", this.addUnits(top));
7689 * Sets the element's CSS right style.
7690 * @param {String} right The right CSS property value
7691 * @return {Roo.Element} this
7693 setRight : function(right){
7694 this.setStyle("right", this.addUnits(right));
7699 * Sets the element's CSS bottom style.
7700 * @param {String} bottom The bottom CSS property value
7701 * @return {Roo.Element} this
7703 setBottom : function(bottom){
7704 this.setStyle("bottom", this.addUnits(bottom));
7709 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7710 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7711 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7712 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7713 * @return {Roo.Element} this
7715 setXY : function(pos, animate){
7717 D.setXY(this.dom, pos);
7719 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7725 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7726 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7727 * @param {Number} x X value for new position (coordinates are page-based)
7728 * @param {Number} y Y value for new position (coordinates are page-based)
7729 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7730 * @return {Roo.Element} this
7732 setLocation : function(x, y, animate){
7733 this.setXY([x, y], this.preanim(arguments, 2));
7738 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7739 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7740 * @param {Number} x X value for new position (coordinates are page-based)
7741 * @param {Number} y Y value for new position (coordinates are page-based)
7742 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7743 * @return {Roo.Element} this
7745 moveTo : function(x, y, animate){
7746 this.setXY([x, y], this.preanim(arguments, 2));
7751 * Returns the region of the given element.
7752 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7753 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7755 getRegion : function(){
7756 return D.getRegion(this.dom);
7760 * Returns the offset height of the element
7761 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7762 * @return {Number} The element's height
7764 getHeight : function(contentHeight){
7765 var h = this.dom.offsetHeight || 0;
7766 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7770 * Returns the offset width of the element
7771 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7772 * @return {Number} The element's width
7774 getWidth : function(contentWidth){
7775 var w = this.dom.offsetWidth || 0;
7776 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7780 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7781 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7782 * if a height has not been set using CSS.
7785 getComputedHeight : function(){
7786 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7788 h = parseInt(this.getStyle('height'), 10) || 0;
7789 if(!this.isBorderBox()){
7790 h += this.getFrameWidth('tb');
7797 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7798 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7799 * if a width has not been set using CSS.
7802 getComputedWidth : function(){
7803 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7805 w = parseInt(this.getStyle('width'), 10) || 0;
7806 if(!this.isBorderBox()){
7807 w += this.getFrameWidth('lr');
7814 * Returns the size of the element.
7815 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7816 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7818 getSize : function(contentSize){
7819 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7823 * Returns the width and height of the viewport.
7824 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7826 getViewSize : function(){
7827 var d = this.dom, doc = document, aw = 0, ah = 0;
7828 if(d == doc || d == doc.body){
7829 return {width : D.getViewWidth(), height: D.getViewHeight()};
7832 width : d.clientWidth,
7833 height: d.clientHeight
7839 * Returns the value of the "value" attribute
7840 * @param {Boolean} asNumber true to parse the value as a number
7841 * @return {String/Number}
7843 getValue : function(asNumber){
7844 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7848 adjustWidth : function(width){
7849 if(typeof width == "number"){
7850 if(this.autoBoxAdjust && !this.isBorderBox()){
7851 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7861 adjustHeight : function(height){
7862 if(typeof height == "number"){
7863 if(this.autoBoxAdjust && !this.isBorderBox()){
7864 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7874 * Set the width of the element
7875 * @param {Number} width The new width
7876 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7877 * @return {Roo.Element} this
7879 setWidth : function(width, animate){
7880 width = this.adjustWidth(width);
7882 this.dom.style.width = this.addUnits(width);
7884 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7890 * Set the height of the element
7891 * @param {Number} height The new height
7892 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7893 * @return {Roo.Element} this
7895 setHeight : function(height, animate){
7896 height = this.adjustHeight(height);
7898 this.dom.style.height = this.addUnits(height);
7900 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7906 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7907 * @param {Number} width The new width
7908 * @param {Number} height The new height
7909 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7910 * @return {Roo.Element} this
7912 setSize : function(width, height, animate){
7913 if(typeof width == "object"){ // in case of object from getSize()
7914 height = width.height; width = width.width;
7916 width = this.adjustWidth(width); height = this.adjustHeight(height);
7918 this.dom.style.width = this.addUnits(width);
7919 this.dom.style.height = this.addUnits(height);
7921 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7927 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7928 * @param {Number} x X value for new position (coordinates are page-based)
7929 * @param {Number} y Y value for new position (coordinates are page-based)
7930 * @param {Number} width The new width
7931 * @param {Number} height The new height
7932 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7933 * @return {Roo.Element} this
7935 setBounds : function(x, y, width, height, animate){
7937 this.setSize(width, height);
7938 this.setLocation(x, y);
7940 width = this.adjustWidth(width); height = this.adjustHeight(height);
7941 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7942 this.preanim(arguments, 4), 'motion');
7948 * 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.
7949 * @param {Roo.lib.Region} region The region to fill
7950 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7951 * @return {Roo.Element} this
7953 setRegion : function(region, animate){
7954 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7959 * Appends an event handler
7961 * @param {String} eventName The type of event to append
7962 * @param {Function} fn The method the event invokes
7963 * @param {Object} scope (optional) The scope (this object) of the fn
7964 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7966 addListener : function(eventName, fn, scope, options){
7968 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
7973 * Removes an event handler from this element
7974 * @param {String} eventName the type of event to remove
7975 * @param {Function} fn the method the event invokes
7976 * @return {Roo.Element} this
7978 removeListener : function(eventName, fn){
7979 Roo.EventManager.removeListener(this.dom, eventName, fn);
7984 * Removes all previous added listeners from this element
7985 * @return {Roo.Element} this
7987 removeAllListeners : function(){
7988 E.purgeElement(this.dom);
7992 relayEvent : function(eventName, observable){
7993 this.on(eventName, function(e){
7994 observable.fireEvent(eventName, e);
7999 * Set the opacity of the element
8000 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8001 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8002 * @return {Roo.Element} this
8004 setOpacity : function(opacity, animate){
8006 var s = this.dom.style;
8009 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8010 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8012 s.opacity = opacity;
8015 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8021 * Gets the left X coordinate
8022 * @param {Boolean} local True to get the local css position instead of page coordinate
8025 getLeft : function(local){
8029 return parseInt(this.getStyle("left"), 10) || 0;
8034 * Gets the right X coordinate of the element (element X position + element width)
8035 * @param {Boolean} local True to get the local css position instead of page coordinate
8038 getRight : function(local){
8040 return this.getX() + this.getWidth();
8042 return (this.getLeft(true) + this.getWidth()) || 0;
8047 * Gets the top Y coordinate
8048 * @param {Boolean} local True to get the local css position instead of page coordinate
8051 getTop : function(local) {
8055 return parseInt(this.getStyle("top"), 10) || 0;
8060 * Gets the bottom Y coordinate of the element (element Y position + element height)
8061 * @param {Boolean} local True to get the local css position instead of page coordinate
8064 getBottom : function(local){
8066 return this.getY() + this.getHeight();
8068 return (this.getTop(true) + this.getHeight()) || 0;
8073 * Initializes positioning on this element. If a desired position is not passed, it will make the
8074 * the element positioned relative IF it is not already positioned.
8075 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8076 * @param {Number} zIndex (optional) The zIndex to apply
8077 * @param {Number} x (optional) Set the page X position
8078 * @param {Number} y (optional) Set the page Y position
8080 position : function(pos, zIndex, x, y){
8082 if(this.getStyle('position') == 'static'){
8083 this.setStyle('position', 'relative');
8086 this.setStyle("position", pos);
8089 this.setStyle("z-index", zIndex);
8091 if(x !== undefined && y !== undefined){
8093 }else if(x !== undefined){
8095 }else if(y !== undefined){
8101 * Clear positioning back to the default when the document was loaded
8102 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8103 * @return {Roo.Element} this
8105 clearPositioning : function(value){
8113 "position" : "static"
8119 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8120 * snapshot before performing an update and then restoring the element.
8123 getPositioning : function(){
8124 var l = this.getStyle("left");
8125 var t = this.getStyle("top");
8127 "position" : this.getStyle("position"),
8129 "right" : l ? "" : this.getStyle("right"),
8131 "bottom" : t ? "" : this.getStyle("bottom"),
8132 "z-index" : this.getStyle("z-index")
8137 * Gets the width of the border(s) for the specified side(s)
8138 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8139 * passing lr would get the border (l)eft width + the border (r)ight width.
8140 * @return {Number} The width of the sides passed added together
8142 getBorderWidth : function(side){
8143 return this.addStyles(side, El.borders);
8147 * Gets the width of the padding(s) for the specified side(s)
8148 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8149 * passing lr would get the padding (l)eft + the padding (r)ight.
8150 * @return {Number} The padding of the sides passed added together
8152 getPadding : function(side){
8153 return this.addStyles(side, El.paddings);
8157 * Set positioning with an object returned by getPositioning().
8158 * @param {Object} posCfg
8159 * @return {Roo.Element} this
8161 setPositioning : function(pc){
8162 this.applyStyles(pc);
8163 if(pc.right == "auto"){
8164 this.dom.style.right = "";
8166 if(pc.bottom == "auto"){
8167 this.dom.style.bottom = "";
8173 fixDisplay : function(){
8174 if(this.getStyle("display") == "none"){
8175 this.setStyle("visibility", "hidden");
8176 this.setStyle("display", this.originalDisplay); // first try reverting to default
8177 if(this.getStyle("display") == "none"){ // if that fails, default to block
8178 this.setStyle("display", "block");
8184 * Quick set left and top adding default units
8185 * @param {String} left The left CSS property value
8186 * @param {String} top The top CSS property value
8187 * @return {Roo.Element} this
8189 setLeftTop : function(left, top){
8190 this.dom.style.left = this.addUnits(left);
8191 this.dom.style.top = this.addUnits(top);
8196 * Move this element relative to its current position.
8197 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8198 * @param {Number} distance How far to move the element in pixels
8199 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8200 * @return {Roo.Element} this
8202 move : function(direction, distance, animate){
8203 var xy = this.getXY();
8204 direction = direction.toLowerCase();
8208 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8212 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8217 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8222 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8229 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8230 * @return {Roo.Element} this
8233 if(!this.isClipped){
8234 this.isClipped = true;
8235 this.originalClip = {
8236 "o": this.getStyle("overflow"),
8237 "x": this.getStyle("overflow-x"),
8238 "y": this.getStyle("overflow-y")
8240 this.setStyle("overflow", "hidden");
8241 this.setStyle("overflow-x", "hidden");
8242 this.setStyle("overflow-y", "hidden");
8248 * Return clipping (overflow) to original clipping before clip() was called
8249 * @return {Roo.Element} this
8251 unclip : function(){
8253 this.isClipped = false;
8254 var o = this.originalClip;
8255 if(o.o){this.setStyle("overflow", o.o);}
8256 if(o.x){this.setStyle("overflow-x", o.x);}
8257 if(o.y){this.setStyle("overflow-y", o.y);}
8264 * Gets the x,y coordinates specified by the anchor position on the element.
8265 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8266 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8267 * {width: (target width), height: (target height)} (defaults to the element's current size)
8268 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8269 * @return {Array} [x, y] An array containing the element's x and y coordinates
8271 getAnchorXY : function(anchor, local, s){
8272 //Passing a different size is useful for pre-calculating anchors,
8273 //especially for anchored animations that change the el size.
8275 var w, h, vp = false;
8278 if(d == document.body || d == document){
8280 w = D.getViewWidth(); h = D.getViewHeight();
8282 w = this.getWidth(); h = this.getHeight();
8285 w = s.width; h = s.height;
8287 var x = 0, y = 0, r = Math.round;
8288 switch((anchor || "tl").toLowerCase()){
8330 var sc = this.getScroll();
8331 return [x + sc.left, y + sc.top];
8333 //Add the element's offset xy
8334 var o = this.getXY();
8335 return [x+o[0], y+o[1]];
8339 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8340 * supported position values.
8341 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8342 * @param {String} position The position to align to.
8343 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8344 * @return {Array} [x, y]
8346 getAlignToXY : function(el, p, o){
8350 throw "Element.alignTo with an element that doesn't exist";
8352 var c = false; //constrain to viewport
8353 var p1 = "", p2 = "";
8360 }else if(p.indexOf("-") == -1){
8363 p = p.toLowerCase();
8364 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8366 throw "Element.alignTo with an invalid alignment " + p;
8368 p1 = m[1]; p2 = m[2]; c = !!m[3];
8370 //Subtract the aligned el's internal xy from the target's offset xy
8371 //plus custom offset to get the aligned el's new offset xy
8372 var a1 = this.getAnchorXY(p1, true);
8373 var a2 = el.getAnchorXY(p2, false);
8374 var x = a2[0] - a1[0] + o[0];
8375 var y = a2[1] - a1[1] + o[1];
8377 //constrain the aligned el to viewport if necessary
8378 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8379 // 5px of margin for ie
8380 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8382 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8383 //perpendicular to the vp border, allow the aligned el to slide on that border,
8384 //otherwise swap the aligned el to the opposite border of the target.
8385 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8386 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8387 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8388 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8391 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8392 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8394 if((x+w) > dw + scrollX){
8395 x = swapX ? r.left-w : dw+scrollX-w;
8398 x = swapX ? r.right : scrollX;
8400 if((y+h) > dh + scrollY){
8401 y = swapY ? r.top-h : dh+scrollY-h;
8404 y = swapY ? r.bottom : scrollY;
8411 getConstrainToXY : function(){
8412 var os = {top:0, left:0, bottom:0, right: 0};
8414 return function(el, local, offsets, proposedXY){
8416 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8418 var vw, vh, vx = 0, vy = 0;
8419 if(el.dom == document.body || el.dom == document){
8420 vw = Roo.lib.Dom.getViewWidth();
8421 vh = Roo.lib.Dom.getViewHeight();
8423 vw = el.dom.clientWidth;
8424 vh = el.dom.clientHeight;
8426 var vxy = el.getXY();
8432 var s = el.getScroll();
8434 vx += offsets.left + s.left;
8435 vy += offsets.top + s.top;
8437 vw -= offsets.right;
8438 vh -= offsets.bottom;
8443 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8444 var x = xy[0], y = xy[1];
8445 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8447 // only move it if it needs it
8450 // first validate right/bottom
8459 // then make sure top/left isn't negative
8468 return moved ? [x, y] : false;
8473 adjustForConstraints : function(xy, parent, offsets){
8474 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8478 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8479 * document it aligns it to the viewport.
8480 * The position parameter is optional, and can be specified in any one of the following formats:
8482 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8483 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8484 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8485 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8486 * <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
8487 * element's anchor point, and the second value is used as the target's anchor point.</li>
8489 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8490 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8491 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8492 * that specified in order to enforce the viewport constraints.
8493 * Following are all of the supported anchor positions:
8496 ----- -----------------------------
8497 tl The top left corner (default)
8498 t The center of the top edge
8499 tr The top right corner
8500 l The center of the left edge
8501 c In the center of the element
8502 r The center of the right edge
8503 bl The bottom left corner
8504 b The center of the bottom edge
8505 br The bottom right corner
8509 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8510 el.alignTo("other-el");
8512 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8513 el.alignTo("other-el", "tr?");
8515 // align the bottom right corner of el with the center left edge of other-el
8516 el.alignTo("other-el", "br-l?");
8518 // align the center of el with the bottom left corner of other-el and
8519 // adjust the x position by -6 pixels (and the y position by 0)
8520 el.alignTo("other-el", "c-bl", [-6, 0]);
8522 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8523 * @param {String} position The position to align to.
8524 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8525 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8526 * @return {Roo.Element} this
8528 alignTo : function(element, position, offsets, animate){
8529 var xy = this.getAlignToXY(element, position, offsets);
8530 this.setXY(xy, this.preanim(arguments, 3));
8535 * Anchors an element to another element and realigns it when the window is resized.
8536 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8537 * @param {String} position The position to align to.
8538 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8539 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8540 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8541 * is a number, it is used as the buffer delay (defaults to 50ms).
8542 * @param {Function} callback The function to call after the animation finishes
8543 * @return {Roo.Element} this
8545 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8546 var action = function(){
8547 this.alignTo(el, alignment, offsets, animate);
8548 Roo.callback(callback, this);
8550 Roo.EventManager.onWindowResize(action, this);
8551 var tm = typeof monitorScroll;
8552 if(tm != 'undefined'){
8553 Roo.EventManager.on(window, 'scroll', action, this,
8554 {buffer: tm == 'number' ? monitorScroll : 50});
8556 action.call(this); // align immediately
8560 * Clears any opacity settings from this element. Required in some cases for IE.
8561 * @return {Roo.Element} this
8563 clearOpacity : function(){
8564 if (window.ActiveXObject) {
8565 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8566 this.dom.style.filter = "";
8569 this.dom.style.opacity = "";
8570 this.dom.style["-moz-opacity"] = "";
8571 this.dom.style["-khtml-opacity"] = "";
8577 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8578 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8579 * @return {Roo.Element} this
8581 hide : function(animate){
8582 this.setVisible(false, this.preanim(arguments, 0));
8587 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8588 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8589 * @return {Roo.Element} this
8591 show : function(animate){
8592 this.setVisible(true, this.preanim(arguments, 0));
8597 * @private Test if size has a unit, otherwise appends the default
8599 addUnits : function(size){
8600 return Roo.Element.addUnits(size, this.defaultUnit);
8604 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8605 * @return {Roo.Element} this
8607 beginMeasure : function(){
8609 if(el.offsetWidth || el.offsetHeight){
8610 return this; // offsets work already
8613 var p = this.dom, b = document.body; // start with this element
8614 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8615 var pe = Roo.get(p);
8616 if(pe.getStyle('display') == 'none'){
8617 changed.push({el: p, visibility: pe.getStyle("visibility")});
8618 p.style.visibility = "hidden";
8619 p.style.display = "block";
8623 this._measureChanged = changed;
8629 * Restores displays to before beginMeasure was called
8630 * @return {Roo.Element} this
8632 endMeasure : function(){
8633 var changed = this._measureChanged;
8635 for(var i = 0, len = changed.length; i < len; i++) {
8637 r.el.style.visibility = r.visibility;
8638 r.el.style.display = "none";
8640 this._measureChanged = null;
8646 * Update the innerHTML of this element, optionally searching for and processing scripts
8647 * @param {String} html The new HTML
8648 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8649 * @param {Function} callback For async script loading you can be noticed when the update completes
8650 * @return {Roo.Element} this
8652 update : function(html, loadScripts, callback){
8653 if(typeof html == "undefined"){
8656 if(loadScripts !== true){
8657 this.dom.innerHTML = html;
8658 if(typeof callback == "function"){
8666 html += '<span id="' + id + '"></span>';
8668 E.onAvailable(id, function(){
8669 var hd = document.getElementsByTagName("head")[0];
8670 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8671 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8672 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8675 while(match = re.exec(html)){
8676 var attrs = match[1];
8677 var srcMatch = attrs ? attrs.match(srcRe) : false;
8678 if(srcMatch && srcMatch[2]){
8679 var s = document.createElement("script");
8680 s.src = srcMatch[2];
8681 var typeMatch = attrs.match(typeRe);
8682 if(typeMatch && typeMatch[2]){
8683 s.type = typeMatch[2];
8686 }else if(match[2] && match[2].length > 0){
8687 if(window.execScript) {
8688 window.execScript(match[2]);
8696 window.eval(match[2]);
8700 var el = document.getElementById(id);
8701 if(el){el.parentNode.removeChild(el);}
8702 if(typeof callback == "function"){
8706 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8711 * Direct access to the UpdateManager update() method (takes the same parameters).
8712 * @param {String/Function} url The url for this request or a function to call to get the url
8713 * @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}
8714 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8715 * @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.
8716 * @return {Roo.Element} this
8719 var um = this.getUpdateManager();
8720 um.update.apply(um, arguments);
8725 * Gets this element's UpdateManager
8726 * @return {Roo.UpdateManager} The UpdateManager
8728 getUpdateManager : function(){
8729 if(!this.updateManager){
8730 this.updateManager = new Roo.UpdateManager(this);
8732 return this.updateManager;
8736 * Disables text selection for this element (normalized across browsers)
8737 * @return {Roo.Element} this
8739 unselectable : function(){
8740 this.dom.unselectable = "on";
8741 this.swallowEvent("selectstart", true);
8742 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8743 this.addClass("x-unselectable");
8748 * Calculates the x, y to center this element on the screen
8749 * @return {Array} The x, y values [x, y]
8751 getCenterXY : function(){
8752 return this.getAlignToXY(document, 'c-c');
8756 * Centers the Element in either the viewport, or another Element.
8757 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8759 center : function(centerIn){
8760 this.alignTo(centerIn || document, 'c-c');
8765 * Tests various css rules/browsers to determine if this element uses a border box
8768 isBorderBox : function(){
8769 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8773 * Return a box {x, y, width, height} that can be used to set another elements
8774 * size/location to match this element.
8775 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8776 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8777 * @return {Object} box An object in the format {x, y, width, height}
8779 getBox : function(contentBox, local){
8784 var left = parseInt(this.getStyle("left"), 10) || 0;
8785 var top = parseInt(this.getStyle("top"), 10) || 0;
8788 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8790 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8792 var l = this.getBorderWidth("l")+this.getPadding("l");
8793 var r = this.getBorderWidth("r")+this.getPadding("r");
8794 var t = this.getBorderWidth("t")+this.getPadding("t");
8795 var b = this.getBorderWidth("b")+this.getPadding("b");
8796 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)};
8798 bx.right = bx.x + bx.width;
8799 bx.bottom = bx.y + bx.height;
8804 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8805 for more information about the sides.
8806 * @param {String} sides
8809 getFrameWidth : function(sides, onlyContentBox){
8810 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8814 * 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.
8815 * @param {Object} box The box to fill {x, y, width, height}
8816 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8817 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8818 * @return {Roo.Element} this
8820 setBox : function(box, adjust, animate){
8821 var w = box.width, h = box.height;
8822 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8823 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8824 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8826 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8831 * Forces the browser to repaint this element
8832 * @return {Roo.Element} this
8834 repaint : function(){
8836 this.addClass("x-repaint");
8837 setTimeout(function(){
8838 Roo.get(dom).removeClass("x-repaint");
8844 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8845 * then it returns the calculated width of the sides (see getPadding)
8846 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8847 * @return {Object/Number}
8849 getMargins : function(side){
8852 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8853 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8854 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8855 right: parseInt(this.getStyle("margin-right"), 10) || 0
8858 return this.addStyles(side, El.margins);
8863 addStyles : function(sides, styles){
8865 for(var i = 0, len = sides.length; i < len; i++){
8866 v = this.getStyle(styles[sides.charAt(i)]);
8868 w = parseInt(v, 10);
8876 * Creates a proxy element of this element
8877 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8878 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8879 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8880 * @return {Roo.Element} The new proxy element
8882 createProxy : function(config, renderTo, matchBox){
8884 renderTo = Roo.getDom(renderTo);
8886 renderTo = document.body;
8888 config = typeof config == "object" ?
8889 config : {tag : "div", cls: config};
8890 var proxy = Roo.DomHelper.append(renderTo, config, true);
8892 proxy.setBox(this.getBox());
8898 * Puts a mask over this element to disable user interaction. Requires core.css.
8899 * This method can only be applied to elements which accept child nodes.
8900 * @param {String} msg (optional) A message to display in the mask
8901 * @param {String} msgCls (optional) A css class to apply to the msg element
8902 * @return {Element} The mask element
8904 mask : function(msg, msgCls)
8906 if(this.getStyle("position") == "static"){
8907 this.setStyle("position", "relative");
8910 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8912 this.addClass("x-masked");
8913 this._mask.setDisplayed(true);
8918 while (dom && dom.style) {
8919 if (!isNaN(parseInt(dom.style.zIndex))) {
8920 z = Math.max(z, parseInt(dom.style.zIndex));
8922 dom = dom.parentNode;
8924 // if we are masking the body - then it hides everything..
8925 if (this.dom == document.body) {
8927 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8928 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8931 if(typeof msg == 'string'){
8933 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8935 var mm = this._maskMsg;
8936 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8937 mm.dom.firstChild.innerHTML = msg;
8938 mm.setDisplayed(true);
8940 mm.setStyle('z-index', z + 102);
8942 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8943 this._mask.setHeight(this.getHeight());
8945 this._mask.setStyle('z-index', z + 100);
8951 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8952 * it is cached for reuse.
8954 unmask : function(removeEl){
8956 if(removeEl === true){
8957 this._mask.remove();
8960 this._maskMsg.remove();
8961 delete this._maskMsg;
8964 this._mask.setDisplayed(false);
8966 this._maskMsg.setDisplayed(false);
8970 this.removeClass("x-masked");
8974 * Returns true if this element is masked
8977 isMasked : function(){
8978 return this._mask && this._mask.isVisible();
8982 * Creates an iframe shim for this element to keep selects and other windowed objects from
8984 * @return {Roo.Element} The new shim element
8986 createShim : function(){
8987 var el = document.createElement('iframe');
8988 el.frameBorder = 'no';
8989 el.className = 'roo-shim';
8990 if(Roo.isIE && Roo.isSecure){
8991 el.src = Roo.SSL_SECURE_URL;
8993 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
8994 shim.autoBoxAdjust = false;
8999 * Removes this element from the DOM and deletes it from the cache
9001 remove : function(){
9002 if(this.dom.parentNode){
9003 this.dom.parentNode.removeChild(this.dom);
9005 delete El.cache[this.dom.id];
9009 * Sets up event handlers to add and remove a css class when the mouse is over this element
9010 * @param {String} className
9011 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9012 * mouseout events for children elements
9013 * @return {Roo.Element} this
9015 addClassOnOver : function(className, preventFlicker){
9016 this.on("mouseover", function(){
9017 Roo.fly(this, '_internal').addClass(className);
9019 var removeFn = function(e){
9020 if(preventFlicker !== true || !e.within(this, true)){
9021 Roo.fly(this, '_internal').removeClass(className);
9024 this.on("mouseout", removeFn, this.dom);
9029 * Sets up event handlers to add and remove a css class when this element has the focus
9030 * @param {String} className
9031 * @return {Roo.Element} this
9033 addClassOnFocus : function(className){
9034 this.on("focus", function(){
9035 Roo.fly(this, '_internal').addClass(className);
9037 this.on("blur", function(){
9038 Roo.fly(this, '_internal').removeClass(className);
9043 * 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)
9044 * @param {String} className
9045 * @return {Roo.Element} this
9047 addClassOnClick : function(className){
9049 this.on("mousedown", function(){
9050 Roo.fly(dom, '_internal').addClass(className);
9051 var d = Roo.get(document);
9052 var fn = function(){
9053 Roo.fly(dom, '_internal').removeClass(className);
9054 d.removeListener("mouseup", fn);
9056 d.on("mouseup", fn);
9062 * Stops the specified event from bubbling and optionally prevents the default action
9063 * @param {String} eventName
9064 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9065 * @return {Roo.Element} this
9067 swallowEvent : function(eventName, preventDefault){
9068 var fn = function(e){
9069 e.stopPropagation();
9074 if(eventName instanceof Array){
9075 for(var i = 0, len = eventName.length; i < len; i++){
9076 this.on(eventName[i], fn);
9080 this.on(eventName, fn);
9087 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9090 * Sizes this element to its parent element's dimensions performing
9091 * neccessary box adjustments.
9092 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9093 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9094 * @return {Roo.Element} this
9096 fitToParent : function(monitorResize, targetParent) {
9097 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9098 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9099 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9102 var p = Roo.get(targetParent || this.dom.parentNode);
9103 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9104 if (monitorResize === true) {
9105 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9106 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9112 * Gets the next sibling, skipping text nodes
9113 * @return {HTMLElement} The next sibling or null
9115 getNextSibling : function(){
9116 var n = this.dom.nextSibling;
9117 while(n && n.nodeType != 1){
9124 * Gets the previous sibling, skipping text nodes
9125 * @return {HTMLElement} The previous sibling or null
9127 getPrevSibling : function(){
9128 var n = this.dom.previousSibling;
9129 while(n && n.nodeType != 1){
9130 n = n.previousSibling;
9137 * Appends the passed element(s) to this element
9138 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9139 * @return {Roo.Element} this
9141 appendChild: function(el){
9148 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9149 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9150 * automatically generated with the specified attributes.
9151 * @param {HTMLElement} insertBefore (optional) a child element of this element
9152 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9153 * @return {Roo.Element} The new child element
9155 createChild: function(config, insertBefore, returnDom){
9156 config = config || {tag:'div'};
9158 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9160 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9164 * Appends this element to the passed element
9165 * @param {String/HTMLElement/Element} el The new parent element
9166 * @return {Roo.Element} this
9168 appendTo: function(el){
9169 el = Roo.getDom(el);
9170 el.appendChild(this.dom);
9175 * Inserts this element before the passed element in the DOM
9176 * @param {String/HTMLElement/Element} el The element to insert before
9177 * @return {Roo.Element} this
9179 insertBefore: function(el){
9180 el = Roo.getDom(el);
9181 el.parentNode.insertBefore(this.dom, el);
9186 * Inserts this element after the passed element in the DOM
9187 * @param {String/HTMLElement/Element} el The element to insert after
9188 * @return {Roo.Element} this
9190 insertAfter: function(el){
9191 el = Roo.getDom(el);
9192 el.parentNode.insertBefore(this.dom, el.nextSibling);
9197 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9198 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9199 * @return {Roo.Element} The new child
9201 insertFirst: function(el, returnDom){
9203 if(typeof el == 'object' && !el.nodeType){ // dh config
9204 return this.createChild(el, this.dom.firstChild, returnDom);
9206 el = Roo.getDom(el);
9207 this.dom.insertBefore(el, this.dom.firstChild);
9208 return !returnDom ? Roo.get(el) : el;
9213 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9214 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9215 * @param {String} where (optional) 'before' or 'after' defaults to before
9216 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9217 * @return {Roo.Element} the inserted Element
9219 insertSibling: function(el, where, returnDom){
9220 where = where ? where.toLowerCase() : 'before';
9222 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9224 if(typeof el == 'object' && !el.nodeType){ // dh config
9225 if(where == 'after' && !this.dom.nextSibling){
9226 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9228 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9232 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9233 where == 'before' ? this.dom : this.dom.nextSibling);
9242 * Creates and wraps this element with another element
9243 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {HTMLElement/Element} The newly created wrapper element
9247 wrap: function(config, returnDom){
9249 config = {tag: "div"};
9251 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9252 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9257 * Replaces the passed element with this element
9258 * @param {String/HTMLElement/Element} el The element to replace
9259 * @return {Roo.Element} this
9261 replace: function(el){
9263 this.insertBefore(el);
9269 * Inserts an html fragment into this element
9270 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9271 * @param {String} html The HTML fragment
9272 * @param {Boolean} returnEl True to return an Roo.Element
9273 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9275 insertHtml : function(where, html, returnEl){
9276 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9277 return returnEl ? Roo.get(el) : el;
9281 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9282 * @param {Object} o The object with the attributes
9283 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9284 * @return {Roo.Element} this
9286 set : function(o, useSet){
9288 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9290 if(attr == "style" || typeof o[attr] == "function") continue;
9292 el.className = o["cls"];
9294 if(useSet) el.setAttribute(attr, o[attr]);
9295 else el[attr] = o[attr];
9299 Roo.DomHelper.applyStyles(el, o.style);
9305 * Convenience method for constructing a KeyMap
9306 * @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:
9307 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9308 * @param {Function} fn The function to call
9309 * @param {Object} scope (optional) The scope of the function
9310 * @return {Roo.KeyMap} The KeyMap created
9312 addKeyListener : function(key, fn, scope){
9314 if(typeof key != "object" || key instanceof Array){
9330 return new Roo.KeyMap(this, config);
9334 * Creates a KeyMap for this element
9335 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9336 * @return {Roo.KeyMap} The KeyMap created
9338 addKeyMap : function(config){
9339 return new Roo.KeyMap(this, config);
9343 * Returns true if this element is scrollable.
9346 isScrollable : function(){
9348 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9352 * 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().
9353 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9354 * @param {Number} value The new scroll value
9355 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9356 * @return {Element} this
9359 scrollTo : function(side, value, animate){
9360 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9362 this.dom[prop] = value;
9364 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9365 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9371 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9372 * within this element's scrollable range.
9373 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9374 * @param {Number} distance How far to scroll the element in pixels
9375 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9376 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9377 * was scrolled as far as it could go.
9379 scroll : function(direction, distance, animate){
9380 if(!this.isScrollable()){
9384 var l = el.scrollLeft, t = el.scrollTop;
9385 var w = el.scrollWidth, h = el.scrollHeight;
9386 var cw = el.clientWidth, ch = el.clientHeight;
9387 direction = direction.toLowerCase();
9388 var scrolled = false;
9389 var a = this.preanim(arguments, 2);
9394 var v = Math.min(l + distance, w-cw);
9395 this.scrollTo("left", v, a);
9402 var v = Math.max(l - distance, 0);
9403 this.scrollTo("left", v, a);
9411 var v = Math.max(t - distance, 0);
9412 this.scrollTo("top", v, a);
9420 var v = Math.min(t + distance, h-ch);
9421 this.scrollTo("top", v, a);
9430 * Translates the passed page coordinates into left/top css values for this element
9431 * @param {Number/Array} x The page x or an array containing [x, y]
9432 * @param {Number} y The page y
9433 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9435 translatePoints : function(x, y){
9436 if(typeof x == 'object' || x instanceof Array){
9439 var p = this.getStyle('position');
9440 var o = this.getXY();
9442 var l = parseInt(this.getStyle('left'), 10);
9443 var t = parseInt(this.getStyle('top'), 10);
9446 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9449 t = (p == "relative") ? 0 : this.dom.offsetTop;
9452 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9456 * Returns the current scroll position of the element.
9457 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9459 getScroll : function(){
9460 var d = this.dom, doc = document;
9461 if(d == doc || d == doc.body){
9462 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9463 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9464 return {left: l, top: t};
9466 return {left: d.scrollLeft, top: d.scrollTop};
9471 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9472 * are convert to standard 6 digit hex color.
9473 * @param {String} attr The css attribute
9474 * @param {String} defaultValue The default value to use when a valid color isn't found
9475 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9478 getColor : function(attr, defaultValue, prefix){
9479 var v = this.getStyle(attr);
9480 if(!v || v == "transparent" || v == "inherit") {
9481 return defaultValue;
9483 var color = typeof prefix == "undefined" ? "#" : prefix;
9484 if(v.substr(0, 4) == "rgb("){
9485 var rvs = v.slice(4, v.length -1).split(",");
9486 for(var i = 0; i < 3; i++){
9487 var h = parseInt(rvs[i]).toString(16);
9494 if(v.substr(0, 1) == "#"){
9496 for(var i = 1; i < 4; i++){
9497 var c = v.charAt(i);
9500 }else if(v.length == 7){
9501 color += v.substr(1);
9505 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9509 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9510 * gradient background, rounded corners and a 4-way shadow.
9511 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9512 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9513 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9514 * @return {Roo.Element} this
9516 boxWrap : function(cls){
9517 cls = cls || 'x-box';
9518 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9519 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9524 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9525 * @param {String} namespace The namespace in which to look for the attribute
9526 * @param {String} name The attribute name
9527 * @return {String} The attribute value
9529 getAttributeNS : Roo.isIE ? function(ns, name){
9531 var type = typeof d[ns+":"+name];
9532 if(type != 'undefined' && type != 'unknown'){
9533 return d[ns+":"+name];
9536 } : function(ns, name){
9538 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9542 var ep = El.prototype;
9545 * Appends an event handler (Shorthand for addListener)
9546 * @param {String} eventName The type of event to append
9547 * @param {Function} fn The method the event invokes
9548 * @param {Object} scope (optional) The scope (this object) of the fn
9549 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9552 ep.on = ep.addListener;
9554 ep.mon = ep.addListener;
9557 * Removes an event handler from this element (shorthand for removeListener)
9558 * @param {String} eventName the type of event to remove
9559 * @param {Function} fn the method the event invokes
9560 * @return {Roo.Element} this
9563 ep.un = ep.removeListener;
9566 * true to automatically adjust width and height settings for box-model issues (default to true)
9568 ep.autoBoxAdjust = true;
9571 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9574 El.addUnits = function(v, defaultUnit){
9575 if(v === "" || v == "auto"){
9578 if(v === undefined){
9581 if(typeof v == "number" || !El.unitPattern.test(v)){
9582 return v + (defaultUnit || 'px');
9587 // special markup used throughout Roo when box wrapping elements
9588 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>';
9590 * Visibility mode constant - Use visibility to hide element
9596 * Visibility mode constant - Use display to hide element
9602 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9603 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9604 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9616 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9617 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9618 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9619 * @return {Element} The Element object
9622 El.get = function(el){
9624 if(!el){ return null; }
9625 if(typeof el == "string"){ // element id
9626 if(!(elm = document.getElementById(el))){
9629 if(ex = El.cache[el]){
9632 ex = El.cache[el] = new El(elm);
9635 }else if(el.tagName){ // dom element
9639 if(ex = El.cache[id]){
9642 ex = El.cache[id] = new El(el);
9645 }else if(el instanceof El){
9647 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9648 // catch case where it hasn't been appended
9649 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9652 }else if(el.isComposite){
9654 }else if(el instanceof Array){
9655 return El.select(el);
9656 }else if(el == document){
9657 // create a bogus element object representing the document object
9659 var f = function(){};
9660 f.prototype = El.prototype;
9662 docEl.dom = document;
9670 El.uncache = function(el){
9671 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9673 delete El.cache[a[i].id || a[i]];
9679 // Garbage collection - uncache elements/purge listeners on orphaned elements
9680 // so we don't hold a reference and cause the browser to retain them
9681 El.garbageCollect = function(){
9682 if(!Roo.enableGarbageCollector){
9683 clearInterval(El.collectorThread);
9686 for(var eid in El.cache){
9687 var el = El.cache[eid], d = el.dom;
9688 // -------------------------------------------------------
9689 // Determining what is garbage:
9690 // -------------------------------------------------------
9692 // dom node is null, definitely garbage
9693 // -------------------------------------------------------
9695 // no parentNode == direct orphan, definitely garbage
9696 // -------------------------------------------------------
9697 // !d.offsetParent && !document.getElementById(eid)
9698 // display none elements have no offsetParent so we will
9699 // also try to look it up by it's id. However, check
9700 // offsetParent first so we don't do unneeded lookups.
9701 // This enables collection of elements that are not orphans
9702 // directly, but somewhere up the line they have an orphan
9704 // -------------------------------------------------------
9705 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9706 delete El.cache[eid];
9707 if(d && Roo.enableListenerCollection){
9713 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9717 El.Flyweight = function(dom){
9720 El.Flyweight.prototype = El.prototype;
9722 El._flyweights = {};
9724 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9725 * the dom node can be overwritten by other code.
9726 * @param {String/HTMLElement} el The dom node or id
9727 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9728 * prevent conflicts (e.g. internally Roo uses "_internal")
9730 * @return {Element} The shared Element object
9732 El.fly = function(el, named){
9733 named = named || '_global';
9734 el = Roo.getDom(el);
9738 if(!El._flyweights[named]){
9739 El._flyweights[named] = new El.Flyweight();
9741 El._flyweights[named].dom = el;
9742 return El._flyweights[named];
9746 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9747 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9748 * Shorthand of {@link Roo.Element#get}
9749 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9750 * @return {Element} The Element object
9756 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9757 * the dom node can be overwritten by other code.
9758 * Shorthand of {@link Roo.Element#fly}
9759 * @param {String/HTMLElement} el The dom node or id
9760 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9761 * prevent conflicts (e.g. internally Roo uses "_internal")
9763 * @return {Element} The shared Element object
9769 // speedy lookup for elements never to box adjust
9770 var noBoxAdjust = Roo.isStrict ? {
9773 input:1, select:1, textarea:1
9775 if(Roo.isIE || Roo.isGecko){
9776 noBoxAdjust['button'] = 1;
9780 Roo.EventManager.on(window, 'unload', function(){
9782 delete El._flyweights;
9790 Roo.Element.selectorFunction = Roo.DomQuery.select;
9793 Roo.Element.select = function(selector, unique, root){
9795 if(typeof selector == "string"){
9796 els = Roo.Element.selectorFunction(selector, root);
9797 }else if(selector.length !== undefined){
9800 throw "Invalid selector";
9802 if(unique === true){
9803 return new Roo.CompositeElement(els);
9805 return new Roo.CompositeElementLite(els);
9809 * Selects elements based on the passed CSS selector to enable working on them as 1.
9810 * @param {String/Array} selector The CSS selector or an array of elements
9811 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9812 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9813 * @return {CompositeElementLite/CompositeElement}
9817 Roo.select = Roo.Element.select;
9834 * Ext JS Library 1.1.1
9835 * Copyright(c) 2006-2007, Ext JS, LLC.
9837 * Originally Released Under LGPL - original licence link has changed is not relivant.
9840 * <script type="text/javascript">
9845 //Notifies Element that fx methods are available
9846 Roo.enableFx = true;
9850 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9851 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9852 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9853 * Element effects to work.</p><br/>
9855 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9856 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9857 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9858 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9859 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9860 * expected results and should be done with care.</p><br/>
9862 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9863 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9866 ----- -----------------------------
9867 tl The top left corner
9868 t The center of the top edge
9869 tr The top right corner
9870 l The center of the left edge
9871 r The center of the right edge
9872 bl The bottom left corner
9873 b The center of the bottom edge
9874 br The bottom right corner
9876 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9877 * below are common options that can be passed to any Fx method.</b>
9878 * @cfg {Function} callback A function called when the effect is finished
9879 * @cfg {Object} scope The scope of the effect function
9880 * @cfg {String} easing A valid Easing value for the effect
9881 * @cfg {String} afterCls A css class to apply after the effect
9882 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9883 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9884 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9885 * effects that end with the element being visually hidden, ignored otherwise)
9886 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9887 * a function which returns such a specification that will be applied to the Element after the effect finishes
9888 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9889 * @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
9890 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9894 * Slides the element into view. An anchor point can be optionally passed to set the point of
9895 * origin for the slide effect. This function automatically handles wrapping the element with
9896 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9899 // default: slide the element in from the top
9902 // custom: slide the element in from the right with a 2-second duration
9903 el.slideIn('r', { duration: 2 });
9905 // common config options shown with default values
9911 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9912 * @param {Object} options (optional) Object literal with any of the Fx config options
9913 * @return {Roo.Element} The Element
9915 slideIn : function(anchor, o){
9916 var el = this.getFxEl();
9919 el.queueFx(o, function(){
9921 anchor = anchor || "t";
9923 // fix display to visibility
9926 // restore values after effect
9927 var r = this.getFxRestore();
9928 var b = this.getBox();
9929 // fixed size for slide
9933 var wrap = this.fxWrap(r.pos, o, "hidden");
9935 var st = this.dom.style;
9936 st.visibility = "visible";
9937 st.position = "absolute";
9939 // clear out temp styles after slide and unwrap
9940 var after = function(){
9941 el.fxUnwrap(wrap, r.pos, o);
9943 st.height = r.height;
9946 // time to calc the positions
9947 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9949 switch(anchor.toLowerCase()){
9951 wrap.setSize(b.width, 0);
9952 st.left = st.bottom = "0";
9956 wrap.setSize(0, b.height);
9957 st.right = st.top = "0";
9961 wrap.setSize(0, b.height);
9963 st.left = st.top = "0";
9964 a = {width: bw, points: pt};
9967 wrap.setSize(b.width, 0);
9968 wrap.setY(b.bottom);
9969 st.left = st.top = "0";
9970 a = {height: bh, points: pt};
9974 st.right = st.bottom = "0";
9975 a = {width: bw, height: bh};
9979 wrap.setY(b.y+b.height);
9980 st.right = st.top = "0";
9981 a = {width: bw, height: bh, points: pt};
9985 wrap.setXY([b.right, b.bottom]);
9986 st.left = st.top = "0";
9987 a = {width: bw, height: bh, points: pt};
9991 wrap.setX(b.x+b.width);
9992 st.left = st.bottom = "0";
9993 a = {width: bw, height: bh, points: pt};
9996 this.dom.style.visibility = "visible";
9999 arguments.callee.anim = wrap.fxanim(a,
10009 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10010 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10011 * 'hidden') but block elements will still take up space in the document. The element must be removed
10012 * from the DOM using the 'remove' config option if desired. This function automatically handles
10013 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10016 // default: slide the element out to the top
10019 // custom: slide the element out to the right with a 2-second duration
10020 el.slideOut('r', { duration: 2 });
10022 // common config options shown with default values
10030 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10031 * @param {Object} options (optional) Object literal with any of the Fx config options
10032 * @return {Roo.Element} The Element
10034 slideOut : function(anchor, o){
10035 var el = this.getFxEl();
10038 el.queueFx(o, function(){
10040 anchor = anchor || "t";
10042 // restore values after effect
10043 var r = this.getFxRestore();
10045 var b = this.getBox();
10046 // fixed size for slide
10050 var wrap = this.fxWrap(r.pos, o, "visible");
10052 var st = this.dom.style;
10053 st.visibility = "visible";
10054 st.position = "absolute";
10058 var after = function(){
10060 el.setDisplayed(false);
10065 el.fxUnwrap(wrap, r.pos, o);
10067 st.width = r.width;
10068 st.height = r.height;
10073 var a, zero = {to: 0};
10074 switch(anchor.toLowerCase()){
10076 st.left = st.bottom = "0";
10077 a = {height: zero};
10080 st.right = st.top = "0";
10084 st.left = st.top = "0";
10085 a = {width: zero, points: {to:[b.right, b.y]}};
10088 st.left = st.top = "0";
10089 a = {height: zero, points: {to:[b.x, b.bottom]}};
10092 st.right = st.bottom = "0";
10093 a = {width: zero, height: zero};
10096 st.right = st.top = "0";
10097 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10100 st.left = st.top = "0";
10101 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10104 st.left = st.bottom = "0";
10105 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10109 arguments.callee.anim = wrap.fxanim(a,
10119 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10120 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10121 * The element must be removed from the DOM using the 'remove' config option if desired.
10127 // common config options shown with default values
10135 * @param {Object} options (optional) Object literal with any of the Fx config options
10136 * @return {Roo.Element} The Element
10138 puff : function(o){
10139 var el = this.getFxEl();
10142 el.queueFx(o, function(){
10143 this.clearOpacity();
10146 // restore values after effect
10147 var r = this.getFxRestore();
10148 var st = this.dom.style;
10150 var after = function(){
10152 el.setDisplayed(false);
10159 el.setPositioning(r.pos);
10160 st.width = r.width;
10161 st.height = r.height;
10166 var width = this.getWidth();
10167 var height = this.getHeight();
10169 arguments.callee.anim = this.fxanim({
10170 width : {to: this.adjustWidth(width * 2)},
10171 height : {to: this.adjustHeight(height * 2)},
10172 points : {by: [-(width * .5), -(height * .5)]},
10174 fontSize: {to:200, unit: "%"}
10185 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10186 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10187 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10193 // all config options shown with default values
10201 * @param {Object} options (optional) Object literal with any of the Fx config options
10202 * @return {Roo.Element} The Element
10204 switchOff : function(o){
10205 var el = this.getFxEl();
10208 el.queueFx(o, function(){
10209 this.clearOpacity();
10212 // restore values after effect
10213 var r = this.getFxRestore();
10214 var st = this.dom.style;
10216 var after = function(){
10218 el.setDisplayed(false);
10224 el.setPositioning(r.pos);
10225 st.width = r.width;
10226 st.height = r.height;
10231 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10232 this.clearOpacity();
10236 points:{by:[0, this.getHeight() * .5]}
10237 }, o, 'motion', 0.3, 'easeIn', after);
10238 }).defer(100, this);
10245 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10246 * changed using the "attr" config option) and then fading back to the original color. If no original
10247 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10250 // default: highlight background to yellow
10253 // custom: highlight foreground text to blue for 2 seconds
10254 el.highlight("0000ff", { attr: 'color', duration: 2 });
10256 // common config options shown with default values
10257 el.highlight("ffff9c", {
10258 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10259 endColor: (current color) or "ffffff",
10264 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10265 * @param {Object} options (optional) Object literal with any of the Fx config options
10266 * @return {Roo.Element} The Element
10268 highlight : function(color, o){
10269 var el = this.getFxEl();
10272 el.queueFx(o, function(){
10273 color = color || "ffff9c";
10274 attr = o.attr || "backgroundColor";
10276 this.clearOpacity();
10279 var origColor = this.getColor(attr);
10280 var restoreColor = this.dom.style[attr];
10281 endColor = (o.endColor || origColor) || "ffffff";
10283 var after = function(){
10284 el.dom.style[attr] = restoreColor;
10289 a[attr] = {from: color, to: endColor};
10290 arguments.callee.anim = this.fxanim(a,
10300 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10303 // default: a single light blue ripple
10306 // custom: 3 red ripples lasting 3 seconds total
10307 el.frame("ff0000", 3, { duration: 3 });
10309 // common config options shown with default values
10310 el.frame("C3DAF9", 1, {
10311 duration: 1 //duration of entire animation (not each individual ripple)
10312 // Note: Easing is not configurable and will be ignored if included
10315 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10316 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10317 * @param {Object} options (optional) Object literal with any of the Fx config options
10318 * @return {Roo.Element} The Element
10320 frame : function(color, count, o){
10321 var el = this.getFxEl();
10324 el.queueFx(o, function(){
10325 color = color || "#C3DAF9";
10326 if(color.length == 6){
10327 color = "#" + color;
10329 count = count || 1;
10330 duration = o.duration || 1;
10333 var b = this.getBox();
10334 var animFn = function(){
10335 var proxy = this.createProxy({
10338 visbility:"hidden",
10339 position:"absolute",
10340 "z-index":"35000", // yee haw
10341 border:"0px solid " + color
10344 var scale = Roo.isBorderBox ? 2 : 1;
10346 top:{from:b.y, to:b.y - 20},
10347 left:{from:b.x, to:b.x - 20},
10348 borderWidth:{from:0, to:10},
10349 opacity:{from:1, to:0},
10350 height:{from:b.height, to:(b.height + (20*scale))},
10351 width:{from:b.width, to:(b.width + (20*scale))}
10352 }, duration, function(){
10356 animFn.defer((duration/2)*1000, this);
10367 * Creates a pause before any subsequent queued effects begin. If there are
10368 * no effects queued after the pause it will have no effect.
10373 * @param {Number} seconds The length of time to pause (in seconds)
10374 * @return {Roo.Element} The Element
10376 pause : function(seconds){
10377 var el = this.getFxEl();
10380 el.queueFx(o, function(){
10381 setTimeout(function(){
10383 }, seconds * 1000);
10389 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10390 * using the "endOpacity" config option.
10393 // default: fade in from opacity 0 to 100%
10396 // custom: fade in from opacity 0 to 75% over 2 seconds
10397 el.fadeIn({ endOpacity: .75, duration: 2});
10399 // common config options shown with default values
10401 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10406 * @param {Object} options (optional) Object literal with any of the Fx config options
10407 * @return {Roo.Element} The Element
10409 fadeIn : function(o){
10410 var el = this.getFxEl();
10412 el.queueFx(o, function(){
10413 this.setOpacity(0);
10415 this.dom.style.visibility = 'visible';
10416 var to = o.endOpacity || 1;
10417 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10418 o, null, .5, "easeOut", function(){
10420 this.clearOpacity();
10429 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10430 * using the "endOpacity" config option.
10433 // default: fade out from the element's current opacity to 0
10436 // custom: fade out from the element's current opacity to 25% over 2 seconds
10437 el.fadeOut({ endOpacity: .25, duration: 2});
10439 // common config options shown with default values
10441 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10448 * @param {Object} options (optional) Object literal with any of the Fx config options
10449 * @return {Roo.Element} The Element
10451 fadeOut : function(o){
10452 var el = this.getFxEl();
10454 el.queueFx(o, function(){
10455 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10456 o, null, .5, "easeOut", function(){
10457 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10458 this.dom.style.display = "none";
10460 this.dom.style.visibility = "hidden";
10462 this.clearOpacity();
10470 * Animates the transition of an element's dimensions from a starting height/width
10471 * to an ending height/width.
10474 // change height and width to 100x100 pixels
10475 el.scale(100, 100);
10477 // common config options shown with default values. The height and width will default to
10478 // the element's existing values if passed as null.
10481 [element's height], {
10486 * @param {Number} width The new width (pass undefined to keep the original width)
10487 * @param {Number} height The new height (pass undefined to keep the original height)
10488 * @param {Object} options (optional) Object literal with any of the Fx config options
10489 * @return {Roo.Element} The Element
10491 scale : function(w, h, o){
10492 this.shift(Roo.apply({}, o, {
10500 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10501 * Any of these properties not specified in the config object will not be changed. This effect
10502 * requires that at least one new dimension, position or opacity setting must be passed in on
10503 * the config object in order for the function to have any effect.
10506 // slide the element horizontally to x position 200 while changing the height and opacity
10507 el.shift({ x: 200, height: 50, opacity: .8 });
10509 // common config options shown with default values.
10511 width: [element's width],
10512 height: [element's height],
10513 x: [element's x position],
10514 y: [element's y position],
10515 opacity: [element's opacity],
10520 * @param {Object} options Object literal with any of the Fx config options
10521 * @return {Roo.Element} The Element
10523 shift : function(o){
10524 var el = this.getFxEl();
10526 el.queueFx(o, function(){
10527 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10528 if(w !== undefined){
10529 a.width = {to: this.adjustWidth(w)};
10531 if(h !== undefined){
10532 a.height = {to: this.adjustHeight(h)};
10534 if(x !== undefined || y !== undefined){
10536 x !== undefined ? x : this.getX(),
10537 y !== undefined ? y : this.getY()
10540 if(op !== undefined){
10541 a.opacity = {to: op};
10543 if(o.xy !== undefined){
10544 a.points = {to: o.xy};
10546 arguments.callee.anim = this.fxanim(a,
10547 o, 'motion', .35, "easeOut", function(){
10555 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10556 * ending point of the effect.
10559 // default: slide the element downward while fading out
10562 // custom: slide the element out to the right with a 2-second duration
10563 el.ghost('r', { duration: 2 });
10565 // common config options shown with default values
10573 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10574 * @param {Object} options (optional) Object literal with any of the Fx config options
10575 * @return {Roo.Element} The Element
10577 ghost : function(anchor, o){
10578 var el = this.getFxEl();
10581 el.queueFx(o, function(){
10582 anchor = anchor || "b";
10584 // restore values after effect
10585 var r = this.getFxRestore();
10586 var w = this.getWidth(),
10587 h = this.getHeight();
10589 var st = this.dom.style;
10591 var after = function(){
10593 el.setDisplayed(false);
10599 el.setPositioning(r.pos);
10600 st.width = r.width;
10601 st.height = r.height;
10606 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10607 switch(anchor.toLowerCase()){
10634 arguments.callee.anim = this.fxanim(a,
10644 * Ensures that all effects queued after syncFx is called on the element are
10645 * run concurrently. This is the opposite of {@link #sequenceFx}.
10646 * @return {Roo.Element} The Element
10648 syncFx : function(){
10649 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10658 * Ensures that all effects queued after sequenceFx is called on the element are
10659 * run in sequence. This is the opposite of {@link #syncFx}.
10660 * @return {Roo.Element} The Element
10662 sequenceFx : function(){
10663 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10665 concurrent : false,
10672 nextFx : function(){
10673 var ef = this.fxQueue[0];
10680 * Returns true if the element has any effects actively running or queued, else returns false.
10681 * @return {Boolean} True if element has active effects, else false
10683 hasActiveFx : function(){
10684 return this.fxQueue && this.fxQueue[0];
10688 * Stops any running effects and clears the element's internal effects queue if it contains
10689 * any additional effects that haven't started yet.
10690 * @return {Roo.Element} The Element
10692 stopFx : function(){
10693 if(this.hasActiveFx()){
10694 var cur = this.fxQueue[0];
10695 if(cur && cur.anim && cur.anim.isAnimated()){
10696 this.fxQueue = [cur]; // clear out others
10697 cur.anim.stop(true);
10704 beforeFx : function(o){
10705 if(this.hasActiveFx() && !o.concurrent){
10716 * Returns true if the element is currently blocking so that no other effect can be queued
10717 * until this effect is finished, else returns false if blocking is not set. This is commonly
10718 * used to ensure that an effect initiated by a user action runs to completion prior to the
10719 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10720 * @return {Boolean} True if blocking, else false
10722 hasFxBlock : function(){
10723 var q = this.fxQueue;
10724 return q && q[0] && q[0].block;
10728 queueFx : function(o, fn){
10732 if(!this.hasFxBlock()){
10733 Roo.applyIf(o, this.fxDefaults);
10735 var run = this.beforeFx(o);
10736 fn.block = o.block;
10737 this.fxQueue.push(fn);
10749 fxWrap : function(pos, o, vis){
10751 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10754 wrapXY = this.getXY();
10756 var div = document.createElement("div");
10757 div.style.visibility = vis;
10758 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10759 wrap.setPositioning(pos);
10760 if(wrap.getStyle("position") == "static"){
10761 wrap.position("relative");
10763 this.clearPositioning('auto');
10765 wrap.dom.appendChild(this.dom);
10767 wrap.setXY(wrapXY);
10774 fxUnwrap : function(wrap, pos, o){
10775 this.clearPositioning();
10776 this.setPositioning(pos);
10778 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10784 getFxRestore : function(){
10785 var st = this.dom.style;
10786 return {pos: this.getPositioning(), width: st.width, height : st.height};
10790 afterFx : function(o){
10792 this.applyStyles(o.afterStyle);
10795 this.addClass(o.afterCls);
10797 if(o.remove === true){
10800 Roo.callback(o.callback, o.scope, [this]);
10802 this.fxQueue.shift();
10808 getFxEl : function(){ // support for composite element fx
10809 return Roo.get(this.dom);
10813 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10814 animType = animType || 'run';
10816 var anim = Roo.lib.Anim[animType](
10818 (opt.duration || defaultDur) || .35,
10819 (opt.easing || defaultEase) || 'easeOut',
10821 Roo.callback(cb, this);
10830 // backwords compat
10831 Roo.Fx.resize = Roo.Fx.scale;
10833 //When included, Roo.Fx is automatically applied to Element so that all basic
10834 //effects are available directly via the Element API
10835 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10837 * Ext JS Library 1.1.1
10838 * Copyright(c) 2006-2007, Ext JS, LLC.
10840 * Originally Released Under LGPL - original licence link has changed is not relivant.
10843 * <script type="text/javascript">
10848 * @class Roo.CompositeElement
10849 * Standard composite class. Creates a Roo.Element for every element in the collection.
10851 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10852 * actions will be performed on all the elements in this collection.</b>
10854 * All methods return <i>this</i> and can be chained.
10856 var els = Roo.select("#some-el div.some-class", true);
10857 // or select directly from an existing element
10858 var el = Roo.get('some-el');
10859 el.select('div.some-class', true);
10861 els.setWidth(100); // all elements become 100 width
10862 els.hide(true); // all elements fade out and hide
10864 els.setWidth(100).hide(true);
10867 Roo.CompositeElement = function(els){
10868 this.elements = [];
10869 this.addElements(els);
10871 Roo.CompositeElement.prototype = {
10873 addElements : function(els){
10874 if(!els) return this;
10875 if(typeof els == "string"){
10876 els = Roo.Element.selectorFunction(els);
10878 var yels = this.elements;
10879 var index = yels.length-1;
10880 for(var i = 0, len = els.length; i < len; i++) {
10881 yels[++index] = Roo.get(els[i]);
10887 * Clears this composite and adds the elements returned by the passed selector.
10888 * @param {String/Array} els A string CSS selector, an array of elements or an element
10889 * @return {CompositeElement} this
10891 fill : function(els){
10892 this.elements = [];
10898 * Filters this composite to only elements that match the passed selector.
10899 * @param {String} selector A string CSS selector
10900 * @return {CompositeElement} this
10902 filter : function(selector){
10904 this.each(function(el){
10905 if(el.is(selector)){
10906 els[els.length] = el.dom;
10913 invoke : function(fn, args){
10914 var els = this.elements;
10915 for(var i = 0, len = els.length; i < len; i++) {
10916 Roo.Element.prototype[fn].apply(els[i], args);
10921 * Adds elements to this composite.
10922 * @param {String/Array} els A string CSS selector, an array of elements or an element
10923 * @return {CompositeElement} this
10925 add : function(els){
10926 if(typeof els == "string"){
10927 this.addElements(Roo.Element.selectorFunction(els));
10928 }else if(els.length !== undefined){
10929 this.addElements(els);
10931 this.addElements([els]);
10936 * Calls the passed function passing (el, this, index) for each element in this composite.
10937 * @param {Function} fn The function to call
10938 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10939 * @return {CompositeElement} this
10941 each : function(fn, scope){
10942 var els = this.elements;
10943 for(var i = 0, len = els.length; i < len; i++){
10944 if(fn.call(scope || els[i], els[i], this, i) === false) {
10952 * Returns the Element object at the specified index
10953 * @param {Number} index
10954 * @return {Roo.Element}
10956 item : function(index){
10957 return this.elements[index] || null;
10961 * Returns the first Element
10962 * @return {Roo.Element}
10964 first : function(){
10965 return this.item(0);
10969 * Returns the last Element
10970 * @return {Roo.Element}
10973 return this.item(this.elements.length-1);
10977 * Returns the number of elements in this composite
10980 getCount : function(){
10981 return this.elements.length;
10985 * Returns true if this composite contains the passed element
10988 contains : function(el){
10989 return this.indexOf(el) !== -1;
10993 * Returns true if this composite contains the passed element
10996 indexOf : function(el){
10997 return this.elements.indexOf(Roo.get(el));
11002 * Removes the specified element(s).
11003 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11004 * or an array of any of those.
11005 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11006 * @return {CompositeElement} this
11008 removeElement : function(el, removeDom){
11009 if(el instanceof Array){
11010 for(var i = 0, len = el.length; i < len; i++){
11011 this.removeElement(el[i]);
11015 var index = typeof el == 'number' ? el : this.indexOf(el);
11018 var d = this.elements[index];
11022 d.parentNode.removeChild(d);
11025 this.elements.splice(index, 1);
11031 * Replaces the specified element with the passed element.
11032 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11034 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11035 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11036 * @return {CompositeElement} this
11038 replaceElement : function(el, replacement, domReplace){
11039 var index = typeof el == 'number' ? el : this.indexOf(el);
11042 this.elements[index].replaceWith(replacement);
11044 this.elements.splice(index, 1, Roo.get(replacement))
11051 * Removes all elements.
11053 clear : function(){
11054 this.elements = [];
11058 Roo.CompositeElement.createCall = function(proto, fnName){
11059 if(!proto[fnName]){
11060 proto[fnName] = function(){
11061 return this.invoke(fnName, arguments);
11065 for(var fnName in Roo.Element.prototype){
11066 if(typeof Roo.Element.prototype[fnName] == "function"){
11067 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11073 * Ext JS Library 1.1.1
11074 * Copyright(c) 2006-2007, Ext JS, LLC.
11076 * Originally Released Under LGPL - original licence link has changed is not relivant.
11079 * <script type="text/javascript">
11083 * @class Roo.CompositeElementLite
11084 * @extends Roo.CompositeElement
11085 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11087 var els = Roo.select("#some-el div.some-class");
11088 // or select directly from an existing element
11089 var el = Roo.get('some-el');
11090 el.select('div.some-class');
11092 els.setWidth(100); // all elements become 100 width
11093 els.hide(true); // all elements fade out and hide
11095 els.setWidth(100).hide(true);
11096 </code></pre><br><br>
11097 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11098 * actions will be performed on all the elements in this collection.</b>
11100 Roo.CompositeElementLite = function(els){
11101 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11102 this.el = new Roo.Element.Flyweight();
11104 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11105 addElements : function(els){
11107 if(els instanceof Array){
11108 this.elements = this.elements.concat(els);
11110 var yels = this.elements;
11111 var index = yels.length-1;
11112 for(var i = 0, len = els.length; i < len; i++) {
11113 yels[++index] = els[i];
11119 invoke : function(fn, args){
11120 var els = this.elements;
11122 for(var i = 0, len = els.length; i < len; i++) {
11124 Roo.Element.prototype[fn].apply(el, args);
11129 * Returns a flyweight Element of the dom element object at the specified index
11130 * @param {Number} index
11131 * @return {Roo.Element}
11133 item : function(index){
11134 if(!this.elements[index]){
11137 this.el.dom = this.elements[index];
11141 // fixes scope with flyweight
11142 addListener : function(eventName, handler, scope, opt){
11143 var els = this.elements;
11144 for(var i = 0, len = els.length; i < len; i++) {
11145 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11151 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11152 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11153 * a reference to the dom node, use el.dom.</b>
11154 * @param {Function} fn The function to call
11155 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11156 * @return {CompositeElement} this
11158 each : function(fn, scope){
11159 var els = this.elements;
11161 for(var i = 0, len = els.length; i < len; i++){
11163 if(fn.call(scope || el, el, this, i) === false){
11170 indexOf : function(el){
11171 return this.elements.indexOf(Roo.getDom(el));
11174 replaceElement : function(el, replacement, domReplace){
11175 var index = typeof el == 'number' ? el : this.indexOf(el);
11177 replacement = Roo.getDom(replacement);
11179 var d = this.elements[index];
11180 d.parentNode.insertBefore(replacement, d);
11181 d.parentNode.removeChild(d);
11183 this.elements.splice(index, 1, replacement);
11188 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11192 * Ext JS Library 1.1.1
11193 * Copyright(c) 2006-2007, Ext JS, LLC.
11195 * Originally Released Under LGPL - original licence link has changed is not relivant.
11198 * <script type="text/javascript">
11204 * @class Roo.data.Connection
11205 * @extends Roo.util.Observable
11206 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11207 * either to a configured URL, or to a URL specified at request time.<br><br>
11209 * Requests made by this class are asynchronous, and will return immediately. No data from
11210 * the server will be available to the statement immediately following the {@link #request} call.
11211 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11213 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11214 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11215 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11216 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11217 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11218 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11219 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11220 * standard DOM methods.
11222 * @param {Object} config a configuration object.
11224 Roo.data.Connection = function(config){
11225 Roo.apply(this, config);
11228 * @event beforerequest
11229 * Fires before a network request is made to retrieve a data object.
11230 * @param {Connection} conn This Connection object.
11231 * @param {Object} options The options config object passed to the {@link #request} method.
11233 "beforerequest" : true,
11235 * @event requestcomplete
11236 * Fires if the request was successfully completed.
11237 * @param {Connection} conn This Connection object.
11238 * @param {Object} response The XHR object containing the response data.
11239 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11240 * @param {Object} options The options config object passed to the {@link #request} method.
11242 "requestcomplete" : true,
11244 * @event requestexception
11245 * Fires if an error HTTP status was returned from the server.
11246 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11247 * @param {Connection} conn This Connection object.
11248 * @param {Object} response The XHR object containing the response data.
11249 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11250 * @param {Object} options The options config object passed to the {@link #request} method.
11252 "requestexception" : true
11254 Roo.data.Connection.superclass.constructor.call(this);
11257 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11259 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11262 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11263 * extra parameters to each request made by this object. (defaults to undefined)
11266 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11267 * to each request made by this object. (defaults to undefined)
11270 * @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)
11273 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11277 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11283 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11286 disableCaching: true,
11289 * Sends an HTTP request to a remote server.
11290 * @param {Object} options An object which may contain the following properties:<ul>
11291 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11292 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11293 * request, a url encoded string or a function to call to get either.</li>
11294 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11295 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11296 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11297 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11298 * <li>options {Object} The parameter to the request call.</li>
11299 * <li>success {Boolean} True if the request succeeded.</li>
11300 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11302 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11303 * The callback is passed the following parameters:<ul>
11304 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11305 * <li>options {Object} The parameter to the request call.</li>
11307 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11308 * The callback is passed the following parameters:<ul>
11309 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11310 * <li>options {Object} The parameter to the request call.</li>
11312 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11313 * for the callback function. Defaults to the browser window.</li>
11314 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11315 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11316 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11317 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11318 * params for the post data. Any params will be appended to the URL.</li>
11319 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11321 * @return {Number} transactionId
11323 request : function(o){
11324 if(this.fireEvent("beforerequest", this, o) !== false){
11327 if(typeof p == "function"){
11328 p = p.call(o.scope||window, o);
11330 if(typeof p == "object"){
11331 p = Roo.urlEncode(o.params);
11333 if(this.extraParams){
11334 var extras = Roo.urlEncode(this.extraParams);
11335 p = p ? (p + '&' + extras) : extras;
11338 var url = o.url || this.url;
11339 if(typeof url == 'function'){
11340 url = url.call(o.scope||window, o);
11344 var form = Roo.getDom(o.form);
11345 url = url || form.action;
11347 var enctype = form.getAttribute("enctype");
11348 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11349 return this.doFormUpload(o, p, url);
11351 var f = Roo.lib.Ajax.serializeForm(form);
11352 p = p ? (p + '&' + f) : f;
11355 var hs = o.headers;
11356 if(this.defaultHeaders){
11357 hs = Roo.apply(hs || {}, this.defaultHeaders);
11364 success: this.handleResponse,
11365 failure: this.handleFailure,
11367 argument: {options: o},
11368 timeout : this.timeout
11371 var method = o.method||this.method||(p ? "POST" : "GET");
11373 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11374 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11377 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11381 }else if(this.autoAbort !== false){
11385 if((method == 'GET' && p) || o.xmlData){
11386 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11389 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11390 return this.transId;
11392 Roo.callback(o.callback, o.scope, [o, null, null]);
11398 * Determine whether this object has a request outstanding.
11399 * @param {Number} transactionId (Optional) defaults to the last transaction
11400 * @return {Boolean} True if there is an outstanding request.
11402 isLoading : function(transId){
11404 return Roo.lib.Ajax.isCallInProgress(transId);
11406 return this.transId ? true : false;
11411 * Aborts any outstanding request.
11412 * @param {Number} transactionId (Optional) defaults to the last transaction
11414 abort : function(transId){
11415 if(transId || this.isLoading()){
11416 Roo.lib.Ajax.abort(transId || this.transId);
11421 handleResponse : function(response){
11422 this.transId = false;
11423 var options = response.argument.options;
11424 response.argument = options ? options.argument : null;
11425 this.fireEvent("requestcomplete", this, response, options);
11426 Roo.callback(options.success, options.scope, [response, options]);
11427 Roo.callback(options.callback, options.scope, [options, true, response]);
11431 handleFailure : function(response, e){
11432 this.transId = false;
11433 var options = response.argument.options;
11434 response.argument = options ? options.argument : null;
11435 this.fireEvent("requestexception", this, response, options, e);
11436 Roo.callback(options.failure, options.scope, [response, options]);
11437 Roo.callback(options.callback, options.scope, [options, false, response]);
11441 doFormUpload : function(o, ps, url){
11443 var frame = document.createElement('iframe');
11446 frame.className = 'x-hidden';
11448 frame.src = Roo.SSL_SECURE_URL;
11450 document.body.appendChild(frame);
11453 document.frames[id].name = id;
11456 var form = Roo.getDom(o.form);
11458 form.method = 'POST';
11459 form.enctype = form.encoding = 'multipart/form-data';
11465 if(ps){ // add dynamic params
11467 ps = Roo.urlDecode(ps, false);
11469 if(ps.hasOwnProperty(k)){
11470 hd = document.createElement('input');
11471 hd.type = 'hidden';
11474 form.appendChild(hd);
11481 var r = { // bogus response object
11486 r.argument = o ? o.argument : null;
11491 doc = frame.contentWindow.document;
11493 doc = (frame.contentDocument || window.frames[id].document);
11495 if(doc && doc.body){
11496 r.responseText = doc.body.innerHTML;
11498 if(doc && doc.XMLDocument){
11499 r.responseXML = doc.XMLDocument;
11501 r.responseXML = doc;
11508 Roo.EventManager.removeListener(frame, 'load', cb, this);
11510 this.fireEvent("requestcomplete", this, r, o);
11511 Roo.callback(o.success, o.scope, [r, o]);
11512 Roo.callback(o.callback, o.scope, [o, true, r]);
11514 setTimeout(function(){document.body.removeChild(frame);}, 100);
11517 Roo.EventManager.on(frame, 'load', cb, this);
11520 if(hiddens){ // remove dynamic params
11521 for(var i = 0, len = hiddens.length; i < len; i++){
11522 form.removeChild(hiddens[i]);
11530 * @extends Roo.data.Connection
11531 * Global Ajax request class.
11535 Roo.Ajax = new Roo.data.Connection({
11538 * @cfg {String} url @hide
11541 * @cfg {Object} extraParams @hide
11544 * @cfg {Object} defaultHeaders @hide
11547 * @cfg {String} method (Optional) @hide
11550 * @cfg {Number} timeout (Optional) @hide
11553 * @cfg {Boolean} autoAbort (Optional) @hide
11557 * @cfg {Boolean} disableCaching (Optional) @hide
11561 * @property disableCaching
11562 * True to add a unique cache-buster param to GET requests. (defaults to true)
11567 * The default URL to be used for requests to the server. (defaults to undefined)
11571 * @property extraParams
11572 * An object containing properties which are used as
11573 * extra parameters to each request made by this object. (defaults to undefined)
11577 * @property defaultHeaders
11578 * An object containing request headers which are added to each request made by this object. (defaults to undefined)
11583 * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11587 * @property timeout
11588 * The timeout in milliseconds to be used for requests. (defaults to 30000)
11593 * @property autoAbort
11594 * Whether a new request should abort any pending requests. (defaults to false)
11600 * Serialize the passed form into a url encoded string
11601 * @param {String/HTMLElement} form
11604 serializeForm : function(form){
11605 return Roo.lib.Ajax.serializeForm(form);
11609 * Ext JS Library 1.1.1
11610 * Copyright(c) 2006-2007, Ext JS, LLC.
11612 * Originally Released Under LGPL - original licence link has changed is not relivant.
11615 * <script type="text/javascript">
11619 * Global Ajax request class.
11622 * @extends Roo.data.Connection
11625 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11626 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11627 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11628 * @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)
11629 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11630 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11631 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11633 Roo.Ajax = new Roo.data.Connection({
11642 * Serialize the passed form into a url encoded string
11644 * @param {String/HTMLElement} form
11647 serializeForm : function(form){
11648 return Roo.lib.Ajax.serializeForm(form);
11652 * Ext JS Library 1.1.1
11653 * Copyright(c) 2006-2007, Ext JS, LLC.
11655 * Originally Released Under LGPL - original licence link has changed is not relivant.
11658 * <script type="text/javascript">
11663 * @class Roo.UpdateManager
11664 * @extends Roo.util.Observable
11665 * Provides AJAX-style update for Element object.<br><br>
11668 * // Get it from a Roo.Element object
11669 * var el = Roo.get("foo");
11670 * var mgr = el.getUpdateManager();
11671 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11673 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11675 * // or directly (returns the same UpdateManager instance)
11676 * var mgr = new Roo.UpdateManager("myElementId");
11677 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11678 * mgr.on("update", myFcnNeedsToKnow);
11680 // short handed call directly from the element object
11681 Roo.get("foo").load({
11685 text: "Loading Foo..."
11689 * Create new UpdateManager directly.
11690 * @param {String/HTMLElement/Roo.Element} el The element to update
11691 * @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).
11693 Roo.UpdateManager = function(el, forceNew){
11695 if(!forceNew && el.updateManager){
11696 return el.updateManager;
11699 * The Element object
11700 * @type Roo.Element
11704 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11707 this.defaultUrl = null;
11711 * @event beforeupdate
11712 * Fired before an update is made, return false from your handler and the update is cancelled.
11713 * @param {Roo.Element} el
11714 * @param {String/Object/Function} url
11715 * @param {String/Object} params
11717 "beforeupdate": true,
11720 * Fired after successful update is made.
11721 * @param {Roo.Element} el
11722 * @param {Object} oResponseObject The response Object
11727 * Fired on update failure.
11728 * @param {Roo.Element} el
11729 * @param {Object} oResponseObject The response Object
11733 var d = Roo.UpdateManager.defaults;
11735 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11738 this.sslBlankUrl = d.sslBlankUrl;
11740 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11743 this.disableCaching = d.disableCaching;
11745 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11748 this.indicatorText = d.indicatorText;
11750 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11753 this.showLoadIndicator = d.showLoadIndicator;
11755 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11758 this.timeout = d.timeout;
11761 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11764 this.loadScripts = d.loadScripts;
11767 * Transaction object of current executing transaction
11769 this.transaction = null;
11774 this.autoRefreshProcId = null;
11776 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11779 this.refreshDelegate = this.refresh.createDelegate(this);
11781 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11784 this.updateDelegate = this.update.createDelegate(this);
11786 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11789 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11793 this.successDelegate = this.processSuccess.createDelegate(this);
11797 this.failureDelegate = this.processFailure.createDelegate(this);
11799 if(!this.renderer){
11801 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11803 this.renderer = new Roo.UpdateManager.BasicRenderer();
11806 Roo.UpdateManager.superclass.constructor.call(this);
11809 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11811 * Get the Element this UpdateManager is bound to
11812 * @return {Roo.Element} The element
11814 getEl : function(){
11818 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11819 * @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:
11822 url: "your-url.php",<br/>
11823 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11824 callback: yourFunction,<br/>
11825 scope: yourObject, //(optional scope) <br/>
11826 discardUrl: false, <br/>
11827 nocache: false,<br/>
11828 text: "Loading...",<br/>
11830 scripts: false<br/>
11833 * The only required property is url. The optional properties nocache, text and scripts
11834 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11835 * @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}
11836 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11837 * @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.
11839 update : function(url, params, callback, discardUrl){
11840 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11841 var method = this.method, cfg;
11842 if(typeof url == "object"){ // must be config object
11845 params = params || cfg.params;
11846 callback = callback || cfg.callback;
11847 discardUrl = discardUrl || cfg.discardUrl;
11848 if(callback && cfg.scope){
11849 callback = callback.createDelegate(cfg.scope);
11851 if(typeof cfg.method != "undefined"){method = cfg.method;};
11852 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11853 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11854 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11855 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11857 this.showLoading();
11859 this.defaultUrl = url;
11861 if(typeof url == "function"){
11862 url = url.call(this);
11865 method = method || (params ? "POST" : "GET");
11866 if(method == "GET"){
11867 url = this.prepareUrl(url);
11870 var o = Roo.apply(cfg ||{}, {
11873 success: this.successDelegate,
11874 failure: this.failureDelegate,
11875 callback: undefined,
11876 timeout: (this.timeout*1000),
11877 argument: {"url": url, "form": null, "callback": callback, "params": params}
11880 this.transaction = Roo.Ajax.request(o);
11885 * 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.
11886 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11887 * @param {String/HTMLElement} form The form Id or form element
11888 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11889 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11890 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11892 formUpdate : function(form, url, reset, callback){
11893 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11894 if(typeof url == "function"){
11895 url = url.call(this);
11897 form = Roo.getDom(form);
11898 this.transaction = Roo.Ajax.request({
11901 success: this.successDelegate,
11902 failure: this.failureDelegate,
11903 timeout: (this.timeout*1000),
11904 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11906 this.showLoading.defer(1, this);
11911 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11912 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11914 refresh : function(callback){
11915 if(this.defaultUrl == null){
11918 this.update(this.defaultUrl, null, callback, true);
11922 * Set this element to auto refresh.
11923 * @param {Number} interval How often to update (in seconds).
11924 * @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)
11925 * @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}
11926 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11927 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11929 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11931 this.update(url || this.defaultUrl, params, callback, true);
11933 if(this.autoRefreshProcId){
11934 clearInterval(this.autoRefreshProcId);
11936 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11940 * Stop auto refresh on this element.
11942 stopAutoRefresh : function(){
11943 if(this.autoRefreshProcId){
11944 clearInterval(this.autoRefreshProcId);
11945 delete this.autoRefreshProcId;
11949 isAutoRefreshing : function(){
11950 return this.autoRefreshProcId ? true : false;
11953 * Called to update the element to "Loading" state. Override to perform custom action.
11955 showLoading : function(){
11956 if(this.showLoadIndicator){
11957 this.el.update(this.indicatorText);
11962 * Adds unique parameter to query string if disableCaching = true
11965 prepareUrl : function(url){
11966 if(this.disableCaching){
11967 var append = "_dc=" + (new Date().getTime());
11968 if(url.indexOf("?") !== -1){
11969 url += "&" + append;
11971 url += "?" + append;
11980 processSuccess : function(response){
11981 this.transaction = null;
11982 if(response.argument.form && response.argument.reset){
11983 try{ // put in try/catch since some older FF releases had problems with this
11984 response.argument.form.reset();
11987 if(this.loadScripts){
11988 this.renderer.render(this.el, response, this,
11989 this.updateComplete.createDelegate(this, [response]));
11991 this.renderer.render(this.el, response, this);
11992 this.updateComplete(response);
11996 updateComplete : function(response){
11997 this.fireEvent("update", this.el, response);
11998 if(typeof response.argument.callback == "function"){
11999 response.argument.callback(this.el, true, response);
12006 processFailure : function(response){
12007 this.transaction = null;
12008 this.fireEvent("failure", this.el, response);
12009 if(typeof response.argument.callback == "function"){
12010 response.argument.callback(this.el, false, response);
12015 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12016 * @param {Object} renderer The object implementing the render() method
12018 setRenderer : function(renderer){
12019 this.renderer = renderer;
12022 getRenderer : function(){
12023 return this.renderer;
12027 * Set the defaultUrl used for updates
12028 * @param {String/Function} defaultUrl The url or a function to call to get the url
12030 setDefaultUrl : function(defaultUrl){
12031 this.defaultUrl = defaultUrl;
12035 * Aborts the executing transaction
12037 abort : function(){
12038 if(this.transaction){
12039 Roo.Ajax.abort(this.transaction);
12044 * Returns true if an update is in progress
12045 * @return {Boolean}
12047 isUpdating : function(){
12048 if(this.transaction){
12049 return Roo.Ajax.isLoading(this.transaction);
12056 * @class Roo.UpdateManager.defaults
12057 * @static (not really - but it helps the doc tool)
12058 * The defaults collection enables customizing the default properties of UpdateManager
12060 Roo.UpdateManager.defaults = {
12062 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12068 * True to process scripts by default (Defaults to false).
12071 loadScripts : false,
12074 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12077 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12079 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12082 disableCaching : false,
12084 * Whether to show indicatorText when loading (Defaults to true).
12087 showLoadIndicator : true,
12089 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12092 indicatorText : '<div class="loading-indicator">Loading...</div>'
12096 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12098 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12099 * @param {String/HTMLElement/Roo.Element} el The element to update
12100 * @param {String} url The url
12101 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12102 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12105 * @member Roo.UpdateManager
12107 Roo.UpdateManager.updateElement = function(el, url, params, options){
12108 var um = Roo.get(el, true).getUpdateManager();
12109 Roo.apply(um, options);
12110 um.update(url, params, options ? options.callback : null);
12112 // alias for backwards compat
12113 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12115 * @class Roo.UpdateManager.BasicRenderer
12116 * Default Content renderer. Updates the elements innerHTML with the responseText.
12118 Roo.UpdateManager.BasicRenderer = function(){};
12120 Roo.UpdateManager.BasicRenderer.prototype = {
12122 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12123 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12124 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12125 * @param {Roo.Element} el The element being rendered
12126 * @param {Object} response The YUI Connect response object
12127 * @param {UpdateManager} updateManager The calling update manager
12128 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12130 render : function(el, response, updateManager, callback){
12131 el.update(response.responseText, updateManager.loadScripts, callback);
12136 * Ext JS Library 1.1.1
12137 * Copyright(c) 2006-2007, Ext JS, LLC.
12139 * Originally Released Under LGPL - original licence link has changed is not relivant.
12142 * <script type="text/javascript">
12146 * @class Roo.util.DelayedTask
12147 * Provides a convenient method of performing setTimeout where a new
12148 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12149 * You can use this class to buffer
12150 * the keypress events for a certain number of milliseconds, and perform only if they stop
12151 * for that amount of time.
12152 * @constructor The parameters to this constructor serve as defaults and are not required.
12153 * @param {Function} fn (optional) The default function to timeout
12154 * @param {Object} scope (optional) The default scope of that timeout
12155 * @param {Array} args (optional) The default Array of arguments
12157 Roo.util.DelayedTask = function(fn, scope, args){
12158 var id = null, d, t;
12160 var call = function(){
12161 var now = new Date().getTime();
12165 fn.apply(scope, args || []);
12169 * Cancels any pending timeout and queues a new one
12170 * @param {Number} delay The milliseconds to delay
12171 * @param {Function} newFn (optional) Overrides function passed to constructor
12172 * @param {Object} newScope (optional) Overrides scope passed to constructor
12173 * @param {Array} newArgs (optional) Overrides args passed to constructor
12175 this.delay = function(delay, newFn, newScope, newArgs){
12176 if(id && delay != d){
12180 t = new Date().getTime();
12182 scope = newScope || scope;
12183 args = newArgs || args;
12185 id = setInterval(call, d);
12190 * Cancel the last queued timeout
12192 this.cancel = function(){
12200 * Ext JS Library 1.1.1
12201 * Copyright(c) 2006-2007, Ext JS, LLC.
12203 * Originally Released Under LGPL - original licence link has changed is not relivant.
12206 * <script type="text/javascript">
12210 Roo.util.TaskRunner = function(interval){
12211 interval = interval || 10;
12212 var tasks = [], removeQueue = [];
12214 var running = false;
12216 var stopThread = function(){
12222 var startThread = function(){
12225 id = setInterval(runTasks, interval);
12229 var removeTask = function(task){
12230 removeQueue.push(task);
12236 var runTasks = function(){
12237 if(removeQueue.length > 0){
12238 for(var i = 0, len = removeQueue.length; i < len; i++){
12239 tasks.remove(removeQueue[i]);
12242 if(tasks.length < 1){
12247 var now = new Date().getTime();
12248 for(var i = 0, len = tasks.length; i < len; ++i){
12250 var itime = now - t.taskRunTime;
12251 if(t.interval <= itime){
12252 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12253 t.taskRunTime = now;
12254 if(rt === false || t.taskRunCount === t.repeat){
12259 if(t.duration && t.duration <= (now - t.taskStartTime)){
12266 * Queues a new task.
12267 * @param {Object} task
12269 this.start = function(task){
12271 task.taskStartTime = new Date().getTime();
12272 task.taskRunTime = 0;
12273 task.taskRunCount = 0;
12278 this.stop = function(task){
12283 this.stopAll = function(){
12285 for(var i = 0, len = tasks.length; i < len; i++){
12286 if(tasks[i].onStop){
12295 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12297 * Ext JS Library 1.1.1
12298 * Copyright(c) 2006-2007, Ext JS, LLC.
12300 * Originally Released Under LGPL - original licence link has changed is not relivant.
12303 * <script type="text/javascript">
12308 * @class Roo.util.MixedCollection
12309 * @extends Roo.util.Observable
12310 * A Collection class that maintains both numeric indexes and keys and exposes events.
12312 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12313 * collection (defaults to false)
12314 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12315 * and return the key value for that item. This is used when available to look up the key on items that
12316 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12317 * equivalent to providing an implementation for the {@link #getKey} method.
12319 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12327 * Fires when the collection is cleared.
12332 * Fires when an item is added to the collection.
12333 * @param {Number} index The index at which the item was added.
12334 * @param {Object} o The item added.
12335 * @param {String} key The key associated with the added item.
12340 * Fires when an item is replaced in the collection.
12341 * @param {String} key he key associated with the new added.
12342 * @param {Object} old The item being replaced.
12343 * @param {Object} new The new item.
12348 * Fires when an item is removed from the collection.
12349 * @param {Object} o The item being removed.
12350 * @param {String} key (optional) The key associated with the removed item.
12355 this.allowFunctions = allowFunctions === true;
12357 this.getKey = keyFn;
12359 Roo.util.MixedCollection.superclass.constructor.call(this);
12362 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12363 allowFunctions : false,
12366 * Adds an item to the collection.
12367 * @param {String} key The key to associate with the item
12368 * @param {Object} o The item to add.
12369 * @return {Object} The item added.
12371 add : function(key, o){
12372 if(arguments.length == 1){
12374 key = this.getKey(o);
12376 if(typeof key == "undefined" || key === null){
12378 this.items.push(o);
12379 this.keys.push(null);
12381 var old = this.map[key];
12383 return this.replace(key, o);
12386 this.items.push(o);
12388 this.keys.push(key);
12390 this.fireEvent("add", this.length-1, o, key);
12395 * MixedCollection has a generic way to fetch keys if you implement getKey.
12398 var mc = new Roo.util.MixedCollection();
12399 mc.add(someEl.dom.id, someEl);
12400 mc.add(otherEl.dom.id, otherEl);
12404 var mc = new Roo.util.MixedCollection();
12405 mc.getKey = function(el){
12411 // or via the constructor
12412 var mc = new Roo.util.MixedCollection(false, function(el){
12418 * @param o {Object} The item for which to find the key.
12419 * @return {Object} The key for the passed item.
12421 getKey : function(o){
12426 * Replaces an item in the collection.
12427 * @param {String} key The key associated with the item to replace, or the item to replace.
12428 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12429 * @return {Object} The new item.
12431 replace : function(key, o){
12432 if(arguments.length == 1){
12434 key = this.getKey(o);
12436 var old = this.item(key);
12437 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12438 return this.add(key, o);
12440 var index = this.indexOfKey(key);
12441 this.items[index] = o;
12443 this.fireEvent("replace", key, old, o);
12448 * Adds all elements of an Array or an Object to the collection.
12449 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12450 * an Array of values, each of which are added to the collection.
12452 addAll : function(objs){
12453 if(arguments.length > 1 || objs instanceof Array){
12454 var args = arguments.length > 1 ? arguments : objs;
12455 for(var i = 0, len = args.length; i < len; i++){
12459 for(var key in objs){
12460 if(this.allowFunctions || typeof objs[key] != "function"){
12461 this.add(key, objs[key]);
12468 * Executes the specified function once for every item in the collection, passing each
12469 * item as the first and only parameter. returning false from the function will stop the iteration.
12470 * @param {Function} fn The function to execute for each item.
12471 * @param {Object} scope (optional) The scope in which to execute the function.
12473 each : function(fn, scope){
12474 var items = [].concat(this.items); // each safe for removal
12475 for(var i = 0, len = items.length; i < len; i++){
12476 if(fn.call(scope || items[i], items[i], i, len) === false){
12483 * Executes the specified function once for every key in the collection, passing each
12484 * key, and its associated item as the first two parameters.
12485 * @param {Function} fn The function to execute for each item.
12486 * @param {Object} scope (optional) The scope in which to execute the function.
12488 eachKey : function(fn, scope){
12489 for(var i = 0, len = this.keys.length; i < len; i++){
12490 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12495 * Returns the first item in the collection which elicits a true return value from the
12496 * passed selection function.
12497 * @param {Function} fn The selection function to execute for each item.
12498 * @param {Object} scope (optional) The scope in which to execute the function.
12499 * @return {Object} The first item in the collection which returned true from the selection function.
12501 find : function(fn, scope){
12502 for(var i = 0, len = this.items.length; i < len; i++){
12503 if(fn.call(scope || window, this.items[i], this.keys[i])){
12504 return this.items[i];
12511 * Inserts an item at the specified index in the collection.
12512 * @param {Number} index The index to insert the item at.
12513 * @param {String} key The key to associate with the new item, or the item itself.
12514 * @param {Object} o (optional) If the second parameter was a key, the new item.
12515 * @return {Object} The item inserted.
12517 insert : function(index, key, o){
12518 if(arguments.length == 2){
12520 key = this.getKey(o);
12522 if(index >= this.length){
12523 return this.add(key, o);
12526 this.items.splice(index, 0, o);
12527 if(typeof key != "undefined" && key != null){
12530 this.keys.splice(index, 0, key);
12531 this.fireEvent("add", index, o, key);
12536 * Removed an item from the collection.
12537 * @param {Object} o The item to remove.
12538 * @return {Object} The item removed.
12540 remove : function(o){
12541 return this.removeAt(this.indexOf(o));
12545 * Remove an item from a specified index in the collection.
12546 * @param {Number} index The index within the collection of the item to remove.
12548 removeAt : function(index){
12549 if(index < this.length && index >= 0){
12551 var o = this.items[index];
12552 this.items.splice(index, 1);
12553 var key = this.keys[index];
12554 if(typeof key != "undefined"){
12555 delete this.map[key];
12557 this.keys.splice(index, 1);
12558 this.fireEvent("remove", o, key);
12563 * Removed an item associated with the passed key fom the collection.
12564 * @param {String} key The key of the item to remove.
12566 removeKey : function(key){
12567 return this.removeAt(this.indexOfKey(key));
12571 * Returns the number of items in the collection.
12572 * @return {Number} the number of items in the collection.
12574 getCount : function(){
12575 return this.length;
12579 * Returns index within the collection of the passed Object.
12580 * @param {Object} o The item to find the index of.
12581 * @return {Number} index of the item.
12583 indexOf : function(o){
12584 if(!this.items.indexOf){
12585 for(var i = 0, len = this.items.length; i < len; i++){
12586 if(this.items[i] == o) return i;
12590 return this.items.indexOf(o);
12595 * Returns index within the collection of the passed key.
12596 * @param {String} key The key to find the index of.
12597 * @return {Number} index of the key.
12599 indexOfKey : function(key){
12600 if(!this.keys.indexOf){
12601 for(var i = 0, len = this.keys.length; i < len; i++){
12602 if(this.keys[i] == key) return i;
12606 return this.keys.indexOf(key);
12611 * Returns the item associated with the passed key OR index. Key has priority over index.
12612 * @param {String/Number} key The key or index of the item.
12613 * @return {Object} The item associated with the passed key.
12615 item : function(key){
12616 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
12617 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12621 * Returns the item at the specified index.
12622 * @param {Number} index The index of the item.
12625 itemAt : function(index){
12626 return this.items[index];
12630 * Returns the item associated with the passed key.
12631 * @param {String/Number} key The key of the item.
12632 * @return {Object} The item associated with the passed key.
12634 key : function(key){
12635 return this.map[key];
12639 * Returns true if the collection contains the passed Object as an item.
12640 * @param {Object} o The Object to look for in the collection.
12641 * @return {Boolean} True if the collection contains the Object as an item.
12643 contains : function(o){
12644 return this.indexOf(o) != -1;
12648 * Returns true if the collection contains the passed Object as a key.
12649 * @param {String} key The key to look for in the collection.
12650 * @return {Boolean} True if the collection contains the Object as a key.
12652 containsKey : function(key){
12653 return typeof this.map[key] != "undefined";
12657 * Removes all items from the collection.
12659 clear : function(){
12664 this.fireEvent("clear");
12668 * Returns the first item in the collection.
12669 * @return {Object} the first item in the collection..
12671 first : function(){
12672 return this.items[0];
12676 * Returns the last item in the collection.
12677 * @return {Object} the last item in the collection..
12680 return this.items[this.length-1];
12683 _sort : function(property, dir, fn){
12684 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
12685 fn = fn || function(a, b){
12688 var c = [], k = this.keys, items = this.items;
12689 for(var i = 0, len = items.length; i < len; i++){
12690 c[c.length] = {key: k[i], value: items[i], index: i};
12692 c.sort(function(a, b){
12693 var v = fn(a[property], b[property]) * dsc;
12695 v = (a.index < b.index ? -1 : 1);
12699 for(var i = 0, len = c.length; i < len; i++){
12700 items[i] = c[i].value;
12703 this.fireEvent("sort", this);
12707 * Sorts this collection with the passed comparison function
12708 * @param {String} direction (optional) "ASC" or "DESC"
12709 * @param {Function} fn (optional) comparison function
12711 sort : function(dir, fn){
12712 this._sort("value", dir, fn);
12716 * Sorts this collection by keys
12717 * @param {String} direction (optional) "ASC" or "DESC"
12718 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
12720 keySort : function(dir, fn){
12721 this._sort("key", dir, fn || function(a, b){
12722 return String(a).toUpperCase()-String(b).toUpperCase();
12727 * Returns a range of items in this collection
12728 * @param {Number} startIndex (optional) defaults to 0
12729 * @param {Number} endIndex (optional) default to the last item
12730 * @return {Array} An array of items
12732 getRange : function(start, end){
12733 var items = this.items;
12734 if(items.length < 1){
12737 start = start || 0;
12738 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
12741 for(var i = start; i <= end; i++) {
12742 r[r.length] = items[i];
12745 for(var i = start; i >= end; i--) {
12746 r[r.length] = items[i];
12753 * Filter the <i>objects</i> in this collection by a specific property.
12754 * Returns a new collection that has been filtered.
12755 * @param {String} property A property on your objects
12756 * @param {String/RegExp} value Either string that the property values
12757 * should start with or a RegExp to test against the property
12758 * @return {MixedCollection} The new filtered collection
12760 filter : function(property, value){
12761 if(!value.exec){ // not a regex
12762 value = String(value);
12763 if(value.length == 0){
12764 return this.clone();
12766 value = new RegExp("^" + Roo.escapeRe(value), "i");
12768 return this.filterBy(function(o){
12769 return o && value.test(o[property]);
12774 * Filter by a function. * Returns a new collection that has been filtered.
12775 * The passed function will be called with each
12776 * object in the collection. If the function returns true, the value is included
12777 * otherwise it is filtered.
12778 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12779 * @param {Object} scope (optional) The scope of the function (defaults to this)
12780 * @return {MixedCollection} The new filtered collection
12782 filterBy : function(fn, scope){
12783 var r = new Roo.util.MixedCollection();
12784 r.getKey = this.getKey;
12785 var k = this.keys, it = this.items;
12786 for(var i = 0, len = it.length; i < len; i++){
12787 if(fn.call(scope||this, it[i], k[i])){
12788 r.add(k[i], it[i]);
12795 * Creates a duplicate of this collection
12796 * @return {MixedCollection}
12798 clone : function(){
12799 var r = new Roo.util.MixedCollection();
12800 var k = this.keys, it = this.items;
12801 for(var i = 0, len = it.length; i < len; i++){
12802 r.add(k[i], it[i]);
12804 r.getKey = this.getKey;
12809 * Returns the item associated with the passed key or index.
12811 * @param {String/Number} key The key or index of the item.
12812 * @return {Object} The item associated with the passed key.
12814 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
12816 * Ext JS Library 1.1.1
12817 * Copyright(c) 2006-2007, Ext JS, LLC.
12819 * Originally Released Under LGPL - original licence link has changed is not relivant.
12822 * <script type="text/javascript">
12825 * @class Roo.util.JSON
12826 * Modified version of Douglas Crockford"s json.js that doesn"t
12827 * mess with the Object prototype
12828 * http://www.json.org/js.html
12831 Roo.util.JSON = new (function(){
12832 var useHasOwn = {}.hasOwnProperty ? true : false;
12834 // crashes Safari in some instances
12835 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
12837 var pad = function(n) {
12838 return n < 10 ? "0" + n : n;
12851 var encodeString = function(s){
12852 if (/["\\\x00-\x1f]/.test(s)) {
12853 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12858 c = b.charCodeAt();
12860 Math.floor(c / 16).toString(16) +
12861 (c % 16).toString(16);
12864 return '"' + s + '"';
12867 var encodeArray = function(o){
12868 var a = ["["], b, i, l = o.length, v;
12869 for (i = 0; i < l; i += 1) {
12871 switch (typeof v) {
12880 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
12888 var encodeDate = function(o){
12889 return '"' + o.getFullYear() + "-" +
12890 pad(o.getMonth() + 1) + "-" +
12891 pad(o.getDate()) + "T" +
12892 pad(o.getHours()) + ":" +
12893 pad(o.getMinutes()) + ":" +
12894 pad(o.getSeconds()) + '"';
12898 * Encodes an Object, Array or other value
12899 * @param {Mixed} o The variable to encode
12900 * @return {String} The JSON string
12902 this.encode = function(o)
12904 // should this be extended to fully wrap stringify..
12906 if(typeof o == "undefined" || o === null){
12908 }else if(o instanceof Array){
12909 return encodeArray(o);
12910 }else if(o instanceof Date){
12911 return encodeDate(o);
12912 }else if(typeof o == "string"){
12913 return encodeString(o);
12914 }else if(typeof o == "number"){
12915 return isFinite(o) ? String(o) : "null";
12916 }else if(typeof o == "boolean"){
12919 var a = ["{"], b, i, v;
12921 if(!useHasOwn || o.hasOwnProperty(i)) {
12923 switch (typeof v) {
12932 a.push(this.encode(i), ":",
12933 v === null ? "null" : this.encode(v));
12944 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
12945 * @param {String} json The JSON string
12946 * @return {Object} The resulting object
12948 this.decode = function(json){
12950 return /** eval:var:json */ eval("(" + json + ')');
12954 * Shorthand for {@link Roo.util.JSON#encode}
12955 * @member Roo encode
12957 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
12959 * Shorthand for {@link Roo.util.JSON#decode}
12960 * @member Roo decode
12962 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
12965 * Ext JS Library 1.1.1
12966 * Copyright(c) 2006-2007, Ext JS, LLC.
12968 * Originally Released Under LGPL - original licence link has changed is not relivant.
12971 * <script type="text/javascript">
12975 * @class Roo.util.Format
12976 * Reusable data formatting functions
12979 Roo.util.Format = function(){
12980 var trimRe = /^\s+|\s+$/g;
12983 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12984 * @param {String} value The string to truncate
12985 * @param {Number} length The maximum length to allow before truncating
12986 * @return {String} The converted text
12988 ellipsis : function(value, len){
12989 if(value && value.length > len){
12990 return value.substr(0, len-3)+"...";
12996 * Checks a reference and converts it to empty string if it is undefined
12997 * @param {Mixed} value Reference to check
12998 * @return {Mixed} Empty string if converted, otherwise the original value
13000 undef : function(value){
13001 return typeof value != "undefined" ? value : "";
13005 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13006 * @param {String} value The string to encode
13007 * @return {String} The encoded text
13009 htmlEncode : function(value){
13010 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13014 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13015 * @param {String} value The string to decode
13016 * @return {String} The decoded text
13018 htmlDecode : function(value){
13019 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13023 * Trims any whitespace from either side of a string
13024 * @param {String} value The text to trim
13025 * @return {String} The trimmed text
13027 trim : function(value){
13028 return String(value).replace(trimRe, "");
13032 * Returns a substring from within an original string
13033 * @param {String} value The original text
13034 * @param {Number} start The start index of the substring
13035 * @param {Number} length The length of the substring
13036 * @return {String} The substring
13038 substr : function(value, start, length){
13039 return String(value).substr(start, length);
13043 * Converts a string to all lower case letters
13044 * @param {String} value The text to convert
13045 * @return {String} The converted text
13047 lowercase : function(value){
13048 return String(value).toLowerCase();
13052 * Converts a string to all upper case letters
13053 * @param {String} value The text to convert
13054 * @return {String} The converted text
13056 uppercase : function(value){
13057 return String(value).toUpperCase();
13061 * Converts the first character only of a string to upper case
13062 * @param {String} value The text to convert
13063 * @return {String} The converted text
13065 capitalize : function(value){
13066 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13070 call : function(value, fn){
13071 if(arguments.length > 2){
13072 var args = Array.prototype.slice.call(arguments, 2);
13073 args.unshift(value);
13075 return /** eval:var:value */ eval(fn).apply(window, args);
13077 /** eval:var:value */
13078 return /** eval:var:value */ eval(fn).call(window, value);
13084 * safer version of Math.toFixed..??/
13085 * @param {Number/String} value The numeric value to format
13086 * @param {Number/String} value Decimal places
13087 * @return {String} The formatted currency string
13089 toFixed : function(v, n)
13091 // why not use to fixed - precision is buggered???
13093 return Math.round(v-0);
13095 var fact = Math.pow(10,n+1);
13096 v = (Math.round((v-0)*fact))/fact;
13097 var z = (''+fact).substring(2);
13098 if (v == Math.floor(v)) {
13099 return Math.floor(v) + '.' + z;
13102 // now just padd decimals..
13103 var ps = String(v).split('.');
13104 var fd = (ps[1] + z);
13105 var r = fd.substring(0,n);
13106 var rm = fd.substring(n);
13108 return ps[0] + '.' + r;
13110 r*=1; // turn it into a number;
13112 if (String(r).length != n) {
13115 r = String(r).substring(1); // chop the end off.
13118 return ps[0] + '.' + r;
13123 * Format a number as US currency
13124 * @param {Number/String} value The numeric value to format
13125 * @return {String} The formatted currency string
13127 usMoney : function(v){
13128 v = (Math.round((v-0)*100))/100;
13129 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13131 var ps = v.split('.');
13133 var sub = ps[1] ? '.'+ ps[1] : '.00';
13134 var r = /(\d+)(\d{3})/;
13135 while (r.test(whole)) {
13136 whole = whole.replace(r, '$1' + ',' + '$2');
13138 return "$" + whole + sub ;
13142 * Parse a value into a formatted date using the specified format pattern.
13143 * @param {Mixed} value The value to format
13144 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13145 * @return {String} The formatted date string
13147 date : function(v, format){
13151 if(!(v instanceof Date)){
13152 v = new Date(Date.parse(v));
13154 return v.dateFormat(format || "m/d/Y");
13158 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13159 * @param {String} format Any valid date format string
13160 * @return {Function} The date formatting function
13162 dateRenderer : function(format){
13163 return function(v){
13164 return Roo.util.Format.date(v, format);
13169 stripTagsRE : /<\/?[^>]+>/gi,
13172 * Strips all HTML tags
13173 * @param {Mixed} value The text from which to strip tags
13174 * @return {String} The stripped text
13176 stripTags : function(v){
13177 return !v ? v : String(v).replace(this.stripTagsRE, "");
13182 * Ext JS Library 1.1.1
13183 * Copyright(c) 2006-2007, Ext JS, LLC.
13185 * Originally Released Under LGPL - original licence link has changed is not relivant.
13188 * <script type="text/javascript">
13195 * @class Roo.MasterTemplate
13196 * @extends Roo.Template
13197 * Provides a template that can have child templates. The syntax is:
13199 var t = new Roo.MasterTemplate(
13200 '<select name="{name}">',
13201 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13204 t.add('options', {value: 'foo', text: 'bar'});
13205 // or you can add multiple child elements in one shot
13206 t.addAll('options', [
13207 {value: 'foo', text: 'bar'},
13208 {value: 'foo2', text: 'bar2'},
13209 {value: 'foo3', text: 'bar3'}
13211 // then append, applying the master template values
13212 t.append('my-form', {name: 'my-select'});
13214 * A name attribute for the child template is not required if you have only one child
13215 * template or you want to refer to them by index.
13217 Roo.MasterTemplate = function(){
13218 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13219 this.originalHtml = this.html;
13221 var m, re = this.subTemplateRe;
13224 while(m = re.exec(this.html)){
13225 var name = m[1], content = m[2];
13230 tpl : new Roo.Template(content)
13233 st[name] = st[subIndex];
13235 st[subIndex].tpl.compile();
13236 st[subIndex].tpl.call = this.call.createDelegate(this);
13239 this.subCount = subIndex;
13242 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13244 * The regular expression used to match sub templates
13248 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13251 * Applies the passed values to a child template.
13252 * @param {String/Number} name (optional) The name or index of the child template
13253 * @param {Array/Object} values The values to be applied to the template
13254 * @return {MasterTemplate} this
13256 add : function(name, values){
13257 if(arguments.length == 1){
13258 values = arguments[0];
13261 var s = this.subs[name];
13262 s.buffer[s.buffer.length] = s.tpl.apply(values);
13267 * Applies all the passed values to a child template.
13268 * @param {String/Number} name (optional) The name or index of the child template
13269 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13270 * @param {Boolean} reset (optional) True to reset the template first
13271 * @return {MasterTemplate} this
13273 fill : function(name, values, reset){
13275 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13283 for(var i = 0, len = values.length; i < len; i++){
13284 this.add(name, values[i]);
13290 * Resets the template for reuse
13291 * @return {MasterTemplate} this
13293 reset : function(){
13295 for(var i = 0; i < this.subCount; i++){
13301 applyTemplate : function(values){
13303 var replaceIndex = -1;
13304 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13305 return s[++replaceIndex].buffer.join("");
13307 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13310 apply : function(){
13311 return this.applyTemplate.apply(this, arguments);
13314 compile : function(){return this;}
13318 * Alias for fill().
13321 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13323 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13324 * var tpl = Roo.MasterTemplate.from('element-id');
13325 * @param {String/HTMLElement} el
13326 * @param {Object} config
13329 Roo.MasterTemplate.from = function(el, config){
13330 el = Roo.getDom(el);
13331 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13334 * Ext JS Library 1.1.1
13335 * Copyright(c) 2006-2007, Ext JS, LLC.
13337 * Originally Released Under LGPL - original licence link has changed is not relivant.
13340 * <script type="text/javascript">
13345 * @class Roo.util.CSS
13346 * Utility class for manipulating CSS rules
13349 Roo.util.CSS = function(){
13351 var doc = document;
13353 var camelRe = /(-[a-z])/gi;
13354 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13358 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13359 * tag and appended to the HEAD of the document.
13360 * @param {String|Object} cssText The text containing the css rules
13361 * @param {String} id An id to add to the stylesheet for later removal
13362 * @return {StyleSheet}
13364 createStyleSheet : function(cssText, id){
13366 var head = doc.getElementsByTagName("head")[0];
13367 var nrules = doc.createElement("style");
13368 nrules.setAttribute("type", "text/css");
13370 nrules.setAttribute("id", id);
13372 if (typeof(cssText) != 'string') {
13373 // support object maps..
13374 // not sure if this a good idea..
13375 // perhaps it should be merged with the general css handling
13376 // and handle js style props.
13377 var cssTextNew = [];
13378 for(var n in cssText) {
13380 for(var k in cssText[n]) {
13381 citems.push( k + ' : ' +cssText[n][k] + ';' );
13383 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13386 cssText = cssTextNew.join("\n");
13392 head.appendChild(nrules);
13393 ss = nrules.styleSheet;
13394 ss.cssText = cssText;
13397 nrules.appendChild(doc.createTextNode(cssText));
13399 nrules.cssText = cssText;
13401 head.appendChild(nrules);
13402 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13404 this.cacheStyleSheet(ss);
13409 * Removes a style or link tag by id
13410 * @param {String} id The id of the tag
13412 removeStyleSheet : function(id){
13413 var existing = doc.getElementById(id);
13415 existing.parentNode.removeChild(existing);
13420 * Dynamically swaps an existing stylesheet reference for a new one
13421 * @param {String} id The id of an existing link tag to remove
13422 * @param {String} url The href of the new stylesheet to include
13424 swapStyleSheet : function(id, url){
13425 this.removeStyleSheet(id);
13426 var ss = doc.createElement("link");
13427 ss.setAttribute("rel", "stylesheet");
13428 ss.setAttribute("type", "text/css");
13429 ss.setAttribute("id", id);
13430 ss.setAttribute("href", url);
13431 doc.getElementsByTagName("head")[0].appendChild(ss);
13435 * Refresh the rule cache if you have dynamically added stylesheets
13436 * @return {Object} An object (hash) of rules indexed by selector
13438 refreshCache : function(){
13439 return this.getRules(true);
13443 cacheStyleSheet : function(stylesheet){
13447 try{// try catch for cross domain access issue
13448 var ssRules = stylesheet.cssRules || stylesheet.rules;
13449 for(var j = ssRules.length-1; j >= 0; --j){
13450 rules[ssRules[j].selectorText] = ssRules[j];
13456 * Gets all css rules for the document
13457 * @param {Boolean} refreshCache true to refresh the internal cache
13458 * @return {Object} An object (hash) of rules indexed by selector
13460 getRules : function(refreshCache){
13461 if(rules == null || refreshCache){
13463 var ds = doc.styleSheets;
13464 for(var i =0, len = ds.length; i < len; i++){
13466 this.cacheStyleSheet(ds[i]);
13474 * Gets an an individual CSS rule by selector(s)
13475 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13476 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13477 * @return {CSSRule} The CSS rule or null if one is not found
13479 getRule : function(selector, refreshCache){
13480 var rs = this.getRules(refreshCache);
13481 if(!(selector instanceof Array)){
13482 return rs[selector];
13484 for(var i = 0; i < selector.length; i++){
13485 if(rs[selector[i]]){
13486 return rs[selector[i]];
13494 * Updates a rule property
13495 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13496 * @param {String} property The css property
13497 * @param {String} value The new value for the property
13498 * @return {Boolean} true If a rule was found and updated
13500 updateRule : function(selector, property, value){
13501 if(!(selector instanceof Array)){
13502 var rule = this.getRule(selector);
13504 rule.style[property.replace(camelRe, camelFn)] = value;
13508 for(var i = 0; i < selector.length; i++){
13509 if(this.updateRule(selector[i], property, value)){
13519 * Ext JS Library 1.1.1
13520 * Copyright(c) 2006-2007, Ext JS, LLC.
13522 * Originally Released Under LGPL - original licence link has changed is not relivant.
13525 * <script type="text/javascript">
13531 * @class Roo.util.ClickRepeater
13532 * @extends Roo.util.Observable
13534 * A wrapper class which can be applied to any element. Fires a "click" event while the
13535 * mouse is pressed. The interval between firings may be specified in the config but
13536 * defaults to 10 milliseconds.
13538 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13540 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13541 * @cfg {Number} delay The initial delay before the repeating event begins firing.
13542 * Similar to an autorepeat key delay.
13543 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
13544 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13545 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13546 * "interval" and "delay" are ignored. "immediate" is honored.
13547 * @cfg {Boolean} preventDefault True to prevent the default click event
13548 * @cfg {Boolean} stopDefault True to stop the default click event
13551 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
13552 * 2007-02-02 jvs Renamed to ClickRepeater
13553 * 2007-02-03 jvs Modifications for FF Mac and Safari
13556 * @param {String/HTMLElement/Element} el The element to listen on
13557 * @param {Object} config
13559 Roo.util.ClickRepeater = function(el, config)
13561 this.el = Roo.get(el);
13562 this.el.unselectable();
13564 Roo.apply(this, config);
13569 * Fires when the mouse button is depressed.
13570 * @param {Roo.util.ClickRepeater} this
13572 "mousedown" : true,
13575 * Fires on a specified interval during the time the element is pressed.
13576 * @param {Roo.util.ClickRepeater} this
13581 * Fires when the mouse key is released.
13582 * @param {Roo.util.ClickRepeater} this
13587 this.el.on("mousedown", this.handleMouseDown, this);
13588 if(this.preventDefault || this.stopDefault){
13589 this.el.on("click", function(e){
13590 if(this.preventDefault){
13591 e.preventDefault();
13593 if(this.stopDefault){
13599 // allow inline handler
13601 this.on("click", this.handler, this.scope || this);
13604 Roo.util.ClickRepeater.superclass.constructor.call(this);
13607 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
13610 preventDefault : true,
13611 stopDefault : false,
13615 handleMouseDown : function(){
13616 clearTimeout(this.timer);
13618 if(this.pressClass){
13619 this.el.addClass(this.pressClass);
13621 this.mousedownTime = new Date();
13623 Roo.get(document).on("mouseup", this.handleMouseUp, this);
13624 this.el.on("mouseout", this.handleMouseOut, this);
13626 this.fireEvent("mousedown", this);
13627 this.fireEvent("click", this);
13629 this.timer = this.click.defer(this.delay || this.interval, this);
13633 click : function(){
13634 this.fireEvent("click", this);
13635 this.timer = this.click.defer(this.getInterval(), this);
13639 getInterval: function(){
13640 if(!this.accelerate){
13641 return this.interval;
13643 var pressTime = this.mousedownTime.getElapsed();
13644 if(pressTime < 500){
13646 }else if(pressTime < 1700){
13648 }else if(pressTime < 2600){
13650 }else if(pressTime < 3500){
13652 }else if(pressTime < 4400){
13654 }else if(pressTime < 5300){
13656 }else if(pressTime < 6200){
13664 handleMouseOut : function(){
13665 clearTimeout(this.timer);
13666 if(this.pressClass){
13667 this.el.removeClass(this.pressClass);
13669 this.el.on("mouseover", this.handleMouseReturn, this);
13673 handleMouseReturn : function(){
13674 this.el.un("mouseover", this.handleMouseReturn);
13675 if(this.pressClass){
13676 this.el.addClass(this.pressClass);
13682 handleMouseUp : function(){
13683 clearTimeout(this.timer);
13684 this.el.un("mouseover", this.handleMouseReturn);
13685 this.el.un("mouseout", this.handleMouseOut);
13686 Roo.get(document).un("mouseup", this.handleMouseUp);
13687 this.el.removeClass(this.pressClass);
13688 this.fireEvent("mouseup", this);
13692 * Ext JS Library 1.1.1
13693 * Copyright(c) 2006-2007, Ext JS, LLC.
13695 * Originally Released Under LGPL - original licence link has changed is not relivant.
13698 * <script type="text/javascript">
13703 * @class Roo.KeyNav
13704 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13705 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13706 * way to implement custom navigation schemes for any UI component.</p>
13707 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13708 * pageUp, pageDown, del, home, end. Usage:</p>
13710 var nav = new Roo.KeyNav("my-element", {
13711 "left" : function(e){
13712 this.moveLeft(e.ctrlKey);
13714 "right" : function(e){
13715 this.moveRight(e.ctrlKey);
13717 "enter" : function(e){
13724 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13725 * @param {Object} config The config
13727 Roo.KeyNav = function(el, config){
13728 this.el = Roo.get(el);
13729 Roo.apply(this, config);
13730 if(!this.disabled){
13731 this.disabled = true;
13736 Roo.KeyNav.prototype = {
13738 * @cfg {Boolean} disabled
13739 * True to disable this KeyNav instance (defaults to false)
13743 * @cfg {String} defaultEventAction
13744 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
13745 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
13746 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
13748 defaultEventAction: "stopEvent",
13750 * @cfg {Boolean} forceKeyDown
13751 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13752 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13753 * handle keydown instead of keypress.
13755 forceKeyDown : false,
13758 prepareEvent : function(e){
13759 var k = e.getKey();
13760 var h = this.keyToHandler[k];
13761 //if(h && this[h]){
13762 // e.stopPropagation();
13764 if(Roo.isSafari && h && k >= 37 && k <= 40){
13770 relay : function(e){
13771 var k = e.getKey();
13772 var h = this.keyToHandler[k];
13774 if(this.doRelay(e, this[h], h) !== true){
13775 e[this.defaultEventAction]();
13781 doRelay : function(e, h, hname){
13782 return h.call(this.scope || this, e);
13785 // possible handlers
13799 // quick lookup hash
13816 * Enable this KeyNav
13818 enable: function(){
13820 // ie won't do special keys on keypress, no one else will repeat keys with keydown
13821 // the EventObject will normalize Safari automatically
13822 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13823 this.el.on("keydown", this.relay, this);
13825 this.el.on("keydown", this.prepareEvent, this);
13826 this.el.on("keypress", this.relay, this);
13828 this.disabled = false;
13833 * Disable this KeyNav
13835 disable: function(){
13836 if(!this.disabled){
13837 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
13838 this.el.un("keydown", this.relay);
13840 this.el.un("keydown", this.prepareEvent);
13841 this.el.un("keypress", this.relay);
13843 this.disabled = true;
13848 * Ext JS Library 1.1.1
13849 * Copyright(c) 2006-2007, Ext JS, LLC.
13851 * Originally Released Under LGPL - original licence link has changed is not relivant.
13854 * <script type="text/javascript">
13859 * @class Roo.KeyMap
13860 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
13861 * The constructor accepts the same config object as defined by {@link #addBinding}.
13862 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
13863 * combination it will call the function with this signature (if the match is a multi-key
13864 * combination the callback will still be called only once): (String key, Roo.EventObject e)
13865 * A KeyMap can also handle a string representation of keys.<br />
13868 // map one key by key code
13869 var map = new Roo.KeyMap("my-element", {
13870 key: 13, // or Roo.EventObject.ENTER
13875 // map multiple keys to one action by string
13876 var map = new Roo.KeyMap("my-element", {
13882 // map multiple keys to multiple actions by strings and array of codes
13883 var map = new Roo.KeyMap("my-element", [
13886 fn: function(){ alert("Return was pressed"); }
13889 fn: function(){ alert('a, b or c was pressed'); }
13894 fn: function(){ alert('Control + shift + tab was pressed.'); }
13898 * <b>Note: A KeyMap starts enabled</b>
13900 * @param {String/HTMLElement/Roo.Element} el The element to bind to
13901 * @param {Object} config The config (see {@link #addBinding})
13902 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
13904 Roo.KeyMap = function(el, config, eventName){
13905 this.el = Roo.get(el);
13906 this.eventName = eventName || "keydown";
13907 this.bindings = [];
13909 this.addBinding(config);
13914 Roo.KeyMap.prototype = {
13916 * True to stop the event from bubbling and prevent the default browser action if the
13917 * key was handled by the KeyMap (defaults to false)
13923 * Add a new binding to this KeyMap. The following config object properties are supported:
13925 Property Type Description
13926 ---------- --------------- ----------------------------------------------------------------------
13927 key String/Array A single keycode or an array of keycodes to handle
13928 shift Boolean True to handle key only when shift is pressed (defaults to false)
13929 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
13930 alt Boolean True to handle key only when alt is pressed (defaults to false)
13931 fn Function The function to call when KeyMap finds the expected key combination
13932 scope Object The scope of the callback function
13938 var map = new Roo.KeyMap(document, {
13939 key: Roo.EventObject.ENTER,
13944 //Add a new binding to the existing KeyMap later
13952 * @param {Object/Array} config A single KeyMap config or an array of configs
13954 addBinding : function(config){
13955 if(config instanceof Array){
13956 for(var i = 0, len = config.length; i < len; i++){
13957 this.addBinding(config[i]);
13961 var keyCode = config.key,
13962 shift = config.shift,
13963 ctrl = config.ctrl,
13966 scope = config.scope;
13967 if(typeof keyCode == "string"){
13969 var keyString = keyCode.toUpperCase();
13970 for(var j = 0, len = keyString.length; j < len; j++){
13971 ks.push(keyString.charCodeAt(j));
13975 var keyArray = keyCode instanceof Array;
13976 var handler = function(e){
13977 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
13978 var k = e.getKey();
13980 for(var i = 0, len = keyCode.length; i < len; i++){
13981 if(keyCode[i] == k){
13982 if(this.stopEvent){
13985 fn.call(scope || window, k, e);
13991 if(this.stopEvent){
13994 fn.call(scope || window, k, e);
13999 this.bindings.push(handler);
14003 * Shorthand for adding a single key listener
14004 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14005 * following options:
14006 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14007 * @param {Function} fn The function to call
14008 * @param {Object} scope (optional) The scope of the function
14010 on : function(key, fn, scope){
14011 var keyCode, shift, ctrl, alt;
14012 if(typeof key == "object" && !(key instanceof Array)){
14031 handleKeyDown : function(e){
14032 if(this.enabled){ //just in case
14033 var b = this.bindings;
14034 for(var i = 0, len = b.length; i < len; i++){
14035 b[i].call(this, e);
14041 * Returns true if this KeyMap is enabled
14042 * @return {Boolean}
14044 isEnabled : function(){
14045 return this.enabled;
14049 * Enables this KeyMap
14051 enable: function(){
14053 this.el.on(this.eventName, this.handleKeyDown, this);
14054 this.enabled = true;
14059 * Disable this KeyMap
14061 disable: function(){
14063 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14064 this.enabled = false;
14069 * Ext JS Library 1.1.1
14070 * Copyright(c) 2006-2007, Ext JS, LLC.
14072 * Originally Released Under LGPL - original licence link has changed is not relivant.
14075 * <script type="text/javascript">
14080 * @class Roo.util.TextMetrics
14081 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14082 * wide, in pixels, a given block of text will be.
14085 Roo.util.TextMetrics = function(){
14089 * Measures the size of the specified text
14090 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14091 * that can affect the size of the rendered text
14092 * @param {String} text The text to measure
14093 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14094 * in order to accurately measure the text height
14095 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14097 measure : function(el, text, fixedWidth){
14099 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14102 shared.setFixedWidth(fixedWidth || 'auto');
14103 return shared.getSize(text);
14107 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14108 * the overhead of multiple calls to initialize the style properties on each measurement.
14109 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14110 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14111 * in order to accurately measure the text height
14112 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14114 createInstance : function(el, fixedWidth){
14115 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14122 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14123 var ml = new Roo.Element(document.createElement('div'));
14124 document.body.appendChild(ml.dom);
14125 ml.position('absolute');
14126 ml.setLeftTop(-1000, -1000);
14130 ml.setWidth(fixedWidth);
14135 * Returns the size of the specified text based on the internal element's style and width properties
14136 * @memberOf Roo.util.TextMetrics.Instance#
14137 * @param {String} text The text to measure
14138 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14140 getSize : function(text){
14142 var s = ml.getSize();
14148 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14149 * that can affect the size of the rendered text
14150 * @memberOf Roo.util.TextMetrics.Instance#
14151 * @param {String/HTMLElement} el The element, dom node or id
14153 bind : function(el){
14155 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14160 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14161 * to set a fixed width in order to accurately measure the text height.
14162 * @memberOf Roo.util.TextMetrics.Instance#
14163 * @param {Number} width The width to set on the element
14165 setFixedWidth : function(width){
14166 ml.setWidth(width);
14170 * Returns the measured width of the specified text
14171 * @memberOf Roo.util.TextMetrics.Instance#
14172 * @param {String} text The text to measure
14173 * @return {Number} width The width in pixels
14175 getWidth : function(text){
14176 ml.dom.style.width = 'auto';
14177 return this.getSize(text).width;
14181 * Returns the measured height of the specified text. For multiline text, be sure to call
14182 * {@link #setFixedWidth} if necessary.
14183 * @memberOf Roo.util.TextMetrics.Instance#
14184 * @param {String} text The text to measure
14185 * @return {Number} height The height in pixels
14187 getHeight : function(text){
14188 return this.getSize(text).height;
14192 instance.bind(bindTo);
14197 // backwards compat
14198 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14200 * Ext JS Library 1.1.1
14201 * Copyright(c) 2006-2007, Ext JS, LLC.
14203 * Originally Released Under LGPL - original licence link has changed is not relivant.
14206 * <script type="text/javascript">
14210 * @class Roo.state.Provider
14211 * Abstract base class for state provider implementations. This class provides methods
14212 * for encoding and decoding <b>typed</b> variables including dates and defines the
14213 * Provider interface.
14215 Roo.state.Provider = function(){
14217 * @event statechange
14218 * Fires when a state change occurs.
14219 * @param {Provider} this This state provider
14220 * @param {String} key The state key which was changed
14221 * @param {String} value The encoded value for the state
14224 "statechange": true
14227 Roo.state.Provider.superclass.constructor.call(this);
14229 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14231 * Returns the current value for a key
14232 * @param {String} name The key name
14233 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14234 * @return {Mixed} The state data
14236 get : function(name, defaultValue){
14237 return typeof this.state[name] == "undefined" ?
14238 defaultValue : this.state[name];
14242 * Clears a value from the state
14243 * @param {String} name The key name
14245 clear : function(name){
14246 delete this.state[name];
14247 this.fireEvent("statechange", this, name, null);
14251 * Sets the value for a key
14252 * @param {String} name The key name
14253 * @param {Mixed} value The value to set
14255 set : function(name, value){
14256 this.state[name] = value;
14257 this.fireEvent("statechange", this, name, value);
14261 * Decodes a string previously encoded with {@link #encodeValue}.
14262 * @param {String} value The value to decode
14263 * @return {Mixed} The decoded value
14265 decodeValue : function(cookie){
14266 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14267 var matches = re.exec(unescape(cookie));
14268 if(!matches || !matches[1]) return; // non state cookie
14269 var type = matches[1];
14270 var v = matches[2];
14273 return parseFloat(v);
14275 return new Date(Date.parse(v));
14280 var values = v.split("^");
14281 for(var i = 0, len = values.length; i < len; i++){
14282 all.push(this.decodeValue(values[i]));
14287 var values = v.split("^");
14288 for(var i = 0, len = values.length; i < len; i++){
14289 var kv = values[i].split("=");
14290 all[kv[0]] = this.decodeValue(kv[1]);
14299 * Encodes a value including type information. Decode with {@link #decodeValue}.
14300 * @param {Mixed} value The value to encode
14301 * @return {String} The encoded value
14303 encodeValue : function(v){
14305 if(typeof v == "number"){
14307 }else if(typeof v == "boolean"){
14308 enc = "b:" + (v ? "1" : "0");
14309 }else if(v instanceof Date){
14310 enc = "d:" + v.toGMTString();
14311 }else if(v instanceof Array){
14313 for(var i = 0, len = v.length; i < len; i++){
14314 flat += this.encodeValue(v[i]);
14315 if(i != len-1) flat += "^";
14318 }else if(typeof v == "object"){
14321 if(typeof v[key] != "function"){
14322 flat += key + "=" + this.encodeValue(v[key]) + "^";
14325 enc = "o:" + flat.substring(0, flat.length-1);
14329 return escape(enc);
14335 * Ext JS Library 1.1.1
14336 * Copyright(c) 2006-2007, Ext JS, LLC.
14338 * Originally Released Under LGPL - original licence link has changed is not relivant.
14341 * <script type="text/javascript">
14344 * @class Roo.state.Manager
14345 * This is the global state manager. By default all components that are "state aware" check this class
14346 * for state information if you don't pass them a custom state provider. In order for this class
14347 * to be useful, it must be initialized with a provider when your application initializes.
14349 // in your initialization function
14351 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14353 // supposed you have a {@link Roo.BorderLayout}
14354 var layout = new Roo.BorderLayout(...);
14355 layout.restoreState();
14356 // or a {Roo.BasicDialog}
14357 var dialog = new Roo.BasicDialog(...);
14358 dialog.restoreState();
14362 Roo.state.Manager = function(){
14363 var provider = new Roo.state.Provider();
14367 * Configures the default state provider for your application
14368 * @param {Provider} stateProvider The state provider to set
14370 setProvider : function(stateProvider){
14371 provider = stateProvider;
14375 * Returns the current value for a key
14376 * @param {String} name The key name
14377 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14378 * @return {Mixed} The state data
14380 get : function(key, defaultValue){
14381 return provider.get(key, defaultValue);
14385 * Sets the value for a key
14386 * @param {String} name The key name
14387 * @param {Mixed} value The state data
14389 set : function(key, value){
14390 provider.set(key, value);
14394 * Clears a value from the state
14395 * @param {String} name The key name
14397 clear : function(key){
14398 provider.clear(key);
14402 * Gets the currently configured state provider
14403 * @return {Provider} The state provider
14405 getProvider : function(){
14412 * Ext JS Library 1.1.1
14413 * Copyright(c) 2006-2007, Ext JS, LLC.
14415 * Originally Released Under LGPL - original licence link has changed is not relivant.
14418 * <script type="text/javascript">
14421 * @class Roo.state.CookieProvider
14422 * @extends Roo.state.Provider
14423 * The default Provider implementation which saves state via cookies.
14426 var cp = new Roo.state.CookieProvider({
14428 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14429 domain: "roojs.com"
14431 Roo.state.Manager.setProvider(cp);
14433 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14434 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14435 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14436 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14437 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14438 * domain the page is running on including the 'www' like 'www.roojs.com')
14439 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14441 * Create a new CookieProvider
14442 * @param {Object} config The configuration object
14444 Roo.state.CookieProvider = function(config){
14445 Roo.state.CookieProvider.superclass.constructor.call(this);
14447 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14448 this.domain = null;
14449 this.secure = false;
14450 Roo.apply(this, config);
14451 this.state = this.readCookies();
14454 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14456 set : function(name, value){
14457 if(typeof value == "undefined" || value === null){
14461 this.setCookie(name, value);
14462 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14466 clear : function(name){
14467 this.clearCookie(name);
14468 Roo.state.CookieProvider.superclass.clear.call(this, name);
14472 readCookies : function(){
14474 var c = document.cookie + ";";
14475 var re = /\s?(.*?)=(.*?);/g;
14477 while((matches = re.exec(c)) != null){
14478 var name = matches[1];
14479 var value = matches[2];
14480 if(name && name.substring(0,3) == "ys-"){
14481 cookies[name.substr(3)] = this.decodeValue(value);
14488 setCookie : function(name, value){
14489 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14490 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14491 ((this.path == null) ? "" : ("; path=" + this.path)) +
14492 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14493 ((this.secure == true) ? "; secure" : "");
14497 clearCookie : function(name){
14498 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14499 ((this.path == null) ? "" : ("; path=" + this.path)) +
14500 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14501 ((this.secure == true) ? "; secure" : "");
14505 * Ext JS Library 1.1.1
14506 * Copyright(c) 2006-2007, Ext JS, LLC.
14508 * Originally Released Under LGPL - original licence link has changed is not relivant.
14511 * <script type="text/javascript">
14517 * These classes are derivatives of the similarly named classes in the YUI Library.
14518 * The original license:
14519 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
14520 * Code licensed under the BSD License:
14521 * http://developer.yahoo.net/yui/license.txt
14526 var Event=Roo.EventManager;
14527 var Dom=Roo.lib.Dom;
14530 * @class Roo.dd.DragDrop
14531 * @extends Roo.util.Observable
14532 * Defines the interface and base operation of items that that can be
14533 * dragged or can be drop targets. It was designed to be extended, overriding
14534 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
14535 * Up to three html elements can be associated with a DragDrop instance:
14537 * <li>linked element: the element that is passed into the constructor.
14538 * This is the element which defines the boundaries for interaction with
14539 * other DragDrop objects.</li>
14540 * <li>handle element(s): The drag operation only occurs if the element that
14541 * was clicked matches a handle element. By default this is the linked
14542 * element, but there are times that you will want only a portion of the
14543 * linked element to initiate the drag operation, and the setHandleElId()
14544 * method provides a way to define this.</li>
14545 * <li>drag element: this represents the element that would be moved along
14546 * with the cursor during a drag operation. By default, this is the linked
14547 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
14548 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
14551 * This class should not be instantiated until the onload event to ensure that
14552 * the associated elements are available.
14553 * The following would define a DragDrop obj that would interact with any
14554 * other DragDrop obj in the "group1" group:
14556 * dd = new Roo.dd.DragDrop("div1", "group1");
14558 * Since none of the event handlers have been implemented, nothing would
14559 * actually happen if you were to run the code above. Normally you would
14560 * override this class or one of the default implementations, but you can
14561 * also override the methods you want on an instance of the class...
14563 * dd.onDragDrop = function(e, id) {
14564 * alert("dd was dropped on " + id);
14568 * @param {String} id of the element that is linked to this instance
14569 * @param {String} sGroup the group of related DragDrop objects
14570 * @param {object} config an object containing configurable attributes
14571 * Valid properties for DragDrop:
14572 * padding, isTarget, maintainOffset, primaryButtonOnly
14574 Roo.dd.DragDrop = function(id, sGroup, config) {
14576 this.init(id, sGroup, config);
14581 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
14584 * The id of the element associated with this object. This is what we
14585 * refer to as the "linked element" because the size and position of
14586 * this element is used to determine when the drag and drop objects have
14594 * Configuration attributes passed into the constructor
14601 * The id of the element that will be dragged. By default this is same
14602 * as the linked element , but could be changed to another element. Ex:
14604 * @property dragElId
14611 * the id of the element that initiates the drag operation. By default
14612 * this is the linked element, but could be changed to be a child of this
14613 * element. This lets us do things like only starting the drag when the
14614 * header element within the linked html element is clicked.
14615 * @property handleElId
14622 * An associative array of HTML tags that will be ignored if clicked.
14623 * @property invalidHandleTypes
14624 * @type {string: string}
14626 invalidHandleTypes: null,
14629 * An associative array of ids for elements that will be ignored if clicked
14630 * @property invalidHandleIds
14631 * @type {string: string}
14633 invalidHandleIds: null,
14636 * An indexted array of css class names for elements that will be ignored
14638 * @property invalidHandleClasses
14641 invalidHandleClasses: null,
14644 * The linked element's absolute X position at the time the drag was
14646 * @property startPageX
14653 * The linked element's absolute X position at the time the drag was
14655 * @property startPageY
14662 * The group defines a logical collection of DragDrop objects that are
14663 * related. Instances only get events when interacting with other
14664 * DragDrop object in the same group. This lets us define multiple
14665 * groups using a single DragDrop subclass if we want.
14667 * @type {string: string}
14672 * Individual drag/drop instances can be locked. This will prevent
14673 * onmousedown start drag.
14681 * Lock this instance
14684 lock: function() { this.locked = true; },
14687 * Unlock this instace
14690 unlock: function() { this.locked = false; },
14693 * By default, all insances can be a drop target. This can be disabled by
14694 * setting isTarget to false.
14701 * The padding configured for this drag and drop object for calculating
14702 * the drop zone intersection with this object.
14709 * Cached reference to the linked element
14710 * @property _domRef
14716 * Internal typeof flag
14717 * @property __ygDragDrop
14720 __ygDragDrop: true,
14723 * Set to true when horizontal contraints are applied
14724 * @property constrainX
14731 * Set to true when vertical contraints are applied
14732 * @property constrainY
14739 * The left constraint
14747 * The right constraint
14755 * The up constraint
14764 * The down constraint
14772 * Maintain offsets when we resetconstraints. Set to true when you want
14773 * the position of the element relative to its parent to stay the same
14774 * when the page changes
14776 * @property maintainOffset
14779 maintainOffset: false,
14782 * Array of pixel locations the element will snap to if we specified a
14783 * horizontal graduation/interval. This array is generated automatically
14784 * when you define a tick interval.
14791 * Array of pixel locations the element will snap to if we specified a
14792 * vertical graduation/interval. This array is generated automatically
14793 * when you define a tick interval.
14800 * By default the drag and drop instance will only respond to the primary
14801 * button click (left button for a right-handed mouse). Set to true to
14802 * allow drag and drop to start with any mouse click that is propogated
14804 * @property primaryButtonOnly
14807 primaryButtonOnly: true,
14810 * The availabe property is false until the linked dom element is accessible.
14811 * @property available
14817 * By default, drags can only be initiated if the mousedown occurs in the
14818 * region the linked element is. This is done in part to work around a
14819 * bug in some browsers that mis-report the mousedown if the previous
14820 * mouseup happened outside of the window. This property is set to true
14821 * if outer handles are defined.
14823 * @property hasOuterHandles
14827 hasOuterHandles: false,
14830 * Code that executes immediately before the startDrag event
14831 * @method b4StartDrag
14834 b4StartDrag: function(x, y) { },
14837 * Abstract method called after a drag/drop object is clicked
14838 * and the drag or mousedown time thresholds have beeen met.
14839 * @method startDrag
14840 * @param {int} X click location
14841 * @param {int} Y click location
14843 startDrag: function(x, y) { /* override this */ },
14846 * Code that executes immediately before the onDrag event
14850 b4Drag: function(e) { },
14853 * Abstract method called during the onMouseMove event while dragging an
14856 * @param {Event} e the mousemove event
14858 onDrag: function(e) { /* override this */ },
14861 * Abstract method called when this element fist begins hovering over
14862 * another DragDrop obj
14863 * @method onDragEnter
14864 * @param {Event} e the mousemove event
14865 * @param {String|DragDrop[]} id In POINT mode, the element
14866 * id this is hovering over. In INTERSECT mode, an array of one or more
14867 * dragdrop items being hovered over.
14869 onDragEnter: function(e, id) { /* override this */ },
14872 * Code that executes immediately before the onDragOver event
14873 * @method b4DragOver
14876 b4DragOver: function(e) { },
14879 * Abstract method called when this element is hovering over another
14881 * @method onDragOver
14882 * @param {Event} e the mousemove event
14883 * @param {String|DragDrop[]} id In POINT mode, the element
14884 * id this is hovering over. In INTERSECT mode, an array of dd items
14885 * being hovered over.
14887 onDragOver: function(e, id) { /* override this */ },
14890 * Code that executes immediately before the onDragOut event
14891 * @method b4DragOut
14894 b4DragOut: function(e) { },
14897 * Abstract method called when we are no longer hovering over an element
14898 * @method onDragOut
14899 * @param {Event} e the mousemove event
14900 * @param {String|DragDrop[]} id In POINT mode, the element
14901 * id this was hovering over. In INTERSECT mode, an array of dd items
14902 * that the mouse is no longer over.
14904 onDragOut: function(e, id) { /* override this */ },
14907 * Code that executes immediately before the onDragDrop event
14908 * @method b4DragDrop
14911 b4DragDrop: function(e) { },
14914 * Abstract method called when this item is dropped on another DragDrop
14916 * @method onDragDrop
14917 * @param {Event} e the mouseup event
14918 * @param {String|DragDrop[]} id In POINT mode, the element
14919 * id this was dropped on. In INTERSECT mode, an array of dd items this
14922 onDragDrop: function(e, id) { /* override this */ },
14925 * Abstract method called when this item is dropped on an area with no
14927 * @method onInvalidDrop
14928 * @param {Event} e the mouseup event
14930 onInvalidDrop: function(e) { /* override this */ },
14933 * Code that executes immediately before the endDrag event
14934 * @method b4EndDrag
14937 b4EndDrag: function(e) { },
14940 * Fired when we are done dragging the object
14942 * @param {Event} e the mouseup event
14944 endDrag: function(e) { /* override this */ },
14947 * Code executed immediately before the onMouseDown event
14948 * @method b4MouseDown
14949 * @param {Event} e the mousedown event
14952 b4MouseDown: function(e) { },
14955 * Event handler that fires when a drag/drop obj gets a mousedown
14956 * @method onMouseDown
14957 * @param {Event} e the mousedown event
14959 onMouseDown: function(e) { /* override this */ },
14962 * Event handler that fires when a drag/drop obj gets a mouseup
14963 * @method onMouseUp
14964 * @param {Event} e the mouseup event
14966 onMouseUp: function(e) { /* override this */ },
14969 * Override the onAvailable method to do what is needed after the initial
14970 * position was determined.
14971 * @method onAvailable
14973 onAvailable: function () {
14977 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
14980 defaultPadding : {left:0, right:0, top:0, bottom:0},
14983 * Initializes the drag drop object's constraints to restrict movement to a certain element.
14987 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
14988 { dragElId: "existingProxyDiv" });
14989 dd.startDrag = function(){
14990 this.constrainTo("parent-id");
14993 * Or you can initalize it using the {@link Roo.Element} object:
14995 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
14996 startDrag : function(){
14997 this.constrainTo("parent-id");
15001 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15002 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15003 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15004 * an object containing the sides to pad. For example: {right:10, bottom:10}
15005 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15007 constrainTo : function(constrainTo, pad, inContent){
15008 if(typeof pad == "number"){
15009 pad = {left: pad, right:pad, top:pad, bottom:pad};
15011 pad = pad || this.defaultPadding;
15012 var b = Roo.get(this.getEl()).getBox();
15013 var ce = Roo.get(constrainTo);
15014 var s = ce.getScroll();
15015 var c, cd = ce.dom;
15016 if(cd == document.body){
15017 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15020 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15024 var topSpace = b.y - c.y;
15025 var leftSpace = b.x - c.x;
15027 this.resetConstraints();
15028 this.setXConstraint(leftSpace - (pad.left||0), // left
15029 c.width - leftSpace - b.width - (pad.right||0) //right
15031 this.setYConstraint(topSpace - (pad.top||0), //top
15032 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15037 * Returns a reference to the linked element
15039 * @return {HTMLElement} the html element
15041 getEl: function() {
15042 if (!this._domRef) {
15043 this._domRef = Roo.getDom(this.id);
15046 return this._domRef;
15050 * Returns a reference to the actual element to drag. By default this is
15051 * the same as the html element, but it can be assigned to another
15052 * element. An example of this can be found in Roo.dd.DDProxy
15053 * @method getDragEl
15054 * @return {HTMLElement} the html element
15056 getDragEl: function() {
15057 return Roo.getDom(this.dragElId);
15061 * Sets up the DragDrop object. Must be called in the constructor of any
15062 * Roo.dd.DragDrop subclass
15064 * @param id the id of the linked element
15065 * @param {String} sGroup the group of related items
15066 * @param {object} config configuration attributes
15068 init: function(id, sGroup, config) {
15069 this.initTarget(id, sGroup, config);
15070 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15071 // Event.on(this.id, "selectstart", Event.preventDefault);
15075 * Initializes Targeting functionality only... the object does not
15076 * get a mousedown handler.
15077 * @method initTarget
15078 * @param id the id of the linked element
15079 * @param {String} sGroup the group of related items
15080 * @param {object} config configuration attributes
15082 initTarget: function(id, sGroup, config) {
15084 // configuration attributes
15085 this.config = config || {};
15087 // create a local reference to the drag and drop manager
15088 this.DDM = Roo.dd.DDM;
15089 // initialize the groups array
15092 // assume that we have an element reference instead of an id if the
15093 // parameter is not a string
15094 if (typeof id !== "string") {
15101 // add to an interaction group
15102 this.addToGroup((sGroup) ? sGroup : "default");
15104 // We don't want to register this as the handle with the manager
15105 // so we just set the id rather than calling the setter.
15106 this.handleElId = id;
15108 // the linked element is the element that gets dragged by default
15109 this.setDragElId(id);
15111 // by default, clicked anchors will not start drag operations.
15112 this.invalidHandleTypes = { A: "A" };
15113 this.invalidHandleIds = {};
15114 this.invalidHandleClasses = [];
15116 this.applyConfig();
15118 this.handleOnAvailable();
15122 * Applies the configuration parameters that were passed into the constructor.
15123 * This is supposed to happen at each level through the inheritance chain. So
15124 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15125 * DragDrop in order to get all of the parameters that are available in
15127 * @method applyConfig
15129 applyConfig: function() {
15131 // configurable properties:
15132 // padding, isTarget, maintainOffset, primaryButtonOnly
15133 this.padding = this.config.padding || [0, 0, 0, 0];
15134 this.isTarget = (this.config.isTarget !== false);
15135 this.maintainOffset = (this.config.maintainOffset);
15136 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15141 * Executed when the linked element is available
15142 * @method handleOnAvailable
15145 handleOnAvailable: function() {
15146 this.available = true;
15147 this.resetConstraints();
15148 this.onAvailable();
15152 * Configures the padding for the target zone in px. Effectively expands
15153 * (or reduces) the virtual object size for targeting calculations.
15154 * Supports css-style shorthand; if only one parameter is passed, all sides
15155 * will have that padding, and if only two are passed, the top and bottom
15156 * will have the first param, the left and right the second.
15157 * @method setPadding
15158 * @param {int} iTop Top pad
15159 * @param {int} iRight Right pad
15160 * @param {int} iBot Bot pad
15161 * @param {int} iLeft Left pad
15163 setPadding: function(iTop, iRight, iBot, iLeft) {
15164 // this.padding = [iLeft, iRight, iTop, iBot];
15165 if (!iRight && 0 !== iRight) {
15166 this.padding = [iTop, iTop, iTop, iTop];
15167 } else if (!iBot && 0 !== iBot) {
15168 this.padding = [iTop, iRight, iTop, iRight];
15170 this.padding = [iTop, iRight, iBot, iLeft];
15175 * Stores the initial placement of the linked element.
15176 * @method setInitialPosition
15177 * @param {int} diffX the X offset, default 0
15178 * @param {int} diffY the Y offset, default 0
15180 setInitPosition: function(diffX, diffY) {
15181 var el = this.getEl();
15183 if (!this.DDM.verifyEl(el)) {
15187 var dx = diffX || 0;
15188 var dy = diffY || 0;
15190 var p = Dom.getXY( el );
15192 this.initPageX = p[0] - dx;
15193 this.initPageY = p[1] - dy;
15195 this.lastPageX = p[0];
15196 this.lastPageY = p[1];
15199 this.setStartPosition(p);
15203 * Sets the start position of the element. This is set when the obj
15204 * is initialized, the reset when a drag is started.
15205 * @method setStartPosition
15206 * @param pos current position (from previous lookup)
15209 setStartPosition: function(pos) {
15210 var p = pos || Dom.getXY( this.getEl() );
15211 this.deltaSetXY = null;
15213 this.startPageX = p[0];
15214 this.startPageY = p[1];
15218 * Add this instance to a group of related drag/drop objects. All
15219 * instances belong to at least one group, and can belong to as many
15220 * groups as needed.
15221 * @method addToGroup
15222 * @param sGroup {string} the name of the group
15224 addToGroup: function(sGroup) {
15225 this.groups[sGroup] = true;
15226 this.DDM.regDragDrop(this, sGroup);
15230 * Remove's this instance from the supplied interaction group
15231 * @method removeFromGroup
15232 * @param {string} sGroup The group to drop
15234 removeFromGroup: function(sGroup) {
15235 if (this.groups[sGroup]) {
15236 delete this.groups[sGroup];
15239 this.DDM.removeDDFromGroup(this, sGroup);
15243 * Allows you to specify that an element other than the linked element
15244 * will be moved with the cursor during a drag
15245 * @method setDragElId
15246 * @param id {string} the id of the element that will be used to initiate the drag
15248 setDragElId: function(id) {
15249 this.dragElId = id;
15253 * Allows you to specify a child of the linked element that should be
15254 * used to initiate the drag operation. An example of this would be if
15255 * you have a content div with text and links. Clicking anywhere in the
15256 * content area would normally start the drag operation. Use this method
15257 * to specify that an element inside of the content div is the element
15258 * that starts the drag operation.
15259 * @method setHandleElId
15260 * @param id {string} the id of the element that will be used to
15261 * initiate the drag.
15263 setHandleElId: function(id) {
15264 if (typeof id !== "string") {
15267 this.handleElId = id;
15268 this.DDM.regHandle(this.id, id);
15272 * Allows you to set an element outside of the linked element as a drag
15274 * @method setOuterHandleElId
15275 * @param id the id of the element that will be used to initiate the drag
15277 setOuterHandleElId: function(id) {
15278 if (typeof id !== "string") {
15281 Event.on(id, "mousedown",
15282 this.handleMouseDown, this);
15283 this.setHandleElId(id);
15285 this.hasOuterHandles = true;
15289 * Remove all drag and drop hooks for this element
15292 unreg: function() {
15293 Event.un(this.id, "mousedown",
15294 this.handleMouseDown);
15295 this._domRef = null;
15296 this.DDM._remove(this);
15299 destroy : function(){
15304 * Returns true if this instance is locked, or the drag drop mgr is locked
15305 * (meaning that all drag/drop is disabled on the page.)
15307 * @return {boolean} true if this obj or all drag/drop is locked, else
15310 isLocked: function() {
15311 return (this.DDM.isLocked() || this.locked);
15315 * Fired when this object is clicked
15316 * @method handleMouseDown
15318 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15321 handleMouseDown: function(e, oDD){
15322 if (this.primaryButtonOnly && e.button != 0) {
15326 if (this.isLocked()) {
15330 this.DDM.refreshCache(this.groups);
15332 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15333 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15335 if (this.clickValidator(e)) {
15337 // set the initial element position
15338 this.setStartPosition();
15341 this.b4MouseDown(e);
15342 this.onMouseDown(e);
15344 this.DDM.handleMouseDown(e, this);
15346 this.DDM.stopEvent(e);
15354 clickValidator: function(e) {
15355 var target = e.getTarget();
15356 return ( this.isValidHandleChild(target) &&
15357 (this.id == this.handleElId ||
15358 this.DDM.handleWasClicked(target, this.id)) );
15362 * Allows you to specify a tag name that should not start a drag operation
15363 * when clicked. This is designed to facilitate embedding links within a
15364 * drag handle that do something other than start the drag.
15365 * @method addInvalidHandleType
15366 * @param {string} tagName the type of element to exclude
15368 addInvalidHandleType: function(tagName) {
15369 var type = tagName.toUpperCase();
15370 this.invalidHandleTypes[type] = type;
15374 * Lets you to specify an element id for a child of a drag handle
15375 * that should not initiate a drag
15376 * @method addInvalidHandleId
15377 * @param {string} id the element id of the element you wish to ignore
15379 addInvalidHandleId: function(id) {
15380 if (typeof id !== "string") {
15383 this.invalidHandleIds[id] = id;
15387 * Lets you specify a css class of elements that will not initiate a drag
15388 * @method addInvalidHandleClass
15389 * @param {string} cssClass the class of the elements you wish to ignore
15391 addInvalidHandleClass: function(cssClass) {
15392 this.invalidHandleClasses.push(cssClass);
15396 * Unsets an excluded tag name set by addInvalidHandleType
15397 * @method removeInvalidHandleType
15398 * @param {string} tagName the type of element to unexclude
15400 removeInvalidHandleType: function(tagName) {
15401 var type = tagName.toUpperCase();
15402 // this.invalidHandleTypes[type] = null;
15403 delete this.invalidHandleTypes[type];
15407 * Unsets an invalid handle id
15408 * @method removeInvalidHandleId
15409 * @param {string} id the id of the element to re-enable
15411 removeInvalidHandleId: function(id) {
15412 if (typeof id !== "string") {
15415 delete this.invalidHandleIds[id];
15419 * Unsets an invalid css class
15420 * @method removeInvalidHandleClass
15421 * @param {string} cssClass the class of the element(s) you wish to
15424 removeInvalidHandleClass: function(cssClass) {
15425 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15426 if (this.invalidHandleClasses[i] == cssClass) {
15427 delete this.invalidHandleClasses[i];
15433 * Checks the tag exclusion list to see if this click should be ignored
15434 * @method isValidHandleChild
15435 * @param {HTMLElement} node the HTMLElement to evaluate
15436 * @return {boolean} true if this is a valid tag type, false if not
15438 isValidHandleChild: function(node) {
15441 // var n = (node.nodeName == "#text") ? node.parentNode : node;
15444 nodeName = node.nodeName.toUpperCase();
15446 nodeName = node.nodeName;
15448 valid = valid && !this.invalidHandleTypes[nodeName];
15449 valid = valid && !this.invalidHandleIds[node.id];
15451 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
15452 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
15461 * Create the array of horizontal tick marks if an interval was specified
15462 * in setXConstraint().
15463 * @method setXTicks
15466 setXTicks: function(iStartX, iTickSize) {
15468 this.xTickSize = iTickSize;
15472 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
15474 this.xTicks[this.xTicks.length] = i;
15479 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
15481 this.xTicks[this.xTicks.length] = i;
15486 this.xTicks.sort(this.DDM.numericSort) ;
15490 * Create the array of vertical tick marks if an interval was specified in
15491 * setYConstraint().
15492 * @method setYTicks
15495 setYTicks: function(iStartY, iTickSize) {
15497 this.yTickSize = iTickSize;
15501 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
15503 this.yTicks[this.yTicks.length] = i;
15508 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
15510 this.yTicks[this.yTicks.length] = i;
15515 this.yTicks.sort(this.DDM.numericSort) ;
15519 * By default, the element can be dragged any place on the screen. Use
15520 * this method to limit the horizontal travel of the element. Pass in
15521 * 0,0 for the parameters if you want to lock the drag to the y axis.
15522 * @method setXConstraint
15523 * @param {int} iLeft the number of pixels the element can move to the left
15524 * @param {int} iRight the number of pixels the element can move to the
15526 * @param {int} iTickSize optional parameter for specifying that the
15528 * should move iTickSize pixels at a time.
15530 setXConstraint: function(iLeft, iRight, iTickSize) {
15531 this.leftConstraint = iLeft;
15532 this.rightConstraint = iRight;
15534 this.minX = this.initPageX - iLeft;
15535 this.maxX = this.initPageX + iRight;
15536 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
15538 this.constrainX = true;
15542 * Clears any constraints applied to this instance. Also clears ticks
15543 * since they can't exist independent of a constraint at this time.
15544 * @method clearConstraints
15546 clearConstraints: function() {
15547 this.constrainX = false;
15548 this.constrainY = false;
15553 * Clears any tick interval defined for this instance
15554 * @method clearTicks
15556 clearTicks: function() {
15557 this.xTicks = null;
15558 this.yTicks = null;
15559 this.xTickSize = 0;
15560 this.yTickSize = 0;
15564 * By default, the element can be dragged any place on the screen. Set
15565 * this to limit the vertical travel of the element. Pass in 0,0 for the
15566 * parameters if you want to lock the drag to the x axis.
15567 * @method setYConstraint
15568 * @param {int} iUp the number of pixels the element can move up
15569 * @param {int} iDown the number of pixels the element can move down
15570 * @param {int} iTickSize optional parameter for specifying that the
15571 * element should move iTickSize pixels at a time.
15573 setYConstraint: function(iUp, iDown, iTickSize) {
15574 this.topConstraint = iUp;
15575 this.bottomConstraint = iDown;
15577 this.minY = this.initPageY - iUp;
15578 this.maxY = this.initPageY + iDown;
15579 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
15581 this.constrainY = true;
15586 * resetConstraints must be called if you manually reposition a dd element.
15587 * @method resetConstraints
15588 * @param {boolean} maintainOffset
15590 resetConstraints: function() {
15593 // Maintain offsets if necessary
15594 if (this.initPageX || this.initPageX === 0) {
15595 // figure out how much this thing has moved
15596 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
15597 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
15599 this.setInitPosition(dx, dy);
15601 // This is the first time we have detected the element's position
15603 this.setInitPosition();
15606 if (this.constrainX) {
15607 this.setXConstraint( this.leftConstraint,
15608 this.rightConstraint,
15612 if (this.constrainY) {
15613 this.setYConstraint( this.topConstraint,
15614 this.bottomConstraint,
15620 * Normally the drag element is moved pixel by pixel, but we can specify
15621 * that it move a number of pixels at a time. This method resolves the
15622 * location when we have it set up like this.
15624 * @param {int} val where we want to place the object
15625 * @param {int[]} tickArray sorted array of valid points
15626 * @return {int} the closest tick
15629 getTick: function(val, tickArray) {
15632 // If tick interval is not defined, it is effectively 1 pixel,
15633 // so we return the value passed to us.
15635 } else if (tickArray[0] >= val) {
15636 // The value is lower than the first tick, so we return the first
15638 return tickArray[0];
15640 for (var i=0, len=tickArray.length; i<len; ++i) {
15642 if (tickArray[next] && tickArray[next] >= val) {
15643 var diff1 = val - tickArray[i];
15644 var diff2 = tickArray[next] - val;
15645 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
15649 // The value is larger than the last tick, so we return the last
15651 return tickArray[tickArray.length - 1];
15658 * @return {string} string representation of the dd obj
15660 toString: function() {
15661 return ("DragDrop " + this.id);
15669 * Ext JS Library 1.1.1
15670 * Copyright(c) 2006-2007, Ext JS, LLC.
15672 * Originally Released Under LGPL - original licence link has changed is not relivant.
15675 * <script type="text/javascript">
15680 * The drag and drop utility provides a framework for building drag and drop
15681 * applications. In addition to enabling drag and drop for specific elements,
15682 * the drag and drop elements are tracked by the manager class, and the
15683 * interactions between the various elements are tracked during the drag and
15684 * the implementing code is notified about these important moments.
15687 // Only load the library once. Rewriting the manager class would orphan
15688 // existing drag and drop instances.
15689 if (!Roo.dd.DragDropMgr) {
15692 * @class Roo.dd.DragDropMgr
15693 * DragDropMgr is a singleton that tracks the element interaction for
15694 * all DragDrop items in the window. Generally, you will not call
15695 * this class directly, but it does have helper methods that could
15696 * be useful in your DragDrop implementations.
15699 Roo.dd.DragDropMgr = function() {
15701 var Event = Roo.EventManager;
15706 * Two dimensional Array of registered DragDrop objects. The first
15707 * dimension is the DragDrop item group, the second the DragDrop
15710 * @type {string: string}
15717 * Array of element ids defined as drag handles. Used to determine
15718 * if the element that generated the mousedown event is actually the
15719 * handle and not the html element itself.
15720 * @property handleIds
15721 * @type {string: string}
15728 * the DragDrop object that is currently being dragged
15729 * @property dragCurrent
15737 * the DragDrop object(s) that are being hovered over
15738 * @property dragOvers
15746 * the X distance between the cursor and the object being dragged
15755 * the Y distance between the cursor and the object being dragged
15764 * Flag to determine if we should prevent the default behavior of the
15765 * events we define. By default this is true, but this can be set to
15766 * false if you need the default behavior (not recommended)
15767 * @property preventDefault
15771 preventDefault: true,
15774 * Flag to determine if we should stop the propagation of the events
15775 * we generate. This is true by default but you may want to set it to
15776 * false if the html element contains other features that require the
15778 * @property stopPropagation
15782 stopPropagation: true,
15785 * Internal flag that is set to true when drag and drop has been
15787 * @property initialized
15794 * All drag and drop can be disabled.
15802 * Called the first time an element is registered.
15808 this.initialized = true;
15812 * In point mode, drag and drop interaction is defined by the
15813 * location of the cursor during the drag/drop
15821 * In intersect mode, drag and drop interactio nis defined by the
15822 * overlap of two or more drag and drop objects.
15823 * @property INTERSECT
15830 * The current drag and drop mode. Default: POINT
15838 * Runs method on all drag and drop objects
15839 * @method _execOnAll
15843 _execOnAll: function(sMethod, args) {
15844 for (var i in this.ids) {
15845 for (var j in this.ids[i]) {
15846 var oDD = this.ids[i][j];
15847 if (! this.isTypeOfDD(oDD)) {
15850 oDD[sMethod].apply(oDD, args);
15856 * Drag and drop initialization. Sets up the global event handlers
15861 _onLoad: function() {
15866 Event.on(document, "mouseup", this.handleMouseUp, this, true);
15867 Event.on(document, "mousemove", this.handleMouseMove, this, true);
15868 Event.on(window, "unload", this._onUnload, this, true);
15869 Event.on(window, "resize", this._onResize, this, true);
15870 // Event.on(window, "mouseout", this._test);
15875 * Reset constraints on all drag and drop objs
15876 * @method _onResize
15880 _onResize: function(e) {
15881 this._execOnAll("resetConstraints", []);
15885 * Lock all drag and drop functionality
15889 lock: function() { this.locked = true; },
15892 * Unlock all drag and drop functionality
15896 unlock: function() { this.locked = false; },
15899 * Is drag and drop locked?
15901 * @return {boolean} True if drag and drop is locked, false otherwise.
15904 isLocked: function() { return this.locked; },
15907 * Location cache that is set for all drag drop objects when a drag is
15908 * initiated, cleared when the drag is finished.
15909 * @property locationCache
15916 * Set useCache to false if you want to force object the lookup of each
15917 * drag and drop linked element constantly during a drag.
15918 * @property useCache
15925 * The number of pixels that the mouse needs to move after the
15926 * mousedown before the drag is initiated. Default=3;
15927 * @property clickPixelThresh
15931 clickPixelThresh: 3,
15934 * The number of milliseconds after the mousedown event to initiate the
15935 * drag if we don't get a mouseup event. Default=1000
15936 * @property clickTimeThresh
15940 clickTimeThresh: 350,
15943 * Flag that indicates that either the drag pixel threshold or the
15944 * mousdown time threshold has been met
15945 * @property dragThreshMet
15950 dragThreshMet: false,
15953 * Timeout used for the click time threshold
15954 * @property clickTimeout
15959 clickTimeout: null,
15962 * The X position of the mousedown event stored for later use when a
15963 * drag threshold is met.
15972 * The Y position of the mousedown event stored for later use when a
15973 * drag threshold is met.
15982 * Each DragDrop instance must be registered with the DragDropMgr.
15983 * This is executed in DragDrop.init()
15984 * @method regDragDrop
15985 * @param {DragDrop} oDD the DragDrop object to register
15986 * @param {String} sGroup the name of the group this element belongs to
15989 regDragDrop: function(oDD, sGroup) {
15990 if (!this.initialized) { this.init(); }
15992 if (!this.ids[sGroup]) {
15993 this.ids[sGroup] = {};
15995 this.ids[sGroup][oDD.id] = oDD;
15999 * Removes the supplied dd instance from the supplied group. Executed
16000 * by DragDrop.removeFromGroup, so don't call this function directly.
16001 * @method removeDDFromGroup
16005 removeDDFromGroup: function(oDD, sGroup) {
16006 if (!this.ids[sGroup]) {
16007 this.ids[sGroup] = {};
16010 var obj = this.ids[sGroup];
16011 if (obj && obj[oDD.id]) {
16012 delete obj[oDD.id];
16017 * Unregisters a drag and drop item. This is executed in
16018 * DragDrop.unreg, use that method instead of calling this directly.
16023 _remove: function(oDD) {
16024 for (var g in oDD.groups) {
16025 if (g && this.ids[g][oDD.id]) {
16026 delete this.ids[g][oDD.id];
16029 delete this.handleIds[oDD.id];
16033 * Each DragDrop handle element must be registered. This is done
16034 * automatically when executing DragDrop.setHandleElId()
16035 * @method regHandle
16036 * @param {String} sDDId the DragDrop id this element is a handle for
16037 * @param {String} sHandleId the id of the element that is the drag
16041 regHandle: function(sDDId, sHandleId) {
16042 if (!this.handleIds[sDDId]) {
16043 this.handleIds[sDDId] = {};
16045 this.handleIds[sDDId][sHandleId] = sHandleId;
16049 * Utility function to determine if a given element has been
16050 * registered as a drag drop item.
16051 * @method isDragDrop
16052 * @param {String} id the element id to check
16053 * @return {boolean} true if this element is a DragDrop item,
16057 isDragDrop: function(id) {
16058 return ( this.getDDById(id) ) ? true : false;
16062 * Returns the drag and drop instances that are in all groups the
16063 * passed in instance belongs to.
16064 * @method getRelated
16065 * @param {DragDrop} p_oDD the obj to get related data for
16066 * @param {boolean} bTargetsOnly if true, only return targetable objs
16067 * @return {DragDrop[]} the related instances
16070 getRelated: function(p_oDD, bTargetsOnly) {
16072 for (var i in p_oDD.groups) {
16073 for (j in this.ids[i]) {
16074 var dd = this.ids[i][j];
16075 if (! this.isTypeOfDD(dd)) {
16078 if (!bTargetsOnly || dd.isTarget) {
16079 oDDs[oDDs.length] = dd;
16088 * Returns true if the specified dd target is a legal target for
16089 * the specifice drag obj
16090 * @method isLegalTarget
16091 * @param {DragDrop} the drag obj
16092 * @param {DragDrop} the target
16093 * @return {boolean} true if the target is a legal target for the
16097 isLegalTarget: function (oDD, oTargetDD) {
16098 var targets = this.getRelated(oDD, true);
16099 for (var i=0, len=targets.length;i<len;++i) {
16100 if (targets[i].id == oTargetDD.id) {
16109 * My goal is to be able to transparently determine if an object is
16110 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16111 * returns "object", oDD.constructor.toString() always returns
16112 * "DragDrop" and not the name of the subclass. So for now it just
16113 * evaluates a well-known variable in DragDrop.
16114 * @method isTypeOfDD
16115 * @param {Object} the object to evaluate
16116 * @return {boolean} true if typeof oDD = DragDrop
16119 isTypeOfDD: function (oDD) {
16120 return (oDD && oDD.__ygDragDrop);
16124 * Utility function to determine if a given element has been
16125 * registered as a drag drop handle for the given Drag Drop object.
16127 * @param {String} id the element id to check
16128 * @return {boolean} true if this element is a DragDrop handle, false
16132 isHandle: function(sDDId, sHandleId) {
16133 return ( this.handleIds[sDDId] &&
16134 this.handleIds[sDDId][sHandleId] );
16138 * Returns the DragDrop instance for a given id
16139 * @method getDDById
16140 * @param {String} id the id of the DragDrop object
16141 * @return {DragDrop} the drag drop object, null if it is not found
16144 getDDById: function(id) {
16145 for (var i in this.ids) {
16146 if (this.ids[i][id]) {
16147 return this.ids[i][id];
16154 * Fired after a registered DragDrop object gets the mousedown event.
16155 * Sets up the events required to track the object being dragged
16156 * @method handleMouseDown
16157 * @param {Event} e the event
16158 * @param oDD the DragDrop object being dragged
16162 handleMouseDown: function(e, oDD) {
16164 Roo.QuickTips.disable();
16166 this.currentTarget = e.getTarget();
16168 this.dragCurrent = oDD;
16170 var el = oDD.getEl();
16172 // track start position
16173 this.startX = e.getPageX();
16174 this.startY = e.getPageY();
16176 this.deltaX = this.startX - el.offsetLeft;
16177 this.deltaY = this.startY - el.offsetTop;
16179 this.dragThreshMet = false;
16181 this.clickTimeout = setTimeout(
16183 var DDM = Roo.dd.DDM;
16184 DDM.startDrag(DDM.startX, DDM.startY);
16186 this.clickTimeThresh );
16190 * Fired when either the drag pixel threshol or the mousedown hold
16191 * time threshold has been met.
16192 * @method startDrag
16193 * @param x {int} the X position of the original mousedown
16194 * @param y {int} the Y position of the original mousedown
16197 startDrag: function(x, y) {
16198 clearTimeout(this.clickTimeout);
16199 if (this.dragCurrent) {
16200 this.dragCurrent.b4StartDrag(x, y);
16201 this.dragCurrent.startDrag(x, y);
16203 this.dragThreshMet = true;
16207 * Internal function to handle the mouseup event. Will be invoked
16208 * from the context of the document.
16209 * @method handleMouseUp
16210 * @param {Event} e the event
16214 handleMouseUp: function(e) {
16217 Roo.QuickTips.enable();
16219 if (! this.dragCurrent) {
16223 clearTimeout(this.clickTimeout);
16225 if (this.dragThreshMet) {
16226 this.fireEvents(e, true);
16236 * Utility to stop event propagation and event default, if these
16237 * features are turned on.
16238 * @method stopEvent
16239 * @param {Event} e the event as returned by this.getEvent()
16242 stopEvent: function(e){
16243 if(this.stopPropagation) {
16244 e.stopPropagation();
16247 if (this.preventDefault) {
16248 e.preventDefault();
16253 * Internal function to clean up event handlers after the drag
16254 * operation is complete
16256 * @param {Event} e the event
16260 stopDrag: function(e) {
16261 // Fire the drag end event for the item that was dragged
16262 if (this.dragCurrent) {
16263 if (this.dragThreshMet) {
16264 this.dragCurrent.b4EndDrag(e);
16265 this.dragCurrent.endDrag(e);
16268 this.dragCurrent.onMouseUp(e);
16271 this.dragCurrent = null;
16272 this.dragOvers = {};
16276 * Internal function to handle the mousemove event. Will be invoked
16277 * from the context of the html element.
16279 * @TODO figure out what we can do about mouse events lost when the
16280 * user drags objects beyond the window boundary. Currently we can
16281 * detect this in internet explorer by verifying that the mouse is
16282 * down during the mousemove event. Firefox doesn't give us the
16283 * button state on the mousemove event.
16284 * @method handleMouseMove
16285 * @param {Event} e the event
16289 handleMouseMove: function(e) {
16290 if (! this.dragCurrent) {
16294 // var button = e.which || e.button;
16296 // check for IE mouseup outside of page boundary
16297 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16299 return this.handleMouseUp(e);
16302 if (!this.dragThreshMet) {
16303 var diffX = Math.abs(this.startX - e.getPageX());
16304 var diffY = Math.abs(this.startY - e.getPageY());
16305 if (diffX > this.clickPixelThresh ||
16306 diffY > this.clickPixelThresh) {
16307 this.startDrag(this.startX, this.startY);
16311 if (this.dragThreshMet) {
16312 this.dragCurrent.b4Drag(e);
16313 this.dragCurrent.onDrag(e);
16314 if(!this.dragCurrent.moveOnly){
16315 this.fireEvents(e, false);
16325 * Iterates over all of the DragDrop elements to find ones we are
16326 * hovering over or dropping on
16327 * @method fireEvents
16328 * @param {Event} e the event
16329 * @param {boolean} isDrop is this a drop op or a mouseover op?
16333 fireEvents: function(e, isDrop) {
16334 var dc = this.dragCurrent;
16336 // If the user did the mouse up outside of the window, we could
16337 // get here even though we have ended the drag.
16338 if (!dc || dc.isLocked()) {
16342 var pt = e.getPoint();
16344 // cache the previous dragOver array
16350 var enterEvts = [];
16352 // Check to see if the object(s) we were hovering over is no longer
16353 // being hovered over so we can fire the onDragOut event
16354 for (var i in this.dragOvers) {
16356 var ddo = this.dragOvers[i];
16358 if (! this.isTypeOfDD(ddo)) {
16362 if (! this.isOverTarget(pt, ddo, this.mode)) {
16363 outEvts.push( ddo );
16366 oldOvers[i] = true;
16367 delete this.dragOvers[i];
16370 for (var sGroup in dc.groups) {
16372 if ("string" != typeof sGroup) {
16376 for (i in this.ids[sGroup]) {
16377 var oDD = this.ids[sGroup][i];
16378 if (! this.isTypeOfDD(oDD)) {
16382 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16383 if (this.isOverTarget(pt, oDD, this.mode)) {
16384 // look for drop interactions
16386 dropEvts.push( oDD );
16387 // look for drag enter and drag over interactions
16390 // initial drag over: dragEnter fires
16391 if (!oldOvers[oDD.id]) {
16392 enterEvts.push( oDD );
16393 // subsequent drag overs: dragOver fires
16395 overEvts.push( oDD );
16398 this.dragOvers[oDD.id] = oDD;
16406 if (outEvts.length) {
16407 dc.b4DragOut(e, outEvts);
16408 dc.onDragOut(e, outEvts);
16411 if (enterEvts.length) {
16412 dc.onDragEnter(e, enterEvts);
16415 if (overEvts.length) {
16416 dc.b4DragOver(e, overEvts);
16417 dc.onDragOver(e, overEvts);
16420 if (dropEvts.length) {
16421 dc.b4DragDrop(e, dropEvts);
16422 dc.onDragDrop(e, dropEvts);
16426 // fire dragout events
16428 for (i=0, len=outEvts.length; i<len; ++i) {
16429 dc.b4DragOut(e, outEvts[i].id);
16430 dc.onDragOut(e, outEvts[i].id);
16433 // fire enter events
16434 for (i=0,len=enterEvts.length; i<len; ++i) {
16435 // dc.b4DragEnter(e, oDD.id);
16436 dc.onDragEnter(e, enterEvts[i].id);
16439 // fire over events
16440 for (i=0,len=overEvts.length; i<len; ++i) {
16441 dc.b4DragOver(e, overEvts[i].id);
16442 dc.onDragOver(e, overEvts[i].id);
16445 // fire drop events
16446 for (i=0, len=dropEvts.length; i<len; ++i) {
16447 dc.b4DragDrop(e, dropEvts[i].id);
16448 dc.onDragDrop(e, dropEvts[i].id);
16453 // notify about a drop that did not find a target
16454 if (isDrop && !dropEvts.length) {
16455 dc.onInvalidDrop(e);
16461 * Helper function for getting the best match from the list of drag
16462 * and drop objects returned by the drag and drop events when we are
16463 * in INTERSECT mode. It returns either the first object that the
16464 * cursor is over, or the object that has the greatest overlap with
16465 * the dragged element.
16466 * @method getBestMatch
16467 * @param {DragDrop[]} dds The array of drag and drop objects
16469 * @return {DragDrop} The best single match
16472 getBestMatch: function(dds) {
16474 // Return null if the input is not what we expect
16475 //if (!dds || !dds.length || dds.length == 0) {
16477 // If there is only one item, it wins
16478 //} else if (dds.length == 1) {
16480 var len = dds.length;
16485 // Loop through the targeted items
16486 for (var i=0; i<len; ++i) {
16488 // If the cursor is over the object, it wins. If the
16489 // cursor is over multiple matches, the first one we come
16491 if (dd.cursorIsOver) {
16494 // Otherwise the object with the most overlap wins
16497 winner.overlap.getArea() < dd.overlap.getArea()) {
16508 * Refreshes the cache of the top-left and bottom-right points of the
16509 * drag and drop objects in the specified group(s). This is in the
16510 * format that is stored in the drag and drop instance, so typical
16513 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
16517 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
16519 * @TODO this really should be an indexed array. Alternatively this
16520 * method could accept both.
16521 * @method refreshCache
16522 * @param {Object} groups an associative array of groups to refresh
16525 refreshCache: function(groups) {
16526 for (var sGroup in groups) {
16527 if ("string" != typeof sGroup) {
16530 for (var i in this.ids[sGroup]) {
16531 var oDD = this.ids[sGroup][i];
16533 if (this.isTypeOfDD(oDD)) {
16534 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
16535 var loc = this.getLocation(oDD);
16537 this.locationCache[oDD.id] = loc;
16539 delete this.locationCache[oDD.id];
16540 // this will unregister the drag and drop object if
16541 // the element is not in a usable state
16550 * This checks to make sure an element exists and is in the DOM. The
16551 * main purpose is to handle cases where innerHTML is used to remove
16552 * drag and drop objects from the DOM. IE provides an 'unspecified
16553 * error' when trying to access the offsetParent of such an element
16555 * @param {HTMLElement} el the element to check
16556 * @return {boolean} true if the element looks usable
16559 verifyEl: function(el) {
16564 parent = el.offsetParent;
16567 parent = el.offsetParent;
16578 * Returns a Region object containing the drag and drop element's position
16579 * and size, including the padding configured for it
16580 * @method getLocation
16581 * @param {DragDrop} oDD the drag and drop object to get the
16583 * @return {Roo.lib.Region} a Region object representing the total area
16584 * the element occupies, including any padding
16585 * the instance is configured for.
16588 getLocation: function(oDD) {
16589 if (! this.isTypeOfDD(oDD)) {
16593 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
16596 pos= Roo.lib.Dom.getXY(el);
16604 x2 = x1 + el.offsetWidth;
16606 y2 = y1 + el.offsetHeight;
16608 t = y1 - oDD.padding[0];
16609 r = x2 + oDD.padding[1];
16610 b = y2 + oDD.padding[2];
16611 l = x1 - oDD.padding[3];
16613 return new Roo.lib.Region( t, r, b, l );
16617 * Checks the cursor location to see if it over the target
16618 * @method isOverTarget
16619 * @param {Roo.lib.Point} pt The point to evaluate
16620 * @param {DragDrop} oTarget the DragDrop object we are inspecting
16621 * @return {boolean} true if the mouse is over the target
16625 isOverTarget: function(pt, oTarget, intersect) {
16626 // use cache if available
16627 var loc = this.locationCache[oTarget.id];
16628 if (!loc || !this.useCache) {
16629 loc = this.getLocation(oTarget);
16630 this.locationCache[oTarget.id] = loc;
16638 oTarget.cursorIsOver = loc.contains( pt );
16640 // DragDrop is using this as a sanity check for the initial mousedown
16641 // in this case we are done. In POINT mode, if the drag obj has no
16642 // contraints, we are also done. Otherwise we need to evaluate the
16643 // location of the target as related to the actual location of the
16644 // dragged element.
16645 var dc = this.dragCurrent;
16646 if (!dc || !dc.getTargetCoord ||
16647 (!intersect && !dc.constrainX && !dc.constrainY)) {
16648 return oTarget.cursorIsOver;
16651 oTarget.overlap = null;
16653 // Get the current location of the drag element, this is the
16654 // location of the mouse event less the delta that represents
16655 // where the original mousedown happened on the element. We
16656 // need to consider constraints and ticks as well.
16657 var pos = dc.getTargetCoord(pt.x, pt.y);
16659 var el = dc.getDragEl();
16660 var curRegion = new Roo.lib.Region( pos.y,
16661 pos.x + el.offsetWidth,
16662 pos.y + el.offsetHeight,
16665 var overlap = curRegion.intersect(loc);
16668 oTarget.overlap = overlap;
16669 return (intersect) ? true : oTarget.cursorIsOver;
16676 * unload event handler
16677 * @method _onUnload
16681 _onUnload: function(e, me) {
16682 Roo.dd.DragDropMgr.unregAll();
16686 * Cleans up the drag and drop events and objects.
16691 unregAll: function() {
16693 if (this.dragCurrent) {
16695 this.dragCurrent = null;
16698 this._execOnAll("unreg", []);
16700 for (i in this.elementCache) {
16701 delete this.elementCache[i];
16704 this.elementCache = {};
16709 * A cache of DOM elements
16710 * @property elementCache
16717 * Get the wrapper for the DOM element specified
16718 * @method getElWrapper
16719 * @param {String} id the id of the element to get
16720 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
16722 * @deprecated This wrapper isn't that useful
16725 getElWrapper: function(id) {
16726 var oWrapper = this.elementCache[id];
16727 if (!oWrapper || !oWrapper.el) {
16728 oWrapper = this.elementCache[id] =
16729 new this.ElementWrapper(Roo.getDom(id));
16735 * Returns the actual DOM element
16736 * @method getElement
16737 * @param {String} id the id of the elment to get
16738 * @return {Object} The element
16739 * @deprecated use Roo.getDom instead
16742 getElement: function(id) {
16743 return Roo.getDom(id);
16747 * Returns the style property for the DOM element (i.e.,
16748 * document.getElById(id).style)
16750 * @param {String} id the id of the elment to get
16751 * @return {Object} The style property of the element
16752 * @deprecated use Roo.getDom instead
16755 getCss: function(id) {
16756 var el = Roo.getDom(id);
16757 return (el) ? el.style : null;
16761 * Inner class for cached elements
16762 * @class DragDropMgr.ElementWrapper
16767 ElementWrapper: function(el) {
16772 this.el = el || null;
16777 this.id = this.el && el.id;
16779 * A reference to the style property
16782 this.css = this.el && el.style;
16786 * Returns the X position of an html element
16788 * @param el the element for which to get the position
16789 * @return {int} the X coordinate
16791 * @deprecated use Roo.lib.Dom.getX instead
16794 getPosX: function(el) {
16795 return Roo.lib.Dom.getX(el);
16799 * Returns the Y position of an html element
16801 * @param el the element for which to get the position
16802 * @return {int} the Y coordinate
16803 * @deprecated use Roo.lib.Dom.getY instead
16806 getPosY: function(el) {
16807 return Roo.lib.Dom.getY(el);
16811 * Swap two nodes. In IE, we use the native method, for others we
16812 * emulate the IE behavior
16814 * @param n1 the first node to swap
16815 * @param n2 the other node to swap
16818 swapNode: function(n1, n2) {
16822 var p = n2.parentNode;
16823 var s = n2.nextSibling;
16826 p.insertBefore(n1, n2);
16827 } else if (n2 == n1.nextSibling) {
16828 p.insertBefore(n2, n1);
16830 n1.parentNode.replaceChild(n2, n1);
16831 p.insertBefore(n1, s);
16837 * Returns the current scroll position
16838 * @method getScroll
16842 getScroll: function () {
16843 var t, l, dde=document.documentElement, db=document.body;
16844 if (dde && (dde.scrollTop || dde.scrollLeft)) {
16846 l = dde.scrollLeft;
16853 return { top: t, left: l };
16857 * Returns the specified element style property
16859 * @param {HTMLElement} el the element
16860 * @param {string} styleProp the style property
16861 * @return {string} The value of the style property
16862 * @deprecated use Roo.lib.Dom.getStyle
16865 getStyle: function(el, styleProp) {
16866 return Roo.fly(el).getStyle(styleProp);
16870 * Gets the scrollTop
16871 * @method getScrollTop
16872 * @return {int} the document's scrollTop
16875 getScrollTop: function () { return this.getScroll().top; },
16878 * Gets the scrollLeft
16879 * @method getScrollLeft
16880 * @return {int} the document's scrollTop
16883 getScrollLeft: function () { return this.getScroll().left; },
16886 * Sets the x/y position of an element to the location of the
16889 * @param {HTMLElement} moveEl The element to move
16890 * @param {HTMLElement} targetEl The position reference element
16893 moveToEl: function (moveEl, targetEl) {
16894 var aCoord = Roo.lib.Dom.getXY(targetEl);
16895 Roo.lib.Dom.setXY(moveEl, aCoord);
16899 * Numeric array sort function
16900 * @method numericSort
16903 numericSort: function(a, b) { return (a - b); },
16907 * @property _timeoutCount
16914 * Trying to make the load order less important. Without this we get
16915 * an error if this file is loaded before the Event Utility.
16916 * @method _addListeners
16920 _addListeners: function() {
16921 var DDM = Roo.dd.DDM;
16922 if ( Roo.lib.Event && document ) {
16925 if (DDM._timeoutCount > 2000) {
16927 setTimeout(DDM._addListeners, 10);
16928 if (document && document.body) {
16929 DDM._timeoutCount += 1;
16936 * Recursively searches the immediate parent and all child nodes for
16937 * the handle element in order to determine wheter or not it was
16939 * @method handleWasClicked
16940 * @param node the html element to inspect
16943 handleWasClicked: function(node, id) {
16944 if (this.isHandle(id, node.id)) {
16947 // check to see if this is a text node child of the one we want
16948 var p = node.parentNode;
16951 if (this.isHandle(id, p.id)) {
16966 // shorter alias, save a few bytes
16967 Roo.dd.DDM = Roo.dd.DragDropMgr;
16968 Roo.dd.DDM._addListeners();
16972 * Ext JS Library 1.1.1
16973 * Copyright(c) 2006-2007, Ext JS, LLC.
16975 * Originally Released Under LGPL - original licence link has changed is not relivant.
16978 * <script type="text/javascript">
16983 * A DragDrop implementation where the linked element follows the
16984 * mouse cursor during a drag.
16985 * @extends Roo.dd.DragDrop
16987 * @param {String} id the id of the linked element
16988 * @param {String} sGroup the group of related DragDrop items
16989 * @param {object} config an object containing configurable attributes
16990 * Valid properties for DD:
16993 Roo.dd.DD = function(id, sGroup, config) {
16995 this.init(id, sGroup, config);
16999 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17002 * When set to true, the utility automatically tries to scroll the browser
17003 * window wehn a drag and drop element is dragged near the viewport boundary.
17004 * Defaults to true.
17011 * Sets the pointer offset to the distance between the linked element's top
17012 * left corner and the location the element was clicked
17013 * @method autoOffset
17014 * @param {int} iPageX the X coordinate of the click
17015 * @param {int} iPageY the Y coordinate of the click
17017 autoOffset: function(iPageX, iPageY) {
17018 var x = iPageX - this.startPageX;
17019 var y = iPageY - this.startPageY;
17020 this.setDelta(x, y);
17024 * Sets the pointer offset. You can call this directly to force the
17025 * offset to be in a particular location (e.g., pass in 0,0 to set it
17026 * to the center of the object)
17028 * @param {int} iDeltaX the distance from the left
17029 * @param {int} iDeltaY the distance from the top
17031 setDelta: function(iDeltaX, iDeltaY) {
17032 this.deltaX = iDeltaX;
17033 this.deltaY = iDeltaY;
17037 * Sets the drag element to the location of the mousedown or click event,
17038 * maintaining the cursor location relative to the location on the element
17039 * that was clicked. Override this if you want to place the element in a
17040 * location other than where the cursor is.
17041 * @method setDragElPos
17042 * @param {int} iPageX the X coordinate of the mousedown or drag event
17043 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17045 setDragElPos: function(iPageX, iPageY) {
17046 // the first time we do this, we are going to check to make sure
17047 // the element has css positioning
17049 var el = this.getDragEl();
17050 this.alignElWithMouse(el, iPageX, iPageY);
17054 * Sets the element to the location of the mousedown or click event,
17055 * maintaining the cursor location relative to the location on the element
17056 * that was clicked. Override this if you want to place the element in a
17057 * location other than where the cursor is.
17058 * @method alignElWithMouse
17059 * @param {HTMLElement} el the element to move
17060 * @param {int} iPageX the X coordinate of the mousedown or drag event
17061 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17063 alignElWithMouse: function(el, iPageX, iPageY) {
17064 var oCoord = this.getTargetCoord(iPageX, iPageY);
17065 var fly = el.dom ? el : Roo.fly(el);
17066 if (!this.deltaSetXY) {
17067 var aCoord = [oCoord.x, oCoord.y];
17069 var newLeft = fly.getLeft(true);
17070 var newTop = fly.getTop(true);
17071 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17073 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17076 this.cachePosition(oCoord.x, oCoord.y);
17077 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17082 * Saves the most recent position so that we can reset the constraints and
17083 * tick marks on-demand. We need to know this so that we can calculate the
17084 * number of pixels the element is offset from its original position.
17085 * @method cachePosition
17086 * @param iPageX the current x position (optional, this just makes it so we
17087 * don't have to look it up again)
17088 * @param iPageY the current y position (optional, this just makes it so we
17089 * don't have to look it up again)
17091 cachePosition: function(iPageX, iPageY) {
17093 this.lastPageX = iPageX;
17094 this.lastPageY = iPageY;
17096 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17097 this.lastPageX = aCoord[0];
17098 this.lastPageY = aCoord[1];
17103 * Auto-scroll the window if the dragged object has been moved beyond the
17104 * visible window boundary.
17105 * @method autoScroll
17106 * @param {int} x the drag element's x position
17107 * @param {int} y the drag element's y position
17108 * @param {int} h the height of the drag element
17109 * @param {int} w the width of the drag element
17112 autoScroll: function(x, y, h, w) {
17115 // The client height
17116 var clientH = Roo.lib.Dom.getViewWidth();
17118 // The client width
17119 var clientW = Roo.lib.Dom.getViewHeight();
17121 // The amt scrolled down
17122 var st = this.DDM.getScrollTop();
17124 // The amt scrolled right
17125 var sl = this.DDM.getScrollLeft();
17127 // Location of the bottom of the element
17130 // Location of the right of the element
17133 // The distance from the cursor to the bottom of the visible area,
17134 // adjusted so that we don't scroll if the cursor is beyond the
17135 // element drag constraints
17136 var toBot = (clientH + st - y - this.deltaY);
17138 // The distance from the cursor to the right of the visible area
17139 var toRight = (clientW + sl - x - this.deltaX);
17142 // How close to the edge the cursor must be before we scroll
17143 // var thresh = (document.all) ? 100 : 40;
17146 // How many pixels to scroll per autoscroll op. This helps to reduce
17147 // clunky scrolling. IE is more sensitive about this ... it needs this
17148 // value to be higher.
17149 var scrAmt = (document.all) ? 80 : 30;
17151 // Scroll down if we are near the bottom of the visible page and the
17152 // obj extends below the crease
17153 if ( bot > clientH && toBot < thresh ) {
17154 window.scrollTo(sl, st + scrAmt);
17157 // Scroll up if the window is scrolled down and the top of the object
17158 // goes above the top border
17159 if ( y < st && st > 0 && y - st < thresh ) {
17160 window.scrollTo(sl, st - scrAmt);
17163 // Scroll right if the obj is beyond the right border and the cursor is
17164 // near the border.
17165 if ( right > clientW && toRight < thresh ) {
17166 window.scrollTo(sl + scrAmt, st);
17169 // Scroll left if the window has been scrolled to the right and the obj
17170 // extends past the left border
17171 if ( x < sl && sl > 0 && x - sl < thresh ) {
17172 window.scrollTo(sl - scrAmt, st);
17178 * Finds the location the element should be placed if we want to move
17179 * it to where the mouse location less the click offset would place us.
17180 * @method getTargetCoord
17181 * @param {int} iPageX the X coordinate of the click
17182 * @param {int} iPageY the Y coordinate of the click
17183 * @return an object that contains the coordinates (Object.x and Object.y)
17186 getTargetCoord: function(iPageX, iPageY) {
17189 var x = iPageX - this.deltaX;
17190 var y = iPageY - this.deltaY;
17192 if (this.constrainX) {
17193 if (x < this.minX) { x = this.minX; }
17194 if (x > this.maxX) { x = this.maxX; }
17197 if (this.constrainY) {
17198 if (y < this.minY) { y = this.minY; }
17199 if (y > this.maxY) { y = this.maxY; }
17202 x = this.getTick(x, this.xTicks);
17203 y = this.getTick(y, this.yTicks);
17210 * Sets up config options specific to this class. Overrides
17211 * Roo.dd.DragDrop, but all versions of this method through the
17212 * inheritance chain are called
17214 applyConfig: function() {
17215 Roo.dd.DD.superclass.applyConfig.call(this);
17216 this.scroll = (this.config.scroll !== false);
17220 * Event that fires prior to the onMouseDown event. Overrides
17223 b4MouseDown: function(e) {
17224 // this.resetConstraints();
17225 this.autoOffset(e.getPageX(),
17230 * Event that fires prior to the onDrag event. Overrides
17233 b4Drag: function(e) {
17234 this.setDragElPos(e.getPageX(),
17238 toString: function() {
17239 return ("DD " + this.id);
17242 //////////////////////////////////////////////////////////////////////////
17243 // Debugging ygDragDrop events that can be overridden
17244 //////////////////////////////////////////////////////////////////////////
17246 startDrag: function(x, y) {
17249 onDrag: function(e) {
17252 onDragEnter: function(e, id) {
17255 onDragOver: function(e, id) {
17258 onDragOut: function(e, id) {
17261 onDragDrop: function(e, id) {
17264 endDrag: function(e) {
17271 * Ext JS Library 1.1.1
17272 * Copyright(c) 2006-2007, Ext JS, LLC.
17274 * Originally Released Under LGPL - original licence link has changed is not relivant.
17277 * <script type="text/javascript">
17281 * @class Roo.dd.DDProxy
17282 * A DragDrop implementation that inserts an empty, bordered div into
17283 * the document that follows the cursor during drag operations. At the time of
17284 * the click, the frame div is resized to the dimensions of the linked html
17285 * element, and moved to the exact location of the linked element.
17287 * References to the "frame" element refer to the single proxy element that
17288 * was created to be dragged in place of all DDProxy elements on the
17291 * @extends Roo.dd.DD
17293 * @param {String} id the id of the linked html element
17294 * @param {String} sGroup the group of related DragDrop objects
17295 * @param {object} config an object containing configurable attributes
17296 * Valid properties for DDProxy in addition to those in DragDrop:
17297 * resizeFrame, centerFrame, dragElId
17299 Roo.dd.DDProxy = function(id, sGroup, config) {
17301 this.init(id, sGroup, config);
17307 * The default drag frame div id
17308 * @property Roo.dd.DDProxy.dragElId
17312 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17314 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17317 * By default we resize the drag frame to be the same size as the element
17318 * we want to drag (this is to get the frame effect). We can turn it off
17319 * if we want a different behavior.
17320 * @property resizeFrame
17326 * By default the frame is positioned exactly where the drag element is, so
17327 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17328 * you do not have constraints on the obj is to have the drag frame centered
17329 * around the cursor. Set centerFrame to true for this effect.
17330 * @property centerFrame
17333 centerFrame: false,
17336 * Creates the proxy element if it does not yet exist
17337 * @method createFrame
17339 createFrame: function() {
17341 var body = document.body;
17343 if (!body || !body.firstChild) {
17344 setTimeout( function() { self.createFrame(); }, 50 );
17348 var div = this.getDragEl();
17351 div = document.createElement("div");
17352 div.id = this.dragElId;
17355 s.position = "absolute";
17356 s.visibility = "hidden";
17358 s.border = "2px solid #aaa";
17361 // appendChild can blow up IE if invoked prior to the window load event
17362 // while rendering a table. It is possible there are other scenarios
17363 // that would cause this to happen as well.
17364 body.insertBefore(div, body.firstChild);
17369 * Initialization for the drag frame element. Must be called in the
17370 * constructor of all subclasses
17371 * @method initFrame
17373 initFrame: function() {
17374 this.createFrame();
17377 applyConfig: function() {
17378 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17380 this.resizeFrame = (this.config.resizeFrame !== false);
17381 this.centerFrame = (this.config.centerFrame);
17382 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17386 * Resizes the drag frame to the dimensions of the clicked object, positions
17387 * it over the object, and finally displays it
17388 * @method showFrame
17389 * @param {int} iPageX X click position
17390 * @param {int} iPageY Y click position
17393 showFrame: function(iPageX, iPageY) {
17394 var el = this.getEl();
17395 var dragEl = this.getDragEl();
17396 var s = dragEl.style;
17398 this._resizeProxy();
17400 if (this.centerFrame) {
17401 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17402 Math.round(parseInt(s.height, 10)/2) );
17405 this.setDragElPos(iPageX, iPageY);
17407 Roo.fly(dragEl).show();
17411 * The proxy is automatically resized to the dimensions of the linked
17412 * element when a drag is initiated, unless resizeFrame is set to false
17413 * @method _resizeProxy
17416 _resizeProxy: function() {
17417 if (this.resizeFrame) {
17418 var el = this.getEl();
17419 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17423 // overrides Roo.dd.DragDrop
17424 b4MouseDown: function(e) {
17425 var x = e.getPageX();
17426 var y = e.getPageY();
17427 this.autoOffset(x, y);
17428 this.setDragElPos(x, y);
17431 // overrides Roo.dd.DragDrop
17432 b4StartDrag: function(x, y) {
17433 // show the drag frame
17434 this.showFrame(x, y);
17437 // overrides Roo.dd.DragDrop
17438 b4EndDrag: function(e) {
17439 Roo.fly(this.getDragEl()).hide();
17442 // overrides Roo.dd.DragDrop
17443 // By default we try to move the element to the last location of the frame.
17444 // This is so that the default behavior mirrors that of Roo.dd.DD.
17445 endDrag: function(e) {
17447 var lel = this.getEl();
17448 var del = this.getDragEl();
17450 // Show the drag frame briefly so we can get its position
17451 del.style.visibility = "";
17454 // Hide the linked element before the move to get around a Safari
17456 lel.style.visibility = "hidden";
17457 Roo.dd.DDM.moveToEl(lel, del);
17458 del.style.visibility = "hidden";
17459 lel.style.visibility = "";
17464 beforeMove : function(){
17468 afterDrag : function(){
17472 toString: function() {
17473 return ("DDProxy " + this.id);
17479 * Ext JS Library 1.1.1
17480 * Copyright(c) 2006-2007, Ext JS, LLC.
17482 * Originally Released Under LGPL - original licence link has changed is not relivant.
17485 * <script type="text/javascript">
17489 * @class Roo.dd.DDTarget
17490 * A DragDrop implementation that does not move, but can be a drop
17491 * target. You would get the same result by simply omitting implementation
17492 * for the event callbacks, but this way we reduce the processing cost of the
17493 * event listener and the callbacks.
17494 * @extends Roo.dd.DragDrop
17496 * @param {String} id the id of the element that is a drop target
17497 * @param {String} sGroup the group of related DragDrop objects
17498 * @param {object} config an object containing configurable attributes
17499 * Valid properties for DDTarget in addition to those in
17503 Roo.dd.DDTarget = function(id, sGroup, config) {
17505 this.initTarget(id, sGroup, config);
17507 if (config.listeners || config.events) {
17508 Roo.dd.DragDrop.superclass.constructor.call(this, {
17509 listeners : config.listeners || {},
17510 events : config.events || {}
17515 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
17516 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
17517 toString: function() {
17518 return ("DDTarget " + this.id);
17523 * Ext JS Library 1.1.1
17524 * Copyright(c) 2006-2007, Ext JS, LLC.
17526 * Originally Released Under LGPL - original licence link has changed is not relivant.
17529 * <script type="text/javascript">
17534 * @class Roo.dd.ScrollManager
17535 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
17536 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
17539 Roo.dd.ScrollManager = function(){
17540 var ddm = Roo.dd.DragDropMgr;
17545 var onStop = function(e){
17550 var triggerRefresh = function(){
17551 if(ddm.dragCurrent){
17552 ddm.refreshCache(ddm.dragCurrent.groups);
17556 var doScroll = function(){
17557 if(ddm.dragCurrent){
17558 var dds = Roo.dd.ScrollManager;
17560 if(proc.el.scroll(proc.dir, dds.increment)){
17564 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
17569 var clearProc = function(){
17571 clearInterval(proc.id);
17578 var startProc = function(el, dir){
17582 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
17585 var onFire = function(e, isDrop){
17586 if(isDrop || !ddm.dragCurrent){ return; }
17587 var dds = Roo.dd.ScrollManager;
17588 if(!dragEl || dragEl != ddm.dragCurrent){
17589 dragEl = ddm.dragCurrent;
17590 // refresh regions on drag start
17591 dds.refreshCache();
17594 var xy = Roo.lib.Event.getXY(e);
17595 var pt = new Roo.lib.Point(xy[0], xy[1]);
17596 for(var id in els){
17597 var el = els[id], r = el._region;
17598 if(r && r.contains(pt) && el.isScrollable()){
17599 if(r.bottom - pt.y <= dds.thresh){
17601 startProc(el, "down");
17604 }else if(r.right - pt.x <= dds.thresh){
17606 startProc(el, "left");
17609 }else if(pt.y - r.top <= dds.thresh){
17611 startProc(el, "up");
17614 }else if(pt.x - r.left <= dds.thresh){
17616 startProc(el, "right");
17625 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
17626 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
17630 * Registers new overflow element(s) to auto scroll
17631 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
17633 register : function(el){
17634 if(el instanceof Array){
17635 for(var i = 0, len = el.length; i < len; i++) {
17636 this.register(el[i]);
17645 * Unregisters overflow element(s) so they are no longer scrolled
17646 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
17648 unregister : function(el){
17649 if(el instanceof Array){
17650 for(var i = 0, len = el.length; i < len; i++) {
17651 this.unregister(el[i]);
17660 * The number of pixels from the edge of a container the pointer needs to be to
17661 * trigger scrolling (defaults to 25)
17667 * The number of pixels to scroll in each scroll increment (defaults to 50)
17673 * The frequency of scrolls in milliseconds (defaults to 500)
17679 * True to animate the scroll (defaults to true)
17685 * The animation duration in seconds -
17686 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
17692 * Manually trigger a cache refresh.
17694 refreshCache : function(){
17695 for(var id in els){
17696 if(typeof els[id] == 'object'){ // for people extending the object prototype
17697 els[id]._region = els[id].getRegion();
17704 * Ext JS Library 1.1.1
17705 * Copyright(c) 2006-2007, Ext JS, LLC.
17707 * Originally Released Under LGPL - original licence link has changed is not relivant.
17710 * <script type="text/javascript">
17715 * @class Roo.dd.Registry
17716 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
17717 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
17720 Roo.dd.Registry = function(){
17723 var autoIdSeed = 0;
17725 var getId = function(el, autogen){
17726 if(typeof el == "string"){
17730 if(!id && autogen !== false){
17731 id = "roodd-" + (++autoIdSeed);
17739 * Register a drag drop element
17740 * @param {String|HTMLElement} element The id or DOM node to register
17741 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
17742 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
17743 * knows how to interpret, plus there are some specific properties known to the Registry that should be
17744 * populated in the data object (if applicable):
17746 Value Description<br />
17747 --------- ------------------------------------------<br />
17748 handles Array of DOM nodes that trigger dragging<br />
17749 for the element being registered<br />
17750 isHandle True if the element passed in triggers<br />
17751 dragging itself, else false
17754 register : function(el, data){
17756 if(typeof el == "string"){
17757 el = document.getElementById(el);
17760 elements[getId(el)] = data;
17761 if(data.isHandle !== false){
17762 handles[data.ddel.id] = data;
17765 var hs = data.handles;
17766 for(var i = 0, len = hs.length; i < len; i++){
17767 handles[getId(hs[i])] = data;
17773 * Unregister a drag drop element
17774 * @param {String|HTMLElement} element The id or DOM node to unregister
17776 unregister : function(el){
17777 var id = getId(el, false);
17778 var data = elements[id];
17780 delete elements[id];
17782 var hs = data.handles;
17783 for(var i = 0, len = hs.length; i < len; i++){
17784 delete handles[getId(hs[i], false)];
17791 * Returns the handle registered for a DOM Node by id
17792 * @param {String|HTMLElement} id The DOM node or id to look up
17793 * @return {Object} handle The custom handle data
17795 getHandle : function(id){
17796 if(typeof id != "string"){ // must be element?
17799 return handles[id];
17803 * Returns the handle that is registered for the DOM node that is the target of the event
17804 * @param {Event} e The event
17805 * @return {Object} handle The custom handle data
17807 getHandleFromEvent : function(e){
17808 var t = Roo.lib.Event.getTarget(e);
17809 return t ? handles[t.id] : null;
17813 * Returns a custom data object that is registered for a DOM node by id
17814 * @param {String|HTMLElement} id The DOM node or id to look up
17815 * @return {Object} data The custom data
17817 getTarget : function(id){
17818 if(typeof id != "string"){ // must be element?
17821 return elements[id];
17825 * Returns a custom data object that is registered for the DOM node that is the target of the event
17826 * @param {Event} e The event
17827 * @return {Object} data The custom data
17829 getTargetFromEvent : function(e){
17830 var t = Roo.lib.Event.getTarget(e);
17831 return t ? elements[t.id] || handles[t.id] : null;
17836 * Ext JS Library 1.1.1
17837 * Copyright(c) 2006-2007, Ext JS, LLC.
17839 * Originally Released Under LGPL - original licence link has changed is not relivant.
17842 * <script type="text/javascript">
17847 * @class Roo.dd.StatusProxy
17848 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
17849 * default drag proxy used by all Roo.dd components.
17851 * @param {Object} config
17853 Roo.dd.StatusProxy = function(config){
17854 Roo.apply(this, config);
17855 this.id = this.id || Roo.id();
17856 this.el = new Roo.Layer({
17858 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
17859 {tag: "div", cls: "x-dd-drop-icon"},
17860 {tag: "div", cls: "x-dd-drag-ghost"}
17863 shadow: !config || config.shadow !== false
17865 this.ghost = Roo.get(this.el.dom.childNodes[1]);
17866 this.dropStatus = this.dropNotAllowed;
17869 Roo.dd.StatusProxy.prototype = {
17871 * @cfg {String} dropAllowed
17872 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
17874 dropAllowed : "x-dd-drop-ok",
17876 * @cfg {String} dropNotAllowed
17877 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
17879 dropNotAllowed : "x-dd-drop-nodrop",
17882 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
17883 * over the current target element.
17884 * @param {String} cssClass The css class for the new drop status indicator image
17886 setStatus : function(cssClass){
17887 cssClass = cssClass || this.dropNotAllowed;
17888 if(this.dropStatus != cssClass){
17889 this.el.replaceClass(this.dropStatus, cssClass);
17890 this.dropStatus = cssClass;
17895 * Resets the status indicator to the default dropNotAllowed value
17896 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
17898 reset : function(clearGhost){
17899 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
17900 this.dropStatus = this.dropNotAllowed;
17902 this.ghost.update("");
17907 * Updates the contents of the ghost element
17908 * @param {String} html The html that will replace the current innerHTML of the ghost element
17910 update : function(html){
17911 if(typeof html == "string"){
17912 this.ghost.update(html);
17914 this.ghost.update("");
17915 html.style.margin = "0";
17916 this.ghost.dom.appendChild(html);
17918 // ensure float = none set?? cant remember why though.
17919 var el = this.ghost.dom.firstChild;
17921 Roo.fly(el).setStyle('float', 'none');
17926 * Returns the underlying proxy {@link Roo.Layer}
17927 * @return {Roo.Layer} el
17929 getEl : function(){
17934 * Returns the ghost element
17935 * @return {Roo.Element} el
17937 getGhost : function(){
17943 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
17945 hide : function(clear){
17953 * Stops the repair animation if it's currently running
17956 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
17962 * Displays this proxy
17969 * Force the Layer to sync its shadow and shim positions to the element
17976 * Causes the proxy to return to its position of origin via an animation. Should be called after an
17977 * invalid drop operation by the item being dragged.
17978 * @param {Array} xy The XY position of the element ([x, y])
17979 * @param {Function} callback The function to call after the repair is complete
17980 * @param {Object} scope The scope in which to execute the callback
17982 repair : function(xy, callback, scope){
17983 this.callback = callback;
17984 this.scope = scope;
17985 if(xy && this.animRepair !== false){
17986 this.el.addClass("x-dd-drag-repair");
17987 this.el.hideUnders(true);
17988 this.anim = this.el.shift({
17989 duration: this.repairDuration || .5,
17993 callback: this.afterRepair,
17997 this.afterRepair();
18002 afterRepair : function(){
18004 if(typeof this.callback == "function"){
18005 this.callback.call(this.scope || this);
18007 this.callback = null;
18012 * Ext JS Library 1.1.1
18013 * Copyright(c) 2006-2007, Ext JS, LLC.
18015 * Originally Released Under LGPL - original licence link has changed is not relivant.
18018 * <script type="text/javascript">
18022 * @class Roo.dd.DragSource
18023 * @extends Roo.dd.DDProxy
18024 * A simple class that provides the basic implementation needed to make any element draggable.
18026 * @param {String/HTMLElement/Element} el The container element
18027 * @param {Object} config
18029 Roo.dd.DragSource = function(el, config){
18030 this.el = Roo.get(el);
18031 this.dragData = {};
18033 Roo.apply(this, config);
18036 this.proxy = new Roo.dd.StatusProxy();
18039 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18040 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18042 this.dragging = false;
18045 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18047 * @cfg {String} dropAllowed
18048 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18050 dropAllowed : "x-dd-drop-ok",
18052 * @cfg {String} dropNotAllowed
18053 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18055 dropNotAllowed : "x-dd-drop-nodrop",
18058 * Returns the data object associated with this drag source
18059 * @return {Object} data An object containing arbitrary data
18061 getDragData : function(e){
18062 return this.dragData;
18066 onDragEnter : function(e, id){
18067 var target = Roo.dd.DragDropMgr.getDDById(id);
18068 this.cachedTarget = target;
18069 if(this.beforeDragEnter(target, e, id) !== false){
18070 if(target.isNotifyTarget){
18071 var status = target.notifyEnter(this, e, this.dragData);
18072 this.proxy.setStatus(status);
18074 this.proxy.setStatus(this.dropAllowed);
18077 if(this.afterDragEnter){
18079 * An empty function by default, but provided so that you can perform a custom action
18080 * when the dragged item enters the drop target by providing an implementation.
18081 * @param {Roo.dd.DragDrop} target The drop target
18082 * @param {Event} e The event object
18083 * @param {String} id The id of the dragged element
18084 * @method afterDragEnter
18086 this.afterDragEnter(target, e, id);
18092 * An empty function by default, but provided so that you can perform a custom action
18093 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18094 * @param {Roo.dd.DragDrop} target The drop target
18095 * @param {Event} e The event object
18096 * @param {String} id The id of the dragged element
18097 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18099 beforeDragEnter : function(target, e, id){
18104 alignElWithMouse: function() {
18105 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18110 onDragOver : function(e, id){
18111 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18112 if(this.beforeDragOver(target, e, id) !== false){
18113 if(target.isNotifyTarget){
18114 var status = target.notifyOver(this, e, this.dragData);
18115 this.proxy.setStatus(status);
18118 if(this.afterDragOver){
18120 * An empty function by default, but provided so that you can perform a custom action
18121 * while the dragged item is over the drop target by providing an implementation.
18122 * @param {Roo.dd.DragDrop} target The drop target
18123 * @param {Event} e The event object
18124 * @param {String} id The id of the dragged element
18125 * @method afterDragOver
18127 this.afterDragOver(target, e, id);
18133 * An empty function by default, but provided so that you can perform a custom action
18134 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18135 * @param {Roo.dd.DragDrop} target The drop target
18136 * @param {Event} e The event object
18137 * @param {String} id The id of the dragged element
18138 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18140 beforeDragOver : function(target, e, id){
18145 onDragOut : function(e, id){
18146 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18147 if(this.beforeDragOut(target, e, id) !== false){
18148 if(target.isNotifyTarget){
18149 target.notifyOut(this, e, this.dragData);
18151 this.proxy.reset();
18152 if(this.afterDragOut){
18154 * An empty function by default, but provided so that you can perform a custom action
18155 * after the dragged item is dragged out of the target without dropping.
18156 * @param {Roo.dd.DragDrop} target The drop target
18157 * @param {Event} e The event object
18158 * @param {String} id The id of the dragged element
18159 * @method afterDragOut
18161 this.afterDragOut(target, e, id);
18164 this.cachedTarget = null;
18168 * An empty function by default, but provided so that you can perform a custom action before the dragged
18169 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18170 * @param {Roo.dd.DragDrop} target The drop target
18171 * @param {Event} e The event object
18172 * @param {String} id The id of the dragged element
18173 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18175 beforeDragOut : function(target, e, id){
18180 onDragDrop : function(e, id){
18181 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18182 if(this.beforeDragDrop(target, e, id) !== false){
18183 if(target.isNotifyTarget){
18184 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18185 this.onValidDrop(target, e, id);
18187 this.onInvalidDrop(target, e, id);
18190 this.onValidDrop(target, e, id);
18193 if(this.afterDragDrop){
18195 * An empty function by default, but provided so that you can perform a custom action
18196 * after a valid drag drop has occurred by providing an implementation.
18197 * @param {Roo.dd.DragDrop} target The drop target
18198 * @param {Event} e The event object
18199 * @param {String} id The id of the dropped element
18200 * @method afterDragDrop
18202 this.afterDragDrop(target, e, id);
18205 delete this.cachedTarget;
18209 * An empty function by default, but provided so that you can perform a custom action before the dragged
18210 * item is dropped onto the target and optionally cancel the onDragDrop.
18211 * @param {Roo.dd.DragDrop} target The drop target
18212 * @param {Event} e The event object
18213 * @param {String} id The id of the dragged element
18214 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18216 beforeDragDrop : function(target, e, id){
18221 onValidDrop : function(target, e, id){
18223 if(this.afterValidDrop){
18225 * An empty function by default, but provided so that you can perform a custom action
18226 * after a valid drop has occurred by providing an implementation.
18227 * @param {Object} target The target DD
18228 * @param {Event} e The event object
18229 * @param {String} id The id of the dropped element
18230 * @method afterInvalidDrop
18232 this.afterValidDrop(target, e, id);
18237 getRepairXY : function(e, data){
18238 return this.el.getXY();
18242 onInvalidDrop : function(target, e, id){
18243 this.beforeInvalidDrop(target, e, id);
18244 if(this.cachedTarget){
18245 if(this.cachedTarget.isNotifyTarget){
18246 this.cachedTarget.notifyOut(this, e, this.dragData);
18248 this.cacheTarget = null;
18250 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18252 if(this.afterInvalidDrop){
18254 * An empty function by default, but provided so that you can perform a custom action
18255 * after an invalid drop has occurred by providing an implementation.
18256 * @param {Event} e The event object
18257 * @param {String} id The id of the dropped element
18258 * @method afterInvalidDrop
18260 this.afterInvalidDrop(e, id);
18265 afterRepair : function(){
18267 this.el.highlight(this.hlColor || "c3daf9");
18269 this.dragging = false;
18273 * An empty function by default, but provided so that you can perform a custom action after an invalid
18274 * drop has occurred.
18275 * @param {Roo.dd.DragDrop} target The drop target
18276 * @param {Event} e The event object
18277 * @param {String} id The id of the dragged element
18278 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18280 beforeInvalidDrop : function(target, e, id){
18285 handleMouseDown : function(e){
18286 if(this.dragging) {
18289 var data = this.getDragData(e);
18290 if(data && this.onBeforeDrag(data, e) !== false){
18291 this.dragData = data;
18293 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18298 * An empty function by default, but provided so that you can perform a custom action before the initial
18299 * drag event begins and optionally cancel it.
18300 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18301 * @param {Event} e The event object
18302 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18304 onBeforeDrag : function(data, e){
18309 * An empty function by default, but provided so that you can perform a custom action once the initial
18310 * drag event has begun. The drag cannot be canceled from this function.
18311 * @param {Number} x The x position of the click on the dragged object
18312 * @param {Number} y The y position of the click on the dragged object
18314 onStartDrag : Roo.emptyFn,
18316 // private - YUI override
18317 startDrag : function(x, y){
18318 this.proxy.reset();
18319 this.dragging = true;
18320 this.proxy.update("");
18321 this.onInitDrag(x, y);
18326 onInitDrag : function(x, y){
18327 var clone = this.el.dom.cloneNode(true);
18328 clone.id = Roo.id(); // prevent duplicate ids
18329 this.proxy.update(clone);
18330 this.onStartDrag(x, y);
18335 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18336 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18338 getProxy : function(){
18343 * Hides the drag source's {@link Roo.dd.StatusProxy}
18345 hideProxy : function(){
18347 this.proxy.reset(true);
18348 this.dragging = false;
18352 triggerCacheRefresh : function(){
18353 Roo.dd.DDM.refreshCache(this.groups);
18356 // private - override to prevent hiding
18357 b4EndDrag: function(e) {
18360 // private - override to prevent moving
18361 endDrag : function(e){
18362 this.onEndDrag(this.dragData, e);
18366 onEndDrag : function(data, e){
18369 // private - pin to cursor
18370 autoOffset : function(x, y) {
18371 this.setDelta(-12, -20);
18375 * Ext JS Library 1.1.1
18376 * Copyright(c) 2006-2007, Ext JS, LLC.
18378 * Originally Released Under LGPL - original licence link has changed is not relivant.
18381 * <script type="text/javascript">
18386 * @class Roo.dd.DropTarget
18387 * @extends Roo.dd.DDTarget
18388 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18389 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18391 * @param {String/HTMLElement/Element} el The container element
18392 * @param {Object} config
18394 Roo.dd.DropTarget = function(el, config){
18395 this.el = Roo.get(el);
18397 var listeners = false; ;
18398 if (config && config.listeners) {
18399 listeners= config.listeners;
18400 delete config.listeners;
18402 Roo.apply(this, config);
18404 if(this.containerScroll){
18405 Roo.dd.ScrollManager.register(this.el);
18409 * @scope Roo.dd.DropTarget
18414 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18415 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18416 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18418 * IMPORTANT : it should set this.overClass and this.dropAllowed
18420 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18421 * @param {Event} e The event
18422 * @param {Object} data An object containing arbitrary data supplied by the drag source
18428 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18429 * This method will be called on every mouse movement while the drag source is over the drop target.
18430 * This default implementation simply returns the dropAllowed config value.
18432 * IMPORTANT : it should set this.dropAllowed
18434 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18435 * @param {Event} e The event
18436 * @param {Object} data An object containing arbitrary data supplied by the drag source
18442 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
18443 * out of the target without dropping. This default implementation simply removes the CSS class specified by
18444 * overClass (if any) from the drop element.
18445 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18446 * @param {Event} e The event
18447 * @param {Object} data An object containing arbitrary data supplied by the drag source
18453 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
18454 * been dropped on it. This method has no default implementation and returns false, so you must provide an
18455 * implementation that does something to process the drop event and returns true so that the drag source's
18456 * repair action does not run.
18458 * IMPORTANT : it should set this.success
18460 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18461 * @param {Event} e The event
18462 * @param {Object} data An object containing arbitrary data supplied by the drag source
18468 Roo.dd.DropTarget.superclass.constructor.call( this,
18470 this.ddGroup || this.group,
18473 listeners : listeners || {}
18481 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
18483 * @cfg {String} overClass
18484 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
18487 * @cfg {String} ddGroup
18488 * The drag drop group to handle drop events for
18492 * @cfg {String} dropAllowed
18493 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18495 dropAllowed : "x-dd-drop-ok",
18497 * @cfg {String} dropNotAllowed
18498 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18500 dropNotAllowed : "x-dd-drop-nodrop",
18502 * @cfg {boolean} success
18503 * set this after drop listener..
18507 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
18508 * if the drop point is valid for over/enter..
18515 isNotifyTarget : true,
18520 notifyEnter : function(dd, e, data)
18523 this.fireEvent('enter', dd, e, data);
18524 if(this.overClass){
18525 this.el.addClass(this.overClass);
18527 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18528 this.valid ? this.dropAllowed : this.dropNotAllowed
18535 notifyOver : function(dd, e, data)
18538 this.fireEvent('over', dd, e, data);
18539 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
18540 this.valid ? this.dropAllowed : this.dropNotAllowed
18547 notifyOut : function(dd, e, data)
18549 this.fireEvent('out', dd, e, data);
18550 if(this.overClass){
18551 this.el.removeClass(this.overClass);
18558 notifyDrop : function(dd, e, data)
18560 this.success = false;
18561 this.fireEvent('drop', dd, e, data);
18562 return this.success;
18566 * Ext JS Library 1.1.1
18567 * Copyright(c) 2006-2007, Ext JS, LLC.
18569 * Originally Released Under LGPL - original licence link has changed is not relivant.
18572 * <script type="text/javascript">
18577 * @class Roo.dd.DragZone
18578 * @extends Roo.dd.DragSource
18579 * This class provides a container DD instance that proxies for multiple child node sources.<br />
18580 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
18582 * @param {String/HTMLElement/Element} el The container element
18583 * @param {Object} config
18585 Roo.dd.DragZone = function(el, config){
18586 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
18587 if(this.containerScroll){
18588 Roo.dd.ScrollManager.register(this.el);
18592 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
18594 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
18595 * for auto scrolling during drag operations.
18598 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
18599 * method after a failed drop (defaults to "c3daf9" - light blue)
18603 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
18604 * for a valid target to drag based on the mouse down. Override this method
18605 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
18606 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
18607 * @param {EventObject} e The mouse down event
18608 * @return {Object} The dragData
18610 getDragData : function(e){
18611 return Roo.dd.Registry.getHandleFromEvent(e);
18615 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
18616 * this.dragData.ddel
18617 * @param {Number} x The x position of the click on the dragged object
18618 * @param {Number} y The y position of the click on the dragged object
18619 * @return {Boolean} true to continue the drag, false to cancel
18621 onInitDrag : function(x, y){
18622 this.proxy.update(this.dragData.ddel.cloneNode(true));
18623 this.onStartDrag(x, y);
18628 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
18630 afterRepair : function(){
18632 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
18634 this.dragging = false;
18638 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
18639 * the XY of this.dragData.ddel
18640 * @param {EventObject} e The mouse up event
18641 * @return {Array} The xy location (e.g. [100, 200])
18643 getRepairXY : function(e){
18644 return Roo.Element.fly(this.dragData.ddel).getXY();
18648 * Ext JS Library 1.1.1
18649 * Copyright(c) 2006-2007, Ext JS, LLC.
18651 * Originally Released Under LGPL - original licence link has changed is not relivant.
18654 * <script type="text/javascript">
18657 * @class Roo.dd.DropZone
18658 * @extends Roo.dd.DropTarget
18659 * This class provides a container DD instance that proxies for multiple child node targets.<br />
18660 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
18662 * @param {String/HTMLElement/Element} el The container element
18663 * @param {Object} config
18665 Roo.dd.DropZone = function(el, config){
18666 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
18669 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
18671 * Returns a custom data object associated with the DOM node that is the target of the event. By default
18672 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
18673 * provide your own custom lookup.
18674 * @param {Event} e The event
18675 * @return {Object} data The custom data
18677 getTargetFromEvent : function(e){
18678 return Roo.dd.Registry.getTargetFromEvent(e);
18682 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
18683 * that it has registered. This method has no default implementation and should be overridden to provide
18684 * node-specific processing if necessary.
18685 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18686 * {@link #getTargetFromEvent} for this node)
18687 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18688 * @param {Event} e The event
18689 * @param {Object} data An object containing arbitrary data supplied by the drag source
18691 onNodeEnter : function(n, dd, e, data){
18696 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
18697 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
18698 * overridden to provide the proper feedback.
18699 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18700 * {@link #getTargetFromEvent} for this node)
18701 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18702 * @param {Event} e The event
18703 * @param {Object} data An object containing arbitrary data supplied by the drag source
18704 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18705 * underlying {@link Roo.dd.StatusProxy} can be updated
18707 onNodeOver : function(n, dd, e, data){
18708 return this.dropAllowed;
18712 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
18713 * the drop node without dropping. This method has no default implementation and should be overridden to provide
18714 * node-specific processing if necessary.
18715 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18716 * {@link #getTargetFromEvent} for this node)
18717 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18718 * @param {Event} e The event
18719 * @param {Object} data An object containing arbitrary data supplied by the drag source
18721 onNodeOut : function(n, dd, e, data){
18726 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
18727 * the drop node. The default implementation returns false, so it should be overridden to provide the
18728 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
18729 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
18730 * {@link #getTargetFromEvent} for this node)
18731 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18732 * @param {Event} e The event
18733 * @param {Object} data An object containing arbitrary data supplied by the drag source
18734 * @return {Boolean} True if the drop was valid, else false
18736 onNodeDrop : function(n, dd, e, data){
18741 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
18742 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
18743 * it should be overridden to provide the proper feedback if necessary.
18744 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18745 * @param {Event} e The event
18746 * @param {Object} data An object containing arbitrary data supplied by the drag source
18747 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18748 * underlying {@link Roo.dd.StatusProxy} can be updated
18750 onContainerOver : function(dd, e, data){
18751 return this.dropNotAllowed;
18755 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
18756 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
18757 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
18758 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
18759 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18760 * @param {Event} e The event
18761 * @param {Object} data An object containing arbitrary data supplied by the drag source
18762 * @return {Boolean} True if the drop was valid, else false
18764 onContainerDrop : function(dd, e, data){
18769 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
18770 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
18771 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
18772 * you should override this method and provide a custom implementation.
18773 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18774 * @param {Event} e The event
18775 * @param {Object} data An object containing arbitrary data supplied by the drag source
18776 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18777 * underlying {@link Roo.dd.StatusProxy} can be updated
18779 notifyEnter : function(dd, e, data){
18780 return this.dropNotAllowed;
18784 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
18785 * This method will be called on every mouse movement while the drag source is over the drop zone.
18786 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
18787 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
18788 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
18789 * registered node, it will call {@link #onContainerOver}.
18790 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18791 * @param {Event} e The event
18792 * @param {Object} data An object containing arbitrary data supplied by the drag source
18793 * @return {String} status The CSS class that communicates the drop status back to the source so that the
18794 * underlying {@link Roo.dd.StatusProxy} can be updated
18796 notifyOver : function(dd, e, data){
18797 var n = this.getTargetFromEvent(e);
18798 if(!n){ // not over valid drop target
18799 if(this.lastOverNode){
18800 this.onNodeOut(this.lastOverNode, dd, e, data);
18801 this.lastOverNode = null;
18803 return this.onContainerOver(dd, e, data);
18805 if(this.lastOverNode != n){
18806 if(this.lastOverNode){
18807 this.onNodeOut(this.lastOverNode, dd, e, data);
18809 this.onNodeEnter(n, dd, e, data);
18810 this.lastOverNode = n;
18812 return this.onNodeOver(n, dd, e, data);
18816 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
18817 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
18818 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
18819 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18820 * @param {Event} e The event
18821 * @param {Object} data An object containing arbitrary data supplied by the drag zone
18823 notifyOut : function(dd, e, data){
18824 if(this.lastOverNode){
18825 this.onNodeOut(this.lastOverNode, dd, e, data);
18826 this.lastOverNode = null;
18831 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
18832 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
18833 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
18834 * otherwise it will call {@link #onContainerDrop}.
18835 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
18836 * @param {Event} e The event
18837 * @param {Object} data An object containing arbitrary data supplied by the drag source
18838 * @return {Boolean} True if the drop was valid, else false
18840 notifyDrop : function(dd, e, data){
18841 if(this.lastOverNode){
18842 this.onNodeOut(this.lastOverNode, dd, e, data);
18843 this.lastOverNode = null;
18845 var n = this.getTargetFromEvent(e);
18847 this.onNodeDrop(n, dd, e, data) :
18848 this.onContainerDrop(dd, e, data);
18852 triggerCacheRefresh : function(){
18853 Roo.dd.DDM.refreshCache(this.groups);
18857 * Ext JS Library 1.1.1
18858 * Copyright(c) 2006-2007, Ext JS, LLC.
18860 * Originally Released Under LGPL - original licence link has changed is not relivant.
18863 * <script type="text/javascript">
18868 * @class Roo.data.SortTypes
18870 * Defines the default sorting (casting?) comparison functions used when sorting data.
18872 Roo.data.SortTypes = {
18874 * Default sort that does nothing
18875 * @param {Mixed} s The value being converted
18876 * @return {Mixed} The comparison value
18878 none : function(s){
18883 * The regular expression used to strip tags
18887 stripTagsRE : /<\/?[^>]+>/gi,
18890 * Strips all HTML tags to sort on text only
18891 * @param {Mixed} s The value being converted
18892 * @return {String} The comparison value
18894 asText : function(s){
18895 return String(s).replace(this.stripTagsRE, "");
18899 * Strips all HTML tags to sort on text only - Case insensitive
18900 * @param {Mixed} s The value being converted
18901 * @return {String} The comparison value
18903 asUCText : function(s){
18904 return String(s).toUpperCase().replace(this.stripTagsRE, "");
18908 * Case insensitive string
18909 * @param {Mixed} s The value being converted
18910 * @return {String} The comparison value
18912 asUCString : function(s) {
18913 return String(s).toUpperCase();
18918 * @param {Mixed} s The value being converted
18919 * @return {Number} The comparison value
18921 asDate : function(s) {
18925 if(s instanceof Date){
18926 return s.getTime();
18928 return Date.parse(String(s));
18933 * @param {Mixed} s The value being converted
18934 * @return {Float} The comparison value
18936 asFloat : function(s) {
18937 var val = parseFloat(String(s).replace(/,/g, ""));
18938 if(isNaN(val)) val = 0;
18944 * @param {Mixed} s The value being converted
18945 * @return {Number} The comparison value
18947 asInt : function(s) {
18948 var val = parseInt(String(s).replace(/,/g, ""));
18949 if(isNaN(val)) val = 0;
18954 * Ext JS Library 1.1.1
18955 * Copyright(c) 2006-2007, Ext JS, LLC.
18957 * Originally Released Under LGPL - original licence link has changed is not relivant.
18960 * <script type="text/javascript">
18964 * @class Roo.data.Record
18965 * Instances of this class encapsulate both record <em>definition</em> information, and record
18966 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
18967 * to access Records cached in an {@link Roo.data.Store} object.<br>
18969 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
18970 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
18973 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
18975 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
18976 * {@link #create}. The parameters are the same.
18977 * @param {Array} data An associative Array of data values keyed by the field name.
18978 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
18979 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
18980 * not specified an integer id is generated.
18982 Roo.data.Record = function(data, id){
18983 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
18988 * Generate a constructor for a specific record layout.
18989 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
18990 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
18991 * Each field definition object may contain the following properties: <ul>
18992 * <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,
18993 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
18994 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
18995 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
18996 * is being used, then this is a string containing the javascript expression to reference the data relative to
18997 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
18998 * to the data item relative to the record element. If the mapping expression is the same as the field name,
18999 * this may be omitted.</p></li>
19000 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19001 * <ul><li>auto (Default, implies no conversion)</li>
19006 * <li>date</li></ul></p></li>
19007 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19008 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19009 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19010 * by the Reader into an object that will be stored in the Record. It is passed the
19011 * following parameters:<ul>
19012 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19014 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19016 * <br>usage:<br><pre><code>
19017 var TopicRecord = Roo.data.Record.create(
19018 {name: 'title', mapping: 'topic_title'},
19019 {name: 'author', mapping: 'username'},
19020 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19021 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19022 {name: 'lastPoster', mapping: 'user2'},
19023 {name: 'excerpt', mapping: 'post_text'}
19026 var myNewRecord = new TopicRecord({
19027 title: 'Do my job please',
19030 lastPost: new Date(),
19031 lastPoster: 'Animal',
19032 excerpt: 'No way dude!'
19034 myStore.add(myNewRecord);
19039 Roo.data.Record.create = function(o){
19040 var f = function(){
19041 f.superclass.constructor.apply(this, arguments);
19043 Roo.extend(f, Roo.data.Record);
19044 var p = f.prototype;
19045 p.fields = new Roo.util.MixedCollection(false, function(field){
19048 for(var i = 0, len = o.length; i < len; i++){
19049 p.fields.add(new Roo.data.Field(o[i]));
19051 f.getField = function(name){
19052 return p.fields.get(name);
19057 Roo.data.Record.AUTO_ID = 1000;
19058 Roo.data.Record.EDIT = 'edit';
19059 Roo.data.Record.REJECT = 'reject';
19060 Roo.data.Record.COMMIT = 'commit';
19062 Roo.data.Record.prototype = {
19064 * Readonly flag - true if this record has been modified.
19073 join : function(store){
19074 this.store = store;
19078 * Set the named field to the specified value.
19079 * @param {String} name The name of the field to set.
19080 * @param {Object} value The value to set the field to.
19082 set : function(name, value){
19083 if(this.data[name] == value){
19087 if(!this.modified){
19088 this.modified = {};
19090 if(typeof this.modified[name] == 'undefined'){
19091 this.modified[name] = this.data[name];
19093 this.data[name] = value;
19094 if(!this.editing && this.store){
19095 this.store.afterEdit(this);
19100 * Get the value of the named field.
19101 * @param {String} name The name of the field to get the value of.
19102 * @return {Object} The value of the field.
19104 get : function(name){
19105 return this.data[name];
19109 beginEdit : function(){
19110 this.editing = true;
19111 this.modified = {};
19115 cancelEdit : function(){
19116 this.editing = false;
19117 delete this.modified;
19121 endEdit : function(){
19122 this.editing = false;
19123 if(this.dirty && this.store){
19124 this.store.afterEdit(this);
19129 * Usually called by the {@link Roo.data.Store} which owns the Record.
19130 * Rejects all changes made to the Record since either creation, or the last commit operation.
19131 * Modified fields are reverted to their original values.
19133 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19134 * of reject operations.
19136 reject : function(){
19137 var m = this.modified;
19139 if(typeof m[n] != "function"){
19140 this.data[n] = m[n];
19143 this.dirty = false;
19144 delete this.modified;
19145 this.editing = false;
19147 this.store.afterReject(this);
19152 * Usually called by the {@link Roo.data.Store} which owns the Record.
19153 * Commits all changes made to the Record since either creation, or the last commit operation.
19155 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19156 * of commit operations.
19158 commit : function(){
19159 this.dirty = false;
19160 delete this.modified;
19161 this.editing = false;
19163 this.store.afterCommit(this);
19168 hasError : function(){
19169 return this.error != null;
19173 clearError : function(){
19178 * Creates a copy of this record.
19179 * @param {String} id (optional) A new record id if you don't want to use this record's id
19182 copy : function(newId) {
19183 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19187 * Ext JS Library 1.1.1
19188 * Copyright(c) 2006-2007, Ext JS, LLC.
19190 * Originally Released Under LGPL - original licence link has changed is not relivant.
19193 * <script type="text/javascript">
19199 * @class Roo.data.Store
19200 * @extends Roo.util.Observable
19201 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19202 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19204 * 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
19205 * has no knowledge of the format of the data returned by the Proxy.<br>
19207 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19208 * instances from the data object. These records are cached and made available through accessor functions.
19210 * Creates a new Store.
19211 * @param {Object} config A config object containing the objects needed for the Store to access data,
19212 * and read the data into Records.
19214 Roo.data.Store = function(config){
19215 this.data = new Roo.util.MixedCollection(false);
19216 this.data.getKey = function(o){
19219 this.baseParams = {};
19221 this.paramNames = {
19226 "multisort" : "_multisort"
19229 if(config && config.data){
19230 this.inlineData = config.data;
19231 delete config.data;
19234 Roo.apply(this, config);
19236 if(this.reader){ // reader passed
19237 this.reader = Roo.factory(this.reader, Roo.data);
19238 this.reader.xmodule = this.xmodule || false;
19239 if(!this.recordType){
19240 this.recordType = this.reader.recordType;
19242 if(this.reader.onMetaChange){
19243 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19247 if(this.recordType){
19248 this.fields = this.recordType.prototype.fields;
19250 this.modified = [];
19254 * @event datachanged
19255 * Fires when the data cache has changed, and a widget which is using this Store
19256 * as a Record cache should refresh its view.
19257 * @param {Store} this
19259 datachanged : true,
19261 * @event metachange
19262 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19263 * @param {Store} this
19264 * @param {Object} meta The JSON metadata
19269 * Fires when Records have been added to the Store
19270 * @param {Store} this
19271 * @param {Roo.data.Record[]} records The array of Records added
19272 * @param {Number} index The index at which the record(s) were added
19277 * Fires when a Record has been removed from the Store
19278 * @param {Store} this
19279 * @param {Roo.data.Record} record The Record that was removed
19280 * @param {Number} index The index at which the record was removed
19285 * Fires when a Record has been updated
19286 * @param {Store} this
19287 * @param {Roo.data.Record} record The Record that was updated
19288 * @param {String} operation The update operation being performed. Value may be one of:
19290 Roo.data.Record.EDIT
19291 Roo.data.Record.REJECT
19292 Roo.data.Record.COMMIT
19298 * Fires when the data cache has been cleared.
19299 * @param {Store} this
19303 * @event beforeload
19304 * Fires before a request is made for a new data object. If the beforeload handler returns false
19305 * the load action will be canceled.
19306 * @param {Store} this
19307 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19312 * Fires after a new set of Records has been loaded.
19313 * @param {Store} this
19314 * @param {Roo.data.Record[]} records The Records that were loaded
19315 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19319 * @event loadexception
19320 * Fires if an exception occurs in the Proxy during loading.
19321 * Called with the signature of the Proxy's "loadexception" event.
19322 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19325 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19326 * @param {Object} load options
19327 * @param {Object} jsonData from your request (normally this contains the Exception)
19329 loadexception : true
19333 this.proxy = Roo.factory(this.proxy, Roo.data);
19334 this.proxy.xmodule = this.xmodule || false;
19335 this.relayEvents(this.proxy, ["loadexception"]);
19337 this.sortToggle = {};
19338 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19340 Roo.data.Store.superclass.constructor.call(this);
19342 if(this.inlineData){
19343 this.loadData(this.inlineData);
19344 delete this.inlineData;
19347 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19349 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19350 * without a remote query - used by combo/forms at present.
19354 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19357 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19360 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19361 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19364 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19365 * on any HTTP request
19368 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19371 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19375 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19376 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19378 remoteSort : false,
19381 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19382 * loaded or when a record is removed. (defaults to false).
19384 pruneModifiedRecords : false,
19387 lastOptions : null,
19390 * Add Records to the Store and fires the add event.
19391 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19393 add : function(records){
19394 records = [].concat(records);
19395 for(var i = 0, len = records.length; i < len; i++){
19396 records[i].join(this);
19398 var index = this.data.length;
19399 this.data.addAll(records);
19400 this.fireEvent("add", this, records, index);
19404 * Remove a Record from the Store and fires the remove event.
19405 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19407 remove : function(record){
19408 var index = this.data.indexOf(record);
19409 this.data.removeAt(index);
19410 if(this.pruneModifiedRecords){
19411 this.modified.remove(record);
19413 this.fireEvent("remove", this, record, index);
19417 * Remove all Records from the Store and fires the clear event.
19419 removeAll : function(){
19421 if(this.pruneModifiedRecords){
19422 this.modified = [];
19424 this.fireEvent("clear", this);
19428 * Inserts Records to the Store at the given index and fires the add event.
19429 * @param {Number} index The start index at which to insert the passed Records.
19430 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19432 insert : function(index, records){
19433 records = [].concat(records);
19434 for(var i = 0, len = records.length; i < len; i++){
19435 this.data.insert(index, records[i]);
19436 records[i].join(this);
19438 this.fireEvent("add", this, records, index);
19442 * Get the index within the cache of the passed Record.
19443 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
19444 * @return {Number} The index of the passed Record. Returns -1 if not found.
19446 indexOf : function(record){
19447 return this.data.indexOf(record);
19451 * Get the index within the cache of the Record with the passed id.
19452 * @param {String} id The id of the Record to find.
19453 * @return {Number} The index of the Record. Returns -1 if not found.
19455 indexOfId : function(id){
19456 return this.data.indexOfKey(id);
19460 * Get the Record with the specified id.
19461 * @param {String} id The id of the Record to find.
19462 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
19464 getById : function(id){
19465 return this.data.key(id);
19469 * Get the Record at the specified index.
19470 * @param {Number} index The index of the Record to find.
19471 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
19473 getAt : function(index){
19474 return this.data.itemAt(index);
19478 * Returns a range of Records between specified indices.
19479 * @param {Number} startIndex (optional) The starting index (defaults to 0)
19480 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
19481 * @return {Roo.data.Record[]} An array of Records
19483 getRange : function(start, end){
19484 return this.data.getRange(start, end);
19488 storeOptions : function(o){
19489 o = Roo.apply({}, o);
19492 this.lastOptions = o;
19496 * Loads the Record cache from the configured Proxy using the configured Reader.
19498 * If using remote paging, then the first load call must specify the <em>start</em>
19499 * and <em>limit</em> properties in the options.params property to establish the initial
19500 * position within the dataset, and the number of Records to cache on each read from the Proxy.
19502 * <strong>It is important to note that for remote data sources, loading is asynchronous,
19503 * and this call will return before the new data has been loaded. Perform any post-processing
19504 * in a callback function, or in a "load" event handler.</strong>
19506 * @param {Object} options An object containing properties which control loading options:<ul>
19507 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
19508 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
19509 * passed the following arguments:<ul>
19510 * <li>r : Roo.data.Record[]</li>
19511 * <li>options: Options object from the load call</li>
19512 * <li>success: Boolean success indicator</li></ul></li>
19513 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
19514 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
19517 load : function(options){
19518 options = options || {};
19519 if(this.fireEvent("beforeload", this, options) !== false){
19520 this.storeOptions(options);
19521 var p = Roo.apply(options.params || {}, this.baseParams);
19522 // if meta was not loaded from remote source.. try requesting it.
19523 if (!this.reader.metaFromRemote) {
19524 p._requestMeta = 1;
19526 if(this.sortInfo && this.remoteSort){
19527 var pn = this.paramNames;
19528 p[pn["sort"]] = this.sortInfo.field;
19529 p[pn["dir"]] = this.sortInfo.direction;
19531 if (this.multiSort) {
19532 var pn = this.paramNames;
19533 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
19536 this.proxy.load(p, this.reader, this.loadRecords, this, options);
19541 * Reloads the Record cache from the configured Proxy using the configured Reader and
19542 * the options from the last load operation performed.
19543 * @param {Object} options (optional) An object containing properties which may override the options
19544 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
19545 * the most recently used options are reused).
19547 reload : function(options){
19548 this.load(Roo.applyIf(options||{}, this.lastOptions));
19552 // Called as a callback by the Reader during a load operation.
19553 loadRecords : function(o, options, success){
19554 if(!o || success === false){
19555 if(success !== false){
19556 this.fireEvent("load", this, [], options);
19558 if(options.callback){
19559 options.callback.call(options.scope || this, [], options, false);
19563 // if data returned failure - throw an exception.
19564 if (o.success === false) {
19565 // show a message if no listener is registered.
19566 if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
19567 Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
19569 // loadmask wil be hooked into this..
19570 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
19573 var r = o.records, t = o.totalRecords || r.length;
19574 if(!options || options.add !== true){
19575 if(this.pruneModifiedRecords){
19576 this.modified = [];
19578 for(var i = 0, len = r.length; i < len; i++){
19582 this.data = this.snapshot;
19583 delete this.snapshot;
19586 this.data.addAll(r);
19587 this.totalLength = t;
19589 this.fireEvent("datachanged", this);
19591 this.totalLength = Math.max(t, this.data.length+r.length);
19594 this.fireEvent("load", this, r, options);
19595 if(options.callback){
19596 options.callback.call(options.scope || this, r, options, true);
19602 * Loads data from a passed data block. A Reader which understands the format of the data
19603 * must have been configured in the constructor.
19604 * @param {Object} data The data block from which to read the Records. The format of the data expected
19605 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
19606 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
19608 loadData : function(o, append){
19609 var r = this.reader.readRecords(o);
19610 this.loadRecords(r, {add: append}, true);
19614 * Gets the number of cached records.
19616 * <em>If using paging, this may not be the total size of the dataset. If the data object
19617 * used by the Reader contains the dataset size, then the getTotalCount() function returns
19618 * the data set size</em>
19620 getCount : function(){
19621 return this.data.length || 0;
19625 * Gets the total number of records in the dataset as returned by the server.
19627 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
19628 * the dataset size</em>
19630 getTotalCount : function(){
19631 return this.totalLength || 0;
19635 * Returns the sort state of the Store as an object with two properties:
19637 field {String} The name of the field by which the Records are sorted
19638 direction {String} The sort order, "ASC" or "DESC"
19641 getSortState : function(){
19642 return this.sortInfo;
19646 applySort : function(){
19647 if(this.sortInfo && !this.remoteSort){
19648 var s = this.sortInfo, f = s.field;
19649 var st = this.fields.get(f).sortType;
19650 var fn = function(r1, r2){
19651 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
19652 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
19654 this.data.sort(s.direction, fn);
19655 if(this.snapshot && this.snapshot != this.data){
19656 this.snapshot.sort(s.direction, fn);
19662 * Sets the default sort column and order to be used by the next load operation.
19663 * @param {String} fieldName The name of the field to sort by.
19664 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19666 setDefaultSort : function(field, dir){
19667 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
19671 * Sort the Records.
19672 * If remote sorting is used, the sort is performed on the server, and the cache is
19673 * reloaded. If local sorting is used, the cache is sorted internally.
19674 * @param {String} fieldName The name of the field to sort by.
19675 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
19677 sort : function(fieldName, dir){
19678 var f = this.fields.get(fieldName);
19680 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
19682 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
19683 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
19688 this.sortToggle[f.name] = dir;
19689 this.sortInfo = {field: f.name, direction: dir};
19690 if(!this.remoteSort){
19692 this.fireEvent("datachanged", this);
19694 this.load(this.lastOptions);
19699 * Calls the specified function for each of the Records in the cache.
19700 * @param {Function} fn The function to call. The Record is passed as the first parameter.
19701 * Returning <em>false</em> aborts and exits the iteration.
19702 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
19704 each : function(fn, scope){
19705 this.data.each(fn, scope);
19709 * Gets all records modified since the last commit. Modified records are persisted across load operations
19710 * (e.g., during paging).
19711 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
19713 getModifiedRecords : function(){
19714 return this.modified;
19718 createFilterFn : function(property, value, anyMatch){
19719 if(!value.exec){ // not a regex
19720 value = String(value);
19721 if(value.length == 0){
19724 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
19726 return function(r){
19727 return value.test(r.data[property]);
19732 * Sums the value of <i>property</i> for each record between start and end and returns the result.
19733 * @param {String} property A field on your records
19734 * @param {Number} start The record index to start at (defaults to 0)
19735 * @param {Number} end The last record index to include (defaults to length - 1)
19736 * @return {Number} The sum
19738 sum : function(property, start, end){
19739 var rs = this.data.items, v = 0;
19740 start = start || 0;
19741 end = (end || end === 0) ? end : rs.length-1;
19743 for(var i = start; i <= end; i++){
19744 v += (rs[i].data[property] || 0);
19750 * Filter the records by a specified property.
19751 * @param {String} field A field on your records
19752 * @param {String/RegExp} value Either a string that the field
19753 * should start with or a RegExp to test against the field
19754 * @param {Boolean} anyMatch True to match any part not just the beginning
19756 filter : function(property, value, anyMatch){
19757 var fn = this.createFilterFn(property, value, anyMatch);
19758 return fn ? this.filterBy(fn) : this.clearFilter();
19762 * Filter by a function. The specified function will be called with each
19763 * record in this data source. If the function returns true the record is included,
19764 * otherwise it is filtered.
19765 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19766 * @param {Object} scope (optional) The scope of the function (defaults to this)
19768 filterBy : function(fn, scope){
19769 this.snapshot = this.snapshot || this.data;
19770 this.data = this.queryBy(fn, scope||this);
19771 this.fireEvent("datachanged", this);
19775 * Query the records by a specified property.
19776 * @param {String} field A field on your records
19777 * @param {String/RegExp} value Either a string that the field
19778 * should start with or a RegExp to test against the field
19779 * @param {Boolean} anyMatch True to match any part not just the beginning
19780 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19782 query : function(property, value, anyMatch){
19783 var fn = this.createFilterFn(property, value, anyMatch);
19784 return fn ? this.queryBy(fn) : this.data.clone();
19788 * Query by a function. The specified function will be called with each
19789 * record in this data source. If the function returns true the record is included
19791 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
19792 * @param {Object} scope (optional) The scope of the function (defaults to this)
19793 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
19795 queryBy : function(fn, scope){
19796 var data = this.snapshot || this.data;
19797 return data.filterBy(fn, scope||this);
19801 * Collects unique values for a particular dataIndex from this store.
19802 * @param {String} dataIndex The property to collect
19803 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
19804 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
19805 * @return {Array} An array of the unique values
19807 collect : function(dataIndex, allowNull, bypassFilter){
19808 var d = (bypassFilter === true && this.snapshot) ?
19809 this.snapshot.items : this.data.items;
19810 var v, sv, r = [], l = {};
19811 for(var i = 0, len = d.length; i < len; i++){
19812 v = d[i].data[dataIndex];
19814 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
19823 * Revert to a view of the Record cache with no filtering applied.
19824 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
19826 clearFilter : function(suppressEvent){
19827 if(this.snapshot && this.snapshot != this.data){
19828 this.data = this.snapshot;
19829 delete this.snapshot;
19830 if(suppressEvent !== true){
19831 this.fireEvent("datachanged", this);
19837 afterEdit : function(record){
19838 if(this.modified.indexOf(record) == -1){
19839 this.modified.push(record);
19841 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
19845 afterReject : function(record){
19846 this.modified.remove(record);
19847 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
19851 afterCommit : function(record){
19852 this.modified.remove(record);
19853 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
19857 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
19858 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
19860 commitChanges : function(){
19861 var m = this.modified.slice(0);
19862 this.modified = [];
19863 for(var i = 0, len = m.length; i < len; i++){
19869 * Cancel outstanding changes on all changed records.
19871 rejectChanges : function(){
19872 var m = this.modified.slice(0);
19873 this.modified = [];
19874 for(var i = 0, len = m.length; i < len; i++){
19879 onMetaChange : function(meta, rtype, o){
19880 this.recordType = rtype;
19881 this.fields = rtype.prototype.fields;
19882 delete this.snapshot;
19883 this.sortInfo = meta.sortInfo || this.sortInfo;
19884 this.modified = [];
19885 this.fireEvent('metachange', this, this.reader.meta);
19889 * Ext JS Library 1.1.1
19890 * Copyright(c) 2006-2007, Ext JS, LLC.
19892 * Originally Released Under LGPL - original licence link has changed is not relivant.
19895 * <script type="text/javascript">
19899 * @class Roo.data.SimpleStore
19900 * @extends Roo.data.Store
19901 * Small helper class to make creating Stores from Array data easier.
19902 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
19903 * @cfg {Array} fields An array of field definition objects, or field name strings.
19904 * @cfg {Array} data The multi-dimensional array of data
19906 * @param {Object} config
19908 Roo.data.SimpleStore = function(config){
19909 Roo.data.SimpleStore.superclass.constructor.call(this, {
19911 reader: new Roo.data.ArrayReader({
19914 Roo.data.Record.create(config.fields)
19916 proxy : new Roo.data.MemoryProxy(config.data)
19920 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
19922 * Ext JS Library 1.1.1
19923 * Copyright(c) 2006-2007, Ext JS, LLC.
19925 * Originally Released Under LGPL - original licence link has changed is not relivant.
19928 * <script type="text/javascript">
19933 * @extends Roo.data.Store
19934 * @class Roo.data.JsonStore
19935 * Small helper class to make creating Stores for JSON data easier. <br/>
19937 var store = new Roo.data.JsonStore({
19938 url: 'get-images.php',
19940 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
19943 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
19944 * JsonReader and HttpProxy (unless inline data is provided).</b>
19945 * @cfg {Array} fields An array of field definition objects, or field name strings.
19947 * @param {Object} config
19949 Roo.data.JsonStore = function(c){
19950 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
19951 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
19952 reader: new Roo.data.JsonReader(c, c.fields)
19955 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
19957 * Ext JS Library 1.1.1
19958 * Copyright(c) 2006-2007, Ext JS, LLC.
19960 * Originally Released Under LGPL - original licence link has changed is not relivant.
19963 * <script type="text/javascript">
19967 Roo.data.Field = function(config){
19968 if(typeof config == "string"){
19969 config = {name: config};
19971 Roo.apply(this, config);
19974 this.type = "auto";
19977 var st = Roo.data.SortTypes;
19978 // named sortTypes are supported, here we look them up
19979 if(typeof this.sortType == "string"){
19980 this.sortType = st[this.sortType];
19983 // set default sortType for strings and dates
19984 if(!this.sortType){
19987 this.sortType = st.asUCString;
19990 this.sortType = st.asDate;
19993 this.sortType = st.none;
19998 var stripRe = /[\$,%]/g;
20000 // prebuilt conversion function for this field, instead of
20001 // switching every time we're reading a value
20003 var cv, dateFormat = this.dateFormat;
20008 cv = function(v){ return v; };
20011 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20015 return v !== undefined && v !== null && v !== '' ?
20016 parseInt(String(v).replace(stripRe, ""), 10) : '';
20021 return v !== undefined && v !== null && v !== '' ?
20022 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20027 cv = function(v){ return v === true || v === "true" || v == 1; };
20034 if(v instanceof Date){
20038 if(dateFormat == "timestamp"){
20039 return new Date(v*1000);
20041 return Date.parseDate(v, dateFormat);
20043 var parsed = Date.parse(v);
20044 return parsed ? new Date(parsed) : null;
20053 Roo.data.Field.prototype = {
20061 * Ext JS Library 1.1.1
20062 * Copyright(c) 2006-2007, Ext JS, LLC.
20064 * Originally Released Under LGPL - original licence link has changed is not relivant.
20067 * <script type="text/javascript">
20070 // Base class for reading structured data from a data source. This class is intended to be
20071 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20074 * @class Roo.data.DataReader
20075 * Base class for reading structured data from a data source. This class is intended to be
20076 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20079 Roo.data.DataReader = function(meta, recordType){
20083 this.recordType = recordType instanceof Array ?
20084 Roo.data.Record.create(recordType) : recordType;
20087 Roo.data.DataReader.prototype = {
20089 * Create an empty record
20090 * @param {Object} data (optional) - overlay some values
20091 * @return {Roo.data.Record} record created.
20093 newRow : function(d) {
20095 this.recordType.prototype.fields.each(function(c) {
20097 case 'int' : da[c.name] = 0; break;
20098 case 'date' : da[c.name] = new Date(); break;
20099 case 'float' : da[c.name] = 0.0; break;
20100 case 'boolean' : da[c.name] = false; break;
20101 default : da[c.name] = ""; break;
20105 return new this.recordType(Roo.apply(da, d));
20110 * Ext JS Library 1.1.1
20111 * Copyright(c) 2006-2007, Ext JS, LLC.
20113 * Originally Released Under LGPL - original licence link has changed is not relivant.
20116 * <script type="text/javascript">
20120 * @class Roo.data.DataProxy
20121 * @extends Roo.data.Observable
20122 * This class is an abstract base class for implementations which provide retrieval of
20123 * unformatted data objects.<br>
20125 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20126 * (of the appropriate type which knows how to parse the data object) to provide a block of
20127 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20129 * Custom implementations must implement the load method as described in
20130 * {@link Roo.data.HttpProxy#load}.
20132 Roo.data.DataProxy = function(){
20135 * @event beforeload
20136 * Fires before a network request is made to retrieve a data object.
20137 * @param {Object} This DataProxy object.
20138 * @param {Object} params The params parameter to the load function.
20143 * Fires before the load method's callback is called.
20144 * @param {Object} This DataProxy object.
20145 * @param {Object} o The data object.
20146 * @param {Object} arg The callback argument object passed to the load function.
20150 * @event loadexception
20151 * Fires if an Exception occurs during data retrieval.
20152 * @param {Object} This DataProxy object.
20153 * @param {Object} o The data object.
20154 * @param {Object} arg The callback argument object passed to the load function.
20155 * @param {Object} e The Exception.
20157 loadexception : true
20159 Roo.data.DataProxy.superclass.constructor.call(this);
20162 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20165 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20169 * Ext JS Library 1.1.1
20170 * Copyright(c) 2006-2007, Ext JS, LLC.
20172 * Originally Released Under LGPL - original licence link has changed is not relivant.
20175 * <script type="text/javascript">
20178 * @class Roo.data.MemoryProxy
20179 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20180 * to the Reader when its load method is called.
20182 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20184 Roo.data.MemoryProxy = function(data){
20188 Roo.data.MemoryProxy.superclass.constructor.call(this);
20192 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20194 * Load data from the requested source (in this case an in-memory
20195 * data object passed to the constructor), read the data object into
20196 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20197 * process that block using the passed callback.
20198 * @param {Object} params This parameter is not used by the MemoryProxy class.
20199 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20200 * object into a block of Roo.data.Records.
20201 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20202 * The function must be passed <ul>
20203 * <li>The Record block object</li>
20204 * <li>The "arg" argument from the load function</li>
20205 * <li>A boolean success indicator</li>
20207 * @param {Object} scope The scope in which to call the callback
20208 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20210 load : function(params, reader, callback, scope, arg){
20211 params = params || {};
20214 result = reader.readRecords(this.data);
20216 this.fireEvent("loadexception", this, arg, null, e);
20217 callback.call(scope, null, arg, false);
20220 callback.call(scope, result, arg, true);
20224 update : function(params, records){
20229 * Ext JS Library 1.1.1
20230 * Copyright(c) 2006-2007, Ext JS, LLC.
20232 * Originally Released Under LGPL - original licence link has changed is not relivant.
20235 * <script type="text/javascript">
20238 * @class Roo.data.HttpProxy
20239 * @extends Roo.data.DataProxy
20240 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20241 * configured to reference a certain URL.<br><br>
20243 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20244 * from which the running page was served.<br><br>
20246 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20248 * Be aware that to enable the browser to parse an XML document, the server must set
20249 * the Content-Type header in the HTTP response to "text/xml".
20251 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20252 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20253 * will be used to make the request.
20255 Roo.data.HttpProxy = function(conn){
20256 Roo.data.HttpProxy.superclass.constructor.call(this);
20257 // is conn a conn config or a real conn?
20259 this.useAjax = !conn || !conn.events;
20263 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20264 // thse are take from connection...
20267 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20270 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20271 * extra parameters to each request made by this object. (defaults to undefined)
20274 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20275 * to each request made by this object. (defaults to undefined)
20278 * @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)
20281 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20284 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20290 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20294 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20295 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20296 * a finer-grained basis than the DataProxy events.
20298 getConnection : function(){
20299 return this.useAjax ? Roo.Ajax : this.conn;
20303 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20304 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20305 * process that block using the passed callback.
20306 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20307 * for the request to the remote server.
20308 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20309 * object into a block of Roo.data.Records.
20310 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20311 * The function must be passed <ul>
20312 * <li>The Record block object</li>
20313 * <li>The "arg" argument from the load function</li>
20314 * <li>A boolean success indicator</li>
20316 * @param {Object} scope The scope in which to call the callback
20317 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20319 load : function(params, reader, callback, scope, arg){
20320 if(this.fireEvent("beforeload", this, params) !== false){
20322 params : params || {},
20324 callback : callback,
20329 callback : this.loadResponse,
20333 Roo.applyIf(o, this.conn);
20334 if(this.activeRequest){
20335 Roo.Ajax.abort(this.activeRequest);
20337 this.activeRequest = Roo.Ajax.request(o);
20339 this.conn.request(o);
20342 callback.call(scope||this, null, arg, false);
20347 loadResponse : function(o, success, response){
20348 delete this.activeRequest;
20350 this.fireEvent("loadexception", this, o, response);
20351 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20356 result = o.reader.read(response);
20358 this.fireEvent("loadexception", this, o, response, e);
20359 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20363 this.fireEvent("load", this, o, o.request.arg);
20364 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20368 update : function(dataSet){
20373 updateResponse : function(dataSet){
20378 * Ext JS Library 1.1.1
20379 * Copyright(c) 2006-2007, Ext JS, LLC.
20381 * Originally Released Under LGPL - original licence link has changed is not relivant.
20384 * <script type="text/javascript">
20388 * @class Roo.data.ScriptTagProxy
20389 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20390 * other than the originating domain of the running page.<br><br>
20392 * <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
20393 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20395 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20396 * source code that is used as the source inside a <script> tag.<br><br>
20398 * In order for the browser to process the returned data, the server must wrap the data object
20399 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20400 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20401 * depending on whether the callback name was passed:
20404 boolean scriptTag = false;
20405 String cb = request.getParameter("callback");
20408 response.setContentType("text/javascript");
20410 response.setContentType("application/x-json");
20412 Writer out = response.getWriter();
20414 out.write(cb + "(");
20416 out.print(dataBlock.toJsonString());
20423 * @param {Object} config A configuration object.
20425 Roo.data.ScriptTagProxy = function(config){
20426 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
20427 Roo.apply(this, config);
20428 this.head = document.getElementsByTagName("head")[0];
20431 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
20433 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
20435 * @cfg {String} url The URL from which to request the data object.
20438 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
20442 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
20443 * the server the name of the callback function set up by the load call to process the returned data object.
20444 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
20445 * javascript output which calls this named function passing the data object as its only parameter.
20447 callbackParam : "callback",
20449 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
20450 * name to the request.
20455 * Load data from the configured URL, read the data object into
20456 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20457 * process that block using the passed callback.
20458 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20459 * for the request to the remote server.
20460 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20461 * object into a block of Roo.data.Records.
20462 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20463 * The function must be passed <ul>
20464 * <li>The Record block object</li>
20465 * <li>The "arg" argument from the load function</li>
20466 * <li>A boolean success indicator</li>
20468 * @param {Object} scope The scope in which to call the callback
20469 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20471 load : function(params, reader, callback, scope, arg){
20472 if(this.fireEvent("beforeload", this, params) !== false){
20474 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
20476 var url = this.url;
20477 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
20479 url += "&_dc=" + (new Date().getTime());
20481 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
20484 cb : "stcCallback"+transId,
20485 scriptId : "stcScript"+transId,
20489 callback : callback,
20495 window[trans.cb] = function(o){
20496 conn.handleResponse(o, trans);
20499 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
20501 if(this.autoAbort !== false){
20505 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
20507 var script = document.createElement("script");
20508 script.setAttribute("src", url);
20509 script.setAttribute("type", "text/javascript");
20510 script.setAttribute("id", trans.scriptId);
20511 this.head.appendChild(script);
20513 this.trans = trans;
20515 callback.call(scope||this, null, arg, false);
20520 isLoading : function(){
20521 return this.trans ? true : false;
20525 * Abort the current server request.
20527 abort : function(){
20528 if(this.isLoading()){
20529 this.destroyTrans(this.trans);
20534 destroyTrans : function(trans, isLoaded){
20535 this.head.removeChild(document.getElementById(trans.scriptId));
20536 clearTimeout(trans.timeoutId);
20538 window[trans.cb] = undefined;
20540 delete window[trans.cb];
20543 // if hasn't been loaded, wait for load to remove it to prevent script error
20544 window[trans.cb] = function(){
20545 window[trans.cb] = undefined;
20547 delete window[trans.cb];
20554 handleResponse : function(o, trans){
20555 this.trans = false;
20556 this.destroyTrans(trans, true);
20559 result = trans.reader.readRecords(o);
20561 this.fireEvent("loadexception", this, o, trans.arg, e);
20562 trans.callback.call(trans.scope||window, null, trans.arg, false);
20565 this.fireEvent("load", this, o, trans.arg);
20566 trans.callback.call(trans.scope||window, result, trans.arg, true);
20570 handleFailure : function(trans){
20571 this.trans = false;
20572 this.destroyTrans(trans, false);
20573 this.fireEvent("loadexception", this, null, trans.arg);
20574 trans.callback.call(trans.scope||window, null, trans.arg, false);
20578 * Ext JS Library 1.1.1
20579 * Copyright(c) 2006-2007, Ext JS, LLC.
20581 * Originally Released Under LGPL - original licence link has changed is not relivant.
20584 * <script type="text/javascript">
20588 * @class Roo.data.JsonReader
20589 * @extends Roo.data.DataReader
20590 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
20591 * based on mappings in a provided Roo.data.Record constructor.
20593 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
20594 * in the reply previously.
20599 var RecordDef = Roo.data.Record.create([
20600 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20601 {name: 'occupation'} // This field will use "occupation" as the mapping.
20603 var myReader = new Roo.data.JsonReader({
20604 totalProperty: "results", // The property which contains the total dataset size (optional)
20605 root: "rows", // The property which contains an Array of row objects
20606 id: "id" // The property within each row object that provides an ID for the record (optional)
20610 * This would consume a JSON file like this:
20612 { 'results': 2, 'rows': [
20613 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
20614 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
20617 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
20618 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20619 * paged from the remote server.
20620 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
20621 * @cfg {String} root name of the property which contains the Array of row objects.
20622 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
20624 * Create a new JsonReader
20625 * @param {Object} meta Metadata configuration options
20626 * @param {Object} recordType Either an Array of field definition objects,
20627 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
20629 Roo.data.JsonReader = function(meta, recordType){
20632 // set some defaults:
20633 Roo.applyIf(meta, {
20634 totalProperty: 'total',
20635 successProperty : 'success',
20640 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20642 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
20645 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
20646 * Used by Store query builder to append _requestMeta to params.
20649 metaFromRemote : false,
20651 * This method is only used by a DataProxy which has retrieved data from a remote server.
20652 * @param {Object} response The XHR object which contains the JSON data in its responseText.
20653 * @return {Object} data A data block which is used by an Roo.data.Store object as
20654 * a cache of Roo.data.Records.
20656 read : function(response){
20657 var json = response.responseText;
20659 var o = /* eval:var:o */ eval("("+json+")");
20661 throw {message: "JsonReader.read: Json object not found"};
20667 this.metaFromRemote = true;
20668 this.meta = o.metaData;
20669 this.recordType = Roo.data.Record.create(o.metaData.fields);
20670 this.onMetaChange(this.meta, this.recordType, o);
20672 return this.readRecords(o);
20675 // private function a store will implement
20676 onMetaChange : function(meta, recordType, o){
20683 simpleAccess: function(obj, subsc) {
20690 getJsonAccessor: function(){
20692 return function(expr) {
20694 return(re.test(expr))
20695 ? new Function("obj", "return obj." + expr)
20700 return Roo.emptyFn;
20705 * Create a data block containing Roo.data.Records from an XML document.
20706 * @param {Object} o An object which contains an Array of row objects in the property specified
20707 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
20708 * which contains the total size of the dataset.
20709 * @return {Object} data A data block which is used by an Roo.data.Store object as
20710 * a cache of Roo.data.Records.
20712 readRecords : function(o){
20714 * After any data loads, the raw JSON data is available for further custom processing.
20718 var s = this.meta, Record = this.recordType,
20719 f = Record.prototype.fields, fi = f.items, fl = f.length;
20721 // Generate extraction functions for the totalProperty, the root, the id, and for each field
20723 if(s.totalProperty) {
20724 this.getTotal = this.getJsonAccessor(s.totalProperty);
20726 if(s.successProperty) {
20727 this.getSuccess = this.getJsonAccessor(s.successProperty);
20729 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
20731 var g = this.getJsonAccessor(s.id);
20732 this.getId = function(rec) {
20734 return (r === undefined || r === "") ? null : r;
20737 this.getId = function(){return null;};
20740 for(var jj = 0; jj < fl; jj++){
20742 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
20743 this.ef[jj] = this.getJsonAccessor(map);
20747 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
20748 if(s.totalProperty){
20749 var vt = parseInt(this.getTotal(o), 10);
20754 if(s.successProperty){
20755 var vs = this.getSuccess(o);
20756 if(vs === false || vs === 'false'){
20761 for(var i = 0; i < c; i++){
20764 var id = this.getId(n);
20765 for(var j = 0; j < fl; j++){
20767 var v = this.ef[j](n);
20769 Roo.log('missing convert for ' + f.name);
20773 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
20775 var record = new Record(values, id);
20777 records[i] = record;
20782 totalRecords : totalRecords
20787 * Ext JS Library 1.1.1
20788 * Copyright(c) 2006-2007, Ext JS, LLC.
20790 * Originally Released Under LGPL - original licence link has changed is not relivant.
20793 * <script type="text/javascript">
20797 * @class Roo.data.XmlReader
20798 * @extends Roo.data.DataReader
20799 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
20800 * based on mappings in a provided Roo.data.Record constructor.<br><br>
20802 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
20803 * header in the HTTP response must be set to "text/xml".</em>
20807 var RecordDef = Roo.data.Record.create([
20808 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
20809 {name: 'occupation'} // This field will use "occupation" as the mapping.
20811 var myReader = new Roo.data.XmlReader({
20812 totalRecords: "results", // The element which contains the total dataset size (optional)
20813 record: "row", // The repeated element which contains row information
20814 id: "id" // The element within the row that provides an ID for the record (optional)
20818 * This would consume an XML file like this:
20822 <results>2</results>
20825 <name>Bill</name>
20826 <occupation>Gardener</occupation>
20830 <name>Ben</name>
20831 <occupation>Horticulturalist</occupation>
20835 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
20836 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
20837 * paged from the remote server.
20838 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
20839 * @cfg {String} success The DomQuery path to the success attribute used by forms.
20840 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
20841 * a record identifier value.
20843 * Create a new XmlReader
20844 * @param {Object} meta Metadata configuration options
20845 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
20846 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
20847 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
20849 Roo.data.XmlReader = function(meta, recordType){
20851 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
20853 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
20855 * This method is only used by a DataProxy which has retrieved data from a remote server.
20856 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
20857 * to contain a method called 'responseXML' that returns an XML document object.
20858 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20859 * a cache of Roo.data.Records.
20861 read : function(response){
20862 var doc = response.responseXML;
20864 throw {message: "XmlReader.read: XML Document not available"};
20866 return this.readRecords(doc);
20870 * Create a data block containing Roo.data.Records from an XML document.
20871 * @param {Object} doc A parsed XML document.
20872 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
20873 * a cache of Roo.data.Records.
20875 readRecords : function(doc){
20877 * After any data loads/reads, the raw XML Document is available for further custom processing.
20878 * @type XMLDocument
20880 this.xmlData = doc;
20881 var root = doc.documentElement || doc;
20882 var q = Roo.DomQuery;
20883 var recordType = this.recordType, fields = recordType.prototype.fields;
20884 var sid = this.meta.id;
20885 var totalRecords = 0, success = true;
20886 if(this.meta.totalRecords){
20887 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
20890 if(this.meta.success){
20891 var sv = q.selectValue(this.meta.success, root, true);
20892 success = sv !== false && sv !== 'false';
20895 var ns = q.select(this.meta.record, root);
20896 for(var i = 0, len = ns.length; i < len; i++) {
20899 var id = sid ? q.selectValue(sid, n) : undefined;
20900 for(var j = 0, jlen = fields.length; j < jlen; j++){
20901 var f = fields.items[j];
20902 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
20904 values[f.name] = v;
20906 var record = new recordType(values, id);
20908 records[records.length] = record;
20914 totalRecords : totalRecords || records.length
20919 * Ext JS Library 1.1.1
20920 * Copyright(c) 2006-2007, Ext JS, LLC.
20922 * Originally Released Under LGPL - original licence link has changed is not relivant.
20925 * <script type="text/javascript">
20929 * @class Roo.data.ArrayReader
20930 * @extends Roo.data.DataReader
20931 * Data reader class to create an Array of Roo.data.Record objects from an Array.
20932 * Each element of that Array represents a row of data fields. The
20933 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
20934 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
20938 var RecordDef = Roo.data.Record.create([
20939 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
20940 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
20942 var myReader = new Roo.data.ArrayReader({
20943 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
20947 * This would consume an Array like this:
20949 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
20951 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
20953 * Create a new JsonReader
20954 * @param {Object} meta Metadata configuration options.
20955 * @param {Object} recordType Either an Array of field definition objects
20956 * as specified to {@link Roo.data.Record#create},
20957 * or an {@link Roo.data.Record} object
20958 * created using {@link Roo.data.Record#create}.
20960 Roo.data.ArrayReader = function(meta, recordType){
20961 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
20964 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
20966 * Create a data block containing Roo.data.Records from an XML document.
20967 * @param {Object} o An Array of row objects which represents the dataset.
20968 * @return {Object} data A data block which is used by an Roo.data.Store object as
20969 * a cache of Roo.data.Records.
20971 readRecords : function(o){
20972 var sid = this.meta ? this.meta.id : null;
20973 var recordType = this.recordType, fields = recordType.prototype.fields;
20976 for(var i = 0; i < root.length; i++){
20979 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
20980 for(var j = 0, jlen = fields.length; j < jlen; j++){
20981 var f = fields.items[j];
20982 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
20983 var v = n[k] !== undefined ? n[k] : f.defaultValue;
20985 values[f.name] = v;
20987 var record = new recordType(values, id);
20989 records[records.length] = record;
20993 totalRecords : records.length
20998 * Ext JS Library 1.1.1
20999 * Copyright(c) 2006-2007, Ext JS, LLC.
21001 * Originally Released Under LGPL - original licence link has changed is not relivant.
21004 * <script type="text/javascript">
21009 * @class Roo.data.Tree
21010 * @extends Roo.util.Observable
21011 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21012 * in the tree have most standard DOM functionality.
21014 * @param {Node} root (optional) The root node
21016 Roo.data.Tree = function(root){
21017 this.nodeHash = {};
21019 * The root node for this tree
21024 this.setRootNode(root);
21029 * Fires when a new child node is appended to a node in this tree.
21030 * @param {Tree} tree The owner tree
21031 * @param {Node} parent The parent node
21032 * @param {Node} node The newly appended node
21033 * @param {Number} index The index of the newly appended node
21038 * Fires when a child node is removed from a node in this tree.
21039 * @param {Tree} tree The owner tree
21040 * @param {Node} parent The parent node
21041 * @param {Node} node The child node removed
21046 * Fires when a node is moved to a new location in the tree
21047 * @param {Tree} tree The owner tree
21048 * @param {Node} node The node moved
21049 * @param {Node} oldParent The old parent of this node
21050 * @param {Node} newParent The new parent of this node
21051 * @param {Number} index The index it was moved to
21056 * Fires when a new child node is inserted in a node in this tree.
21057 * @param {Tree} tree The owner tree
21058 * @param {Node} parent The parent node
21059 * @param {Node} node The child node inserted
21060 * @param {Node} refNode The child node the node was inserted before
21064 * @event beforeappend
21065 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21066 * @param {Tree} tree The owner tree
21067 * @param {Node} parent The parent node
21068 * @param {Node} node The child node to be appended
21070 "beforeappend" : true,
21072 * @event beforeremove
21073 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21074 * @param {Tree} tree The owner tree
21075 * @param {Node} parent The parent node
21076 * @param {Node} node The child node to be removed
21078 "beforeremove" : true,
21080 * @event beforemove
21081 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21082 * @param {Tree} tree The owner tree
21083 * @param {Node} node The node being moved
21084 * @param {Node} oldParent The parent of the node
21085 * @param {Node} newParent The new parent the node is moving to
21086 * @param {Number} index The index it is being moved to
21088 "beforemove" : true,
21090 * @event beforeinsert
21091 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21092 * @param {Tree} tree The owner tree
21093 * @param {Node} parent The parent node
21094 * @param {Node} node The child node to be inserted
21095 * @param {Node} refNode The child node the node is being inserted before
21097 "beforeinsert" : true
21100 Roo.data.Tree.superclass.constructor.call(this);
21103 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21104 pathSeparator: "/",
21106 proxyNodeEvent : function(){
21107 return this.fireEvent.apply(this, arguments);
21111 * Returns the root node for this tree.
21114 getRootNode : function(){
21119 * Sets the root node for this tree.
21120 * @param {Node} node
21123 setRootNode : function(node){
21125 node.ownerTree = this;
21126 node.isRoot = true;
21127 this.registerNode(node);
21132 * Gets a node in this tree by its id.
21133 * @param {String} id
21136 getNodeById : function(id){
21137 return this.nodeHash[id];
21140 registerNode : function(node){
21141 this.nodeHash[node.id] = node;
21144 unregisterNode : function(node){
21145 delete this.nodeHash[node.id];
21148 toString : function(){
21149 return "[Tree"+(this.id?" "+this.id:"")+"]";
21154 * @class Roo.data.Node
21155 * @extends Roo.util.Observable
21156 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21157 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21159 * @param {Object} attributes The attributes/config for the node
21161 Roo.data.Node = function(attributes){
21163 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21166 this.attributes = attributes || {};
21167 this.leaf = this.attributes.leaf;
21169 * The node id. @type String
21171 this.id = this.attributes.id;
21173 this.id = Roo.id(null, "ynode-");
21174 this.attributes.id = this.id;
21177 * All child nodes of this node. @type Array
21179 this.childNodes = [];
21180 if(!this.childNodes.indexOf){ // indexOf is a must
21181 this.childNodes.indexOf = function(o){
21182 for(var i = 0, len = this.length; i < len; i++){
21191 * The parent node for this node. @type Node
21193 this.parentNode = null;
21195 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21197 this.firstChild = null;
21199 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21201 this.lastChild = null;
21203 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21205 this.previousSibling = null;
21207 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21209 this.nextSibling = null;
21214 * Fires when a new child node is appended
21215 * @param {Tree} tree The owner tree
21216 * @param {Node} this This node
21217 * @param {Node} node The newly appended node
21218 * @param {Number} index The index of the newly appended node
21223 * Fires when a child node is removed
21224 * @param {Tree} tree The owner tree
21225 * @param {Node} this This node
21226 * @param {Node} node The removed node
21231 * Fires when this node is moved to a new location in the tree
21232 * @param {Tree} tree The owner tree
21233 * @param {Node} this This node
21234 * @param {Node} oldParent The old parent of this node
21235 * @param {Node} newParent The new parent of this node
21236 * @param {Number} index The index it was moved to
21241 * Fires when a new child node is inserted.
21242 * @param {Tree} tree The owner tree
21243 * @param {Node} this This node
21244 * @param {Node} node The child node inserted
21245 * @param {Node} refNode The child node the node was inserted before
21249 * @event beforeappend
21250 * Fires before a new child is appended, return false to cancel the append.
21251 * @param {Tree} tree The owner tree
21252 * @param {Node} this This node
21253 * @param {Node} node The child node to be appended
21255 "beforeappend" : true,
21257 * @event beforeremove
21258 * Fires before a child is removed, return false to cancel the remove.
21259 * @param {Tree} tree The owner tree
21260 * @param {Node} this This node
21261 * @param {Node} node The child node to be removed
21263 "beforeremove" : true,
21265 * @event beforemove
21266 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21267 * @param {Tree} tree The owner tree
21268 * @param {Node} this This node
21269 * @param {Node} oldParent The parent of this node
21270 * @param {Node} newParent The new parent this node is moving to
21271 * @param {Number} index The index it is being moved to
21273 "beforemove" : true,
21275 * @event beforeinsert
21276 * Fires before a new child is inserted, return false to cancel the insert.
21277 * @param {Tree} tree The owner tree
21278 * @param {Node} this This node
21279 * @param {Node} node The child node to be inserted
21280 * @param {Node} refNode The child node the node is being inserted before
21282 "beforeinsert" : true
21284 this.listeners = this.attributes.listeners;
21285 Roo.data.Node.superclass.constructor.call(this);
21288 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21289 fireEvent : function(evtName){
21290 // first do standard event for this node
21291 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21294 // then bubble it up to the tree if the event wasn't cancelled
21295 var ot = this.getOwnerTree();
21297 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21305 * Returns true if this node is a leaf
21306 * @return {Boolean}
21308 isLeaf : function(){
21309 return this.leaf === true;
21313 setFirstChild : function(node){
21314 this.firstChild = node;
21318 setLastChild : function(node){
21319 this.lastChild = node;
21324 * Returns true if this node is the last child of its parent
21325 * @return {Boolean}
21327 isLast : function(){
21328 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21332 * Returns true if this node is the first child of its parent
21333 * @return {Boolean}
21335 isFirst : function(){
21336 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21339 hasChildNodes : function(){
21340 return !this.isLeaf() && this.childNodes.length > 0;
21344 * Insert node(s) as the last child node of this node.
21345 * @param {Node/Array} node The node or Array of nodes to append
21346 * @return {Node} The appended node if single append, or null if an array was passed
21348 appendChild : function(node){
21350 if(node instanceof Array){
21352 }else if(arguments.length > 1){
21355 // if passed an array or multiple args do them one by one
21357 for(var i = 0, len = multi.length; i < len; i++) {
21358 this.appendChild(multi[i]);
21361 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21364 var index = this.childNodes.length;
21365 var oldParent = node.parentNode;
21366 // it's a move, make sure we move it cleanly
21368 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21371 oldParent.removeChild(node);
21373 index = this.childNodes.length;
21375 this.setFirstChild(node);
21377 this.childNodes.push(node);
21378 node.parentNode = this;
21379 var ps = this.childNodes[index-1];
21381 node.previousSibling = ps;
21382 ps.nextSibling = node;
21384 node.previousSibling = null;
21386 node.nextSibling = null;
21387 this.setLastChild(node);
21388 node.setOwnerTree(this.getOwnerTree());
21389 this.fireEvent("append", this.ownerTree, this, node, index);
21391 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21398 * Removes a child node from this node.
21399 * @param {Node} node The node to remove
21400 * @return {Node} The removed node
21402 removeChild : function(node){
21403 var index = this.childNodes.indexOf(node);
21407 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21411 // remove it from childNodes collection
21412 this.childNodes.splice(index, 1);
21415 if(node.previousSibling){
21416 node.previousSibling.nextSibling = node.nextSibling;
21418 if(node.nextSibling){
21419 node.nextSibling.previousSibling = node.previousSibling;
21422 // update child refs
21423 if(this.firstChild == node){
21424 this.setFirstChild(node.nextSibling);
21426 if(this.lastChild == node){
21427 this.setLastChild(node.previousSibling);
21430 node.setOwnerTree(null);
21431 // clear any references from the node
21432 node.parentNode = null;
21433 node.previousSibling = null;
21434 node.nextSibling = null;
21435 this.fireEvent("remove", this.ownerTree, this, node);
21440 * Inserts the first node before the second node in this nodes childNodes collection.
21441 * @param {Node} node The node to insert
21442 * @param {Node} refNode The node to insert before (if null the node is appended)
21443 * @return {Node} The inserted node
21445 insertBefore : function(node, refNode){
21446 if(!refNode){ // like standard Dom, refNode can be null for append
21447 return this.appendChild(node);
21450 if(node == refNode){
21454 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
21457 var index = this.childNodes.indexOf(refNode);
21458 var oldParent = node.parentNode;
21459 var refIndex = index;
21461 // when moving internally, indexes will change after remove
21462 if(oldParent == this && this.childNodes.indexOf(node) < index){
21466 // it's a move, make sure we move it cleanly
21468 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
21471 oldParent.removeChild(node);
21474 this.setFirstChild(node);
21476 this.childNodes.splice(refIndex, 0, node);
21477 node.parentNode = this;
21478 var ps = this.childNodes[refIndex-1];
21480 node.previousSibling = ps;
21481 ps.nextSibling = node;
21483 node.previousSibling = null;
21485 node.nextSibling = refNode;
21486 refNode.previousSibling = node;
21487 node.setOwnerTree(this.getOwnerTree());
21488 this.fireEvent("insert", this.ownerTree, this, node, refNode);
21490 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
21496 * Returns the child node at the specified index.
21497 * @param {Number} index
21500 item : function(index){
21501 return this.childNodes[index];
21505 * Replaces one child node in this node with another.
21506 * @param {Node} newChild The replacement node
21507 * @param {Node} oldChild The node to replace
21508 * @return {Node} The replaced node
21510 replaceChild : function(newChild, oldChild){
21511 this.insertBefore(newChild, oldChild);
21512 this.removeChild(oldChild);
21517 * Returns the index of a child node
21518 * @param {Node} node
21519 * @return {Number} The index of the node or -1 if it was not found
21521 indexOf : function(child){
21522 return this.childNodes.indexOf(child);
21526 * Returns the tree this node is in.
21529 getOwnerTree : function(){
21530 // if it doesn't have one, look for one
21531 if(!this.ownerTree){
21535 this.ownerTree = p.ownerTree;
21541 return this.ownerTree;
21545 * Returns depth of this node (the root node has a depth of 0)
21548 getDepth : function(){
21551 while(p.parentNode){
21559 setOwnerTree : function(tree){
21560 // if it's move, we need to update everyone
21561 if(tree != this.ownerTree){
21562 if(this.ownerTree){
21563 this.ownerTree.unregisterNode(this);
21565 this.ownerTree = tree;
21566 var cs = this.childNodes;
21567 for(var i = 0, len = cs.length; i < len; i++) {
21568 cs[i].setOwnerTree(tree);
21571 tree.registerNode(this);
21577 * Returns the path for this node. The path can be used to expand or select this node programmatically.
21578 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
21579 * @return {String} The path
21581 getPath : function(attr){
21582 attr = attr || "id";
21583 var p = this.parentNode;
21584 var b = [this.attributes[attr]];
21586 b.unshift(p.attributes[attr]);
21589 var sep = this.getOwnerTree().pathSeparator;
21590 return sep + b.join(sep);
21594 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21595 * function call will be the scope provided or the current node. The arguments to the function
21596 * will be the args provided or the current node. If the function returns false at any point,
21597 * the bubble is stopped.
21598 * @param {Function} fn The function to call
21599 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21600 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21602 bubble : function(fn, scope, args){
21605 if(fn.call(scope || p, args || p) === false){
21613 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
21614 * function call will be the scope provided or the current node. The arguments to the function
21615 * will be the args provided or the current node. If the function returns false at any point,
21616 * the cascade is stopped on that branch.
21617 * @param {Function} fn The function to call
21618 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21619 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21621 cascade : function(fn, scope, args){
21622 if(fn.call(scope || this, args || this) !== false){
21623 var cs = this.childNodes;
21624 for(var i = 0, len = cs.length; i < len; i++) {
21625 cs[i].cascade(fn, scope, args);
21631 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
21632 * function call will be the scope provided or the current node. The arguments to the function
21633 * will be the args provided or the current node. If the function returns false at any point,
21634 * the iteration stops.
21635 * @param {Function} fn The function to call
21636 * @param {Object} scope (optional) The scope of the function (defaults to current node)
21637 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
21639 eachChild : function(fn, scope, args){
21640 var cs = this.childNodes;
21641 for(var i = 0, len = cs.length; i < len; i++) {
21642 if(fn.call(scope || this, args || cs[i]) === false){
21649 * Finds the first child that has the attribute with the specified value.
21650 * @param {String} attribute The attribute name
21651 * @param {Mixed} value The value to search for
21652 * @return {Node} The found child or null if none was found
21654 findChild : function(attribute, value){
21655 var cs = this.childNodes;
21656 for(var i = 0, len = cs.length; i < len; i++) {
21657 if(cs[i].attributes[attribute] == value){
21665 * Finds the first child by a custom function. The child matches if the function passed
21667 * @param {Function} fn
21668 * @param {Object} scope (optional)
21669 * @return {Node} The found child or null if none was found
21671 findChildBy : function(fn, scope){
21672 var cs = this.childNodes;
21673 for(var i = 0, len = cs.length; i < len; i++) {
21674 if(fn.call(scope||cs[i], cs[i]) === true){
21682 * Sorts this nodes children using the supplied sort function
21683 * @param {Function} fn
21684 * @param {Object} scope (optional)
21686 sort : function(fn, scope){
21687 var cs = this.childNodes;
21688 var len = cs.length;
21690 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
21692 for(var i = 0; i < len; i++){
21694 n.previousSibling = cs[i-1];
21695 n.nextSibling = cs[i+1];
21697 this.setFirstChild(n);
21700 this.setLastChild(n);
21707 * Returns true if this node is an ancestor (at any point) of the passed node.
21708 * @param {Node} node
21709 * @return {Boolean}
21711 contains : function(node){
21712 return node.isAncestor(this);
21716 * Returns true if the passed node is an ancestor (at any point) of this node.
21717 * @param {Node} node
21718 * @return {Boolean}
21720 isAncestor : function(node){
21721 var p = this.parentNode;
21731 toString : function(){
21732 return "[Node"+(this.id?" "+this.id:"")+"]";
21736 * Ext JS Library 1.1.1
21737 * Copyright(c) 2006-2007, Ext JS, LLC.
21739 * Originally Released Under LGPL - original licence link has changed is not relivant.
21742 * <script type="text/javascript">
21747 * @class Roo.ComponentMgr
21748 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
21751 Roo.ComponentMgr = function(){
21752 var all = new Roo.util.MixedCollection();
21756 * Registers a component.
21757 * @param {Roo.Component} c The component
21759 register : function(c){
21764 * Unregisters a component.
21765 * @param {Roo.Component} c The component
21767 unregister : function(c){
21772 * Returns a component by id
21773 * @param {String} id The component id
21775 get : function(id){
21776 return all.get(id);
21780 * Registers a function that will be called when a specified component is added to ComponentMgr
21781 * @param {String} id The component id
21782 * @param {Funtction} fn The callback function
21783 * @param {Object} scope The scope of the callback
21785 onAvailable : function(id, fn, scope){
21786 all.on("add", function(index, o){
21788 fn.call(scope || o, o);
21789 all.un("add", fn, scope);
21796 * Ext JS Library 1.1.1
21797 * Copyright(c) 2006-2007, Ext JS, LLC.
21799 * Originally Released Under LGPL - original licence link has changed is not relivant.
21802 * <script type="text/javascript">
21806 * @class Roo.Component
21807 * @extends Roo.util.Observable
21808 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
21809 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
21810 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
21811 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
21812 * All visual components (widgets) that require rendering into a layout should subclass Component.
21814 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
21815 * 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
21816 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
21818 Roo.Component = function(config){
21819 config = config || {};
21820 if(config.tagName || config.dom || typeof config == "string"){ // element object
21821 config = {el: config, id: config.id || config};
21823 this.initialConfig = config;
21825 Roo.apply(this, config);
21829 * Fires after the component is disabled.
21830 * @param {Roo.Component} this
21835 * Fires after the component is enabled.
21836 * @param {Roo.Component} this
21840 * @event beforeshow
21841 * Fires before the component is shown. Return false to stop the show.
21842 * @param {Roo.Component} this
21847 * Fires after the component is shown.
21848 * @param {Roo.Component} this
21852 * @event beforehide
21853 * Fires before the component is hidden. Return false to stop the hide.
21854 * @param {Roo.Component} this
21859 * Fires after the component is hidden.
21860 * @param {Roo.Component} this
21864 * @event beforerender
21865 * Fires before the component is rendered. Return false to stop the render.
21866 * @param {Roo.Component} this
21868 beforerender : true,
21871 * Fires after the component is rendered.
21872 * @param {Roo.Component} this
21876 * @event beforedestroy
21877 * Fires before the component is destroyed. Return false to stop the destroy.
21878 * @param {Roo.Component} this
21880 beforedestroy : true,
21883 * Fires after the component is destroyed.
21884 * @param {Roo.Component} this
21889 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
21891 Roo.ComponentMgr.register(this);
21892 Roo.Component.superclass.constructor.call(this);
21893 this.initComponent();
21894 if(this.renderTo){ // not supported by all components yet. use at your own risk!
21895 this.render(this.renderTo);
21896 delete this.renderTo;
21901 Roo.Component.AUTO_ID = 1000;
21903 Roo.extend(Roo.Component, Roo.util.Observable, {
21905 * @scope Roo.Component.prototype
21907 * true if this component is hidden. Read-only.
21912 * true if this component is disabled. Read-only.
21917 * true if this component has been rendered. Read-only.
21921 /** @cfg {String} disableClass
21922 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
21924 disabledClass : "x-item-disabled",
21925 /** @cfg {Boolean} allowDomMove
21926 * Whether the component can move the Dom node when rendering (defaults to true).
21928 allowDomMove : true,
21929 /** @cfg {String} hideMode
21930 * How this component should hidden. Supported values are
21931 * "visibility" (css visibility), "offsets" (negative offset position) and
21932 * "display" (css display) - defaults to "display".
21934 hideMode: 'display',
21937 ctype : "Roo.Component",
21940 * @cfg {String} actionMode
21941 * which property holds the element that used for hide() / show() / disable() / enable()
21947 getActionEl : function(){
21948 return this[this.actionMode];
21951 initComponent : Roo.emptyFn,
21953 * If this is a lazy rendering component, render it to its container element.
21954 * @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.
21956 render : function(container, position){
21957 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
21958 if(!container && this.el){
21959 this.el = Roo.get(this.el);
21960 container = this.el.dom.parentNode;
21961 this.allowDomMove = false;
21963 this.container = Roo.get(container);
21964 this.rendered = true;
21965 if(position !== undefined){
21966 if(typeof position == 'number'){
21967 position = this.container.dom.childNodes[position];
21969 position = Roo.getDom(position);
21972 this.onRender(this.container, position || null);
21974 this.el.addClass(this.cls);
21978 this.el.applyStyles(this.style);
21981 this.fireEvent("render", this);
21982 this.afterRender(this.container);
21994 // default function is not really useful
21995 onRender : function(ct, position){
21997 this.el = Roo.get(this.el);
21998 if(this.allowDomMove !== false){
21999 ct.dom.insertBefore(this.el.dom, position);
22005 getAutoCreate : function(){
22006 var cfg = typeof this.autoCreate == "object" ?
22007 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22008 if(this.id && !cfg.id){
22015 afterRender : Roo.emptyFn,
22018 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22019 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22021 destroy : function(){
22022 if(this.fireEvent("beforedestroy", this) !== false){
22023 this.purgeListeners();
22024 this.beforeDestroy();
22026 this.el.removeAllListeners();
22028 if(this.actionMode == "container"){
22029 this.container.remove();
22033 Roo.ComponentMgr.unregister(this);
22034 this.fireEvent("destroy", this);
22039 beforeDestroy : function(){
22044 onDestroy : function(){
22049 * Returns the underlying {@link Roo.Element}.
22050 * @return {Roo.Element} The element
22052 getEl : function(){
22057 * Returns the id of this component.
22060 getId : function(){
22065 * Try to focus this component.
22066 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22067 * @return {Roo.Component} this
22069 focus : function(selectText){
22072 if(selectText === true){
22073 this.el.dom.select();
22088 * Disable this component.
22089 * @return {Roo.Component} this
22091 disable : function(){
22095 this.disabled = true;
22096 this.fireEvent("disable", this);
22101 onDisable : function(){
22102 this.getActionEl().addClass(this.disabledClass);
22103 this.el.dom.disabled = true;
22107 * Enable this component.
22108 * @return {Roo.Component} this
22110 enable : function(){
22114 this.disabled = false;
22115 this.fireEvent("enable", this);
22120 onEnable : function(){
22121 this.getActionEl().removeClass(this.disabledClass);
22122 this.el.dom.disabled = false;
22126 * Convenience function for setting disabled/enabled by boolean.
22127 * @param {Boolean} disabled
22129 setDisabled : function(disabled){
22130 this[disabled ? "disable" : "enable"]();
22134 * Show this component.
22135 * @return {Roo.Component} this
22138 if(this.fireEvent("beforeshow", this) !== false){
22139 this.hidden = false;
22143 this.fireEvent("show", this);
22149 onShow : function(){
22150 var ae = this.getActionEl();
22151 if(this.hideMode == 'visibility'){
22152 ae.dom.style.visibility = "visible";
22153 }else if(this.hideMode == 'offsets'){
22154 ae.removeClass('x-hidden');
22156 ae.dom.style.display = "";
22161 * Hide this component.
22162 * @return {Roo.Component} this
22165 if(this.fireEvent("beforehide", this) !== false){
22166 this.hidden = true;
22170 this.fireEvent("hide", this);
22176 onHide : function(){
22177 var ae = this.getActionEl();
22178 if(this.hideMode == 'visibility'){
22179 ae.dom.style.visibility = "hidden";
22180 }else if(this.hideMode == 'offsets'){
22181 ae.addClass('x-hidden');
22183 ae.dom.style.display = "none";
22188 * Convenience function to hide or show this component by boolean.
22189 * @param {Boolean} visible True to show, false to hide
22190 * @return {Roo.Component} this
22192 setVisible: function(visible){
22202 * Returns true if this component is visible.
22204 isVisible : function(){
22205 return this.getActionEl().isVisible();
22208 cloneConfig : function(overrides){
22209 overrides = overrides || {};
22210 var id = overrides.id || Roo.id();
22211 var cfg = Roo.applyIf(overrides, this.initialConfig);
22212 cfg.id = id; // prevent dup id
22213 return new this.constructor(cfg);
22217 * Ext JS Library 1.1.1
22218 * Copyright(c) 2006-2007, Ext JS, LLC.
22220 * Originally Released Under LGPL - original licence link has changed is not relivant.
22223 * <script type="text/javascript">
22228 * @extends Roo.Element
22229 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22230 * automatic maintaining of shadow/shim positions.
22231 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22232 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22233 * you can pass a string with a CSS class name. False turns off the shadow.
22234 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22235 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22236 * @cfg {String} cls CSS class to add to the element
22237 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22238 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22240 * @param {Object} config An object with config options.
22241 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22244 Roo.Layer = function(config, existingEl){
22245 config = config || {};
22246 var dh = Roo.DomHelper;
22247 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22249 this.dom = Roo.getDom(existingEl);
22252 var o = config.dh || {tag: "div", cls: "x-layer"};
22253 this.dom = dh.append(pel, o);
22256 this.addClass(config.cls);
22258 this.constrain = config.constrain !== false;
22259 this.visibilityMode = Roo.Element.VISIBILITY;
22261 this.id = this.dom.id = config.id;
22263 this.id = Roo.id(this.dom);
22265 this.zindex = config.zindex || this.getZIndex();
22266 this.position("absolute", this.zindex);
22268 this.shadowOffset = config.shadowOffset || 4;
22269 this.shadow = new Roo.Shadow({
22270 offset : this.shadowOffset,
22271 mode : config.shadow
22274 this.shadowOffset = 0;
22276 this.useShim = config.shim !== false && Roo.useShims;
22277 this.useDisplay = config.useDisplay;
22281 var supr = Roo.Element.prototype;
22283 // shims are shared among layer to keep from having 100 iframes
22286 Roo.extend(Roo.Layer, Roo.Element, {
22288 getZIndex : function(){
22289 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22292 getShim : function(){
22299 var shim = shims.shift();
22301 shim = this.createShim();
22302 shim.enableDisplayMode('block');
22303 shim.dom.style.display = 'none';
22304 shim.dom.style.visibility = 'visible';
22306 var pn = this.dom.parentNode;
22307 if(shim.dom.parentNode != pn){
22308 pn.insertBefore(shim.dom, this.dom);
22310 shim.setStyle('z-index', this.getZIndex()-2);
22315 hideShim : function(){
22317 this.shim.setDisplayed(false);
22318 shims.push(this.shim);
22323 disableShadow : function(){
22325 this.shadowDisabled = true;
22326 this.shadow.hide();
22327 this.lastShadowOffset = this.shadowOffset;
22328 this.shadowOffset = 0;
22332 enableShadow : function(show){
22334 this.shadowDisabled = false;
22335 this.shadowOffset = this.lastShadowOffset;
22336 delete this.lastShadowOffset;
22344 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22345 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22346 sync : function(doShow){
22347 var sw = this.shadow;
22348 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22349 var sh = this.getShim();
22351 var w = this.getWidth(),
22352 h = this.getHeight();
22354 var l = this.getLeft(true),
22355 t = this.getTop(true);
22357 if(sw && !this.shadowDisabled){
22358 if(doShow && !sw.isVisible()){
22361 sw.realign(l, t, w, h);
22367 // fit the shim behind the shadow, so it is shimmed too
22368 var a = sw.adjusts, s = sh.dom.style;
22369 s.left = (Math.min(l, l+a.l))+"px";
22370 s.top = (Math.min(t, t+a.t))+"px";
22371 s.width = (w+a.w)+"px";
22372 s.height = (h+a.h)+"px";
22379 sh.setLeftTop(l, t);
22386 destroy : function(){
22389 this.shadow.hide();
22391 this.removeAllListeners();
22392 var pn = this.dom.parentNode;
22394 pn.removeChild(this.dom);
22396 Roo.Element.uncache(this.id);
22399 remove : function(){
22404 beginUpdate : function(){
22405 this.updating = true;
22409 endUpdate : function(){
22410 this.updating = false;
22415 hideUnders : function(negOffset){
22417 this.shadow.hide();
22423 constrainXY : function(){
22424 if(this.constrain){
22425 var vw = Roo.lib.Dom.getViewWidth(),
22426 vh = Roo.lib.Dom.getViewHeight();
22427 var s = Roo.get(document).getScroll();
22429 var xy = this.getXY();
22430 var x = xy[0], y = xy[1];
22431 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
22432 // only move it if it needs it
22434 // first validate right/bottom
22435 if((x + w) > vw+s.left){
22436 x = vw - w - this.shadowOffset;
22439 if((y + h) > vh+s.top){
22440 y = vh - h - this.shadowOffset;
22443 // then make sure top/left isn't negative
22454 var ay = this.avoidY;
22455 if(y <= ay && (y+h) >= ay){
22461 supr.setXY.call(this, xy);
22467 isVisible : function(){
22468 return this.visible;
22472 showAction : function(){
22473 this.visible = true; // track visibility to prevent getStyle calls
22474 if(this.useDisplay === true){
22475 this.setDisplayed("");
22476 }else if(this.lastXY){
22477 supr.setXY.call(this, this.lastXY);
22478 }else if(this.lastLT){
22479 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
22484 hideAction : function(){
22485 this.visible = false;
22486 if(this.useDisplay === true){
22487 this.setDisplayed(false);
22489 this.setLeftTop(-10000,-10000);
22493 // overridden Element method
22494 setVisible : function(v, a, d, c, e){
22499 var cb = function(){
22504 }.createDelegate(this);
22505 supr.setVisible.call(this, true, true, d, cb, e);
22508 this.hideUnders(true);
22517 }.createDelegate(this);
22519 supr.setVisible.call(this, v, a, d, cb, e);
22528 storeXY : function(xy){
22529 delete this.lastLT;
22533 storeLeftTop : function(left, top){
22534 delete this.lastXY;
22535 this.lastLT = [left, top];
22539 beforeFx : function(){
22540 this.beforeAction();
22541 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
22545 afterFx : function(){
22546 Roo.Layer.superclass.afterFx.apply(this, arguments);
22547 this.sync(this.isVisible());
22551 beforeAction : function(){
22552 if(!this.updating && this.shadow){
22553 this.shadow.hide();
22557 // overridden Element method
22558 setLeft : function(left){
22559 this.storeLeftTop(left, this.getTop(true));
22560 supr.setLeft.apply(this, arguments);
22564 setTop : function(top){
22565 this.storeLeftTop(this.getLeft(true), top);
22566 supr.setTop.apply(this, arguments);
22570 setLeftTop : function(left, top){
22571 this.storeLeftTop(left, top);
22572 supr.setLeftTop.apply(this, arguments);
22576 setXY : function(xy, a, d, c, e){
22578 this.beforeAction();
22580 var cb = this.createCB(c);
22581 supr.setXY.call(this, xy, a, d, cb, e);
22588 createCB : function(c){
22599 // overridden Element method
22600 setX : function(x, a, d, c, e){
22601 this.setXY([x, this.getY()], a, d, c, e);
22604 // overridden Element method
22605 setY : function(y, a, d, c, e){
22606 this.setXY([this.getX(), y], a, d, c, e);
22609 // overridden Element method
22610 setSize : function(w, h, a, d, c, e){
22611 this.beforeAction();
22612 var cb = this.createCB(c);
22613 supr.setSize.call(this, w, h, a, d, cb, e);
22619 // overridden Element method
22620 setWidth : function(w, a, d, c, e){
22621 this.beforeAction();
22622 var cb = this.createCB(c);
22623 supr.setWidth.call(this, w, a, d, cb, e);
22629 // overridden Element method
22630 setHeight : function(h, a, d, c, e){
22631 this.beforeAction();
22632 var cb = this.createCB(c);
22633 supr.setHeight.call(this, h, a, d, cb, e);
22639 // overridden Element method
22640 setBounds : function(x, y, w, h, a, d, c, e){
22641 this.beforeAction();
22642 var cb = this.createCB(c);
22644 this.storeXY([x, y]);
22645 supr.setXY.call(this, [x, y]);
22646 supr.setSize.call(this, w, h, a, d, cb, e);
22649 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
22655 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
22656 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
22657 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
22658 * @param {Number} zindex The new z-index to set
22659 * @return {this} The Layer
22661 setZIndex : function(zindex){
22662 this.zindex = zindex;
22663 this.setStyle("z-index", zindex + 2);
22665 this.shadow.setZIndex(zindex + 1);
22668 this.shim.setStyle("z-index", zindex);
22674 * Ext JS Library 1.1.1
22675 * Copyright(c) 2006-2007, Ext JS, LLC.
22677 * Originally Released Under LGPL - original licence link has changed is not relivant.
22680 * <script type="text/javascript">
22685 * @class Roo.Shadow
22686 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
22687 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
22688 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
22690 * Create a new Shadow
22691 * @param {Object} config The config object
22693 Roo.Shadow = function(config){
22694 Roo.apply(this, config);
22695 if(typeof this.mode != "string"){
22696 this.mode = this.defaultMode;
22698 var o = this.offset, a = {h: 0};
22699 var rad = Math.floor(this.offset/2);
22700 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
22706 a.l -= this.offset + rad;
22707 a.t -= this.offset + rad;
22718 a.l -= (this.offset - rad);
22719 a.t -= this.offset + rad;
22721 a.w -= (this.offset - rad)*2;
22732 a.l -= (this.offset - rad);
22733 a.t -= (this.offset - rad);
22735 a.w -= (this.offset + rad + 1);
22736 a.h -= (this.offset + rad);
22745 Roo.Shadow.prototype = {
22747 * @cfg {String} mode
22748 * The shadow display mode. Supports the following options:<br />
22749 * sides: Shadow displays on both sides and bottom only<br />
22750 * frame: Shadow displays equally on all four sides<br />
22751 * drop: Traditional bottom-right drop shadow (default)
22754 * @cfg {String} offset
22755 * The number of pixels to offset the shadow from the element (defaults to 4)
22760 defaultMode: "drop",
22763 * Displays the shadow under the target element
22764 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
22766 show : function(target){
22767 target = Roo.get(target);
22769 this.el = Roo.Shadow.Pool.pull();
22770 if(this.el.dom.nextSibling != target.dom){
22771 this.el.insertBefore(target);
22774 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
22776 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
22779 target.getLeft(true),
22780 target.getTop(true),
22784 this.el.dom.style.display = "block";
22788 * Returns true if the shadow is visible, else false
22790 isVisible : function(){
22791 return this.el ? true : false;
22795 * Direct alignment when values are already available. Show must be called at least once before
22796 * calling this method to ensure it is initialized.
22797 * @param {Number} left The target element left position
22798 * @param {Number} top The target element top position
22799 * @param {Number} width The target element width
22800 * @param {Number} height The target element height
22802 realign : function(l, t, w, h){
22806 var a = this.adjusts, d = this.el.dom, s = d.style;
22808 s.left = (l+a.l)+"px";
22809 s.top = (t+a.t)+"px";
22810 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
22812 if(s.width != sws || s.height != shs){
22816 var cn = d.childNodes;
22817 var sww = Math.max(0, (sw-12))+"px";
22818 cn[0].childNodes[1].style.width = sww;
22819 cn[1].childNodes[1].style.width = sww;
22820 cn[2].childNodes[1].style.width = sww;
22821 cn[1].style.height = Math.max(0, (sh-12))+"px";
22827 * Hides this shadow
22831 this.el.dom.style.display = "none";
22832 Roo.Shadow.Pool.push(this.el);
22838 * Adjust the z-index of this shadow
22839 * @param {Number} zindex The new z-index
22841 setZIndex : function(z){
22844 this.el.setStyle("z-index", z);
22849 // Private utility class that manages the internal Shadow cache
22850 Roo.Shadow.Pool = function(){
22852 var markup = Roo.isIE ?
22853 '<div class="x-ie-shadow"></div>' :
22854 '<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>';
22857 var sh = p.shift();
22859 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
22860 sh.autoBoxAdjust = false;
22865 push : function(sh){
22871 * Ext JS Library 1.1.1
22872 * Copyright(c) 2006-2007, Ext JS, LLC.
22874 * Originally Released Under LGPL - original licence link has changed is not relivant.
22877 * <script type="text/javascript">
22881 * @class Roo.BoxComponent
22882 * @extends Roo.Component
22883 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
22884 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
22885 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
22886 * layout containers.
22888 * @param {Roo.Element/String/Object} config The configuration options.
22890 Roo.BoxComponent = function(config){
22891 Roo.Component.call(this, config);
22895 * Fires after the component is resized.
22896 * @param {Roo.Component} this
22897 * @param {Number} adjWidth The box-adjusted width that was set
22898 * @param {Number} adjHeight The box-adjusted height that was set
22899 * @param {Number} rawWidth The width that was originally specified
22900 * @param {Number} rawHeight The height that was originally specified
22905 * Fires after the component is moved.
22906 * @param {Roo.Component} this
22907 * @param {Number} x The new x position
22908 * @param {Number} y The new y position
22914 Roo.extend(Roo.BoxComponent, Roo.Component, {
22915 // private, set in afterRender to signify that the component has been rendered
22917 // private, used to defer height settings to subclasses
22918 deferHeight: false,
22919 /** @cfg {Number} width
22920 * width (optional) size of component
22922 /** @cfg {Number} height
22923 * height (optional) size of component
22927 * Sets the width and height of the component. This method fires the resize event. This method can accept
22928 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
22929 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
22930 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
22931 * @return {Roo.BoxComponent} this
22933 setSize : function(w, h){
22934 // support for standard size objects
22935 if(typeof w == 'object'){
22940 if(!this.boxReady){
22946 // prevent recalcs when not needed
22947 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
22950 this.lastSize = {width: w, height: h};
22952 var adj = this.adjustSize(w, h);
22953 var aw = adj.width, ah = adj.height;
22954 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
22955 var rz = this.getResizeEl();
22956 if(!this.deferHeight && aw !== undefined && ah !== undefined){
22957 rz.setSize(aw, ah);
22958 }else if(!this.deferHeight && ah !== undefined){
22960 }else if(aw !== undefined){
22963 this.onResize(aw, ah, w, h);
22964 this.fireEvent('resize', this, aw, ah, w, h);
22970 * Gets the current size of the component's underlying element.
22971 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
22973 getSize : function(){
22974 return this.el.getSize();
22978 * Gets the current XY position of the component's underlying element.
22979 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22980 * @return {Array} The XY position of the element (e.g., [100, 200])
22982 getPosition : function(local){
22983 if(local === true){
22984 return [this.el.getLeft(true), this.el.getTop(true)];
22986 return this.xy || this.el.getXY();
22990 * Gets the current box measurements of the component's underlying element.
22991 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
22992 * @returns {Object} box An object in the format {x, y, width, height}
22994 getBox : function(local){
22995 var s = this.el.getSize();
22997 s.x = this.el.getLeft(true);
22998 s.y = this.el.getTop(true);
23000 var xy = this.xy || this.el.getXY();
23008 * Sets the current box measurements of the component's underlying element.
23009 * @param {Object} box An object in the format {x, y, width, height}
23010 * @returns {Roo.BoxComponent} this
23012 updateBox : function(box){
23013 this.setSize(box.width, box.height);
23014 this.setPagePosition(box.x, box.y);
23019 getResizeEl : function(){
23020 return this.resizeEl || this.el;
23024 getPositionEl : function(){
23025 return this.positionEl || this.el;
23029 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23030 * This method fires the move event.
23031 * @param {Number} left The new left
23032 * @param {Number} top The new top
23033 * @returns {Roo.BoxComponent} this
23035 setPosition : function(x, y){
23038 if(!this.boxReady){
23041 var adj = this.adjustPosition(x, y);
23042 var ax = adj.x, ay = adj.y;
23044 var el = this.getPositionEl();
23045 if(ax !== undefined || ay !== undefined){
23046 if(ax !== undefined && ay !== undefined){
23047 el.setLeftTop(ax, ay);
23048 }else if(ax !== undefined){
23050 }else if(ay !== undefined){
23053 this.onPosition(ax, ay);
23054 this.fireEvent('move', this, ax, ay);
23060 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23061 * This method fires the move event.
23062 * @param {Number} x The new x position
23063 * @param {Number} y The new y position
23064 * @returns {Roo.BoxComponent} this
23066 setPagePosition : function(x, y){
23069 if(!this.boxReady){
23072 if(x === undefined || y === undefined){ // cannot translate undefined points
23075 var p = this.el.translatePoints(x, y);
23076 this.setPosition(p.left, p.top);
23081 onRender : function(ct, position){
23082 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23084 this.resizeEl = Roo.get(this.resizeEl);
23086 if(this.positionEl){
23087 this.positionEl = Roo.get(this.positionEl);
23092 afterRender : function(){
23093 Roo.BoxComponent.superclass.afterRender.call(this);
23094 this.boxReady = true;
23095 this.setSize(this.width, this.height);
23096 if(this.x || this.y){
23097 this.setPosition(this.x, this.y);
23099 if(this.pageX || this.pageY){
23100 this.setPagePosition(this.pageX, this.pageY);
23105 * Force the component's size to recalculate based on the underlying element's current height and width.
23106 * @returns {Roo.BoxComponent} this
23108 syncSize : function(){
23109 delete this.lastSize;
23110 this.setSize(this.el.getWidth(), this.el.getHeight());
23115 * Called after the component is resized, this method is empty by default but can be implemented by any
23116 * subclass that needs to perform custom logic after a resize occurs.
23117 * @param {Number} adjWidth The box-adjusted width that was set
23118 * @param {Number} adjHeight The box-adjusted height that was set
23119 * @param {Number} rawWidth The width that was originally specified
23120 * @param {Number} rawHeight The height that was originally specified
23122 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23127 * Called after the component is moved, this method is empty by default but can be implemented by any
23128 * subclass that needs to perform custom logic after a move occurs.
23129 * @param {Number} x The new x position
23130 * @param {Number} y The new y position
23132 onPosition : function(x, y){
23137 adjustSize : function(w, h){
23138 if(this.autoWidth){
23141 if(this.autoHeight){
23144 return {width : w, height: h};
23148 adjustPosition : function(x, y){
23149 return {x : x, y: y};
23153 * Ext JS Library 1.1.1
23154 * Copyright(c) 2006-2007, Ext JS, LLC.
23156 * Originally Released Under LGPL - original licence link has changed is not relivant.
23159 * <script type="text/javascript">
23164 * @class Roo.SplitBar
23165 * @extends Roo.util.Observable
23166 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23170 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23171 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23172 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23173 split.minSize = 100;
23174 split.maxSize = 600;
23175 split.animate = true;
23176 split.on('moved', splitterMoved);
23179 * Create a new SplitBar
23180 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23181 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23182 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23183 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23184 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23185 position of the SplitBar).
23187 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23190 this.el = Roo.get(dragElement, true);
23191 this.el.dom.unselectable = "on";
23193 this.resizingEl = Roo.get(resizingElement, true);
23197 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23198 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23201 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23204 * The minimum size of the resizing element. (Defaults to 0)
23210 * The maximum size of the resizing element. (Defaults to 2000)
23213 this.maxSize = 2000;
23216 * Whether to animate the transition to the new size
23219 this.animate = false;
23222 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23225 this.useShim = false;
23230 if(!existingProxy){
23232 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23234 this.proxy = Roo.get(existingProxy).dom;
23237 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23240 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23243 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23246 this.dragSpecs = {};
23249 * @private The adapter to use to positon and resize elements
23251 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23252 this.adapter.init(this);
23254 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23256 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23257 this.el.addClass("x-splitbar-h");
23260 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23261 this.el.addClass("x-splitbar-v");
23267 * Fires when the splitter is moved (alias for {@link #event-moved})
23268 * @param {Roo.SplitBar} this
23269 * @param {Number} newSize the new width or height
23274 * Fires when the splitter is moved
23275 * @param {Roo.SplitBar} this
23276 * @param {Number} newSize the new width or height
23280 * @event beforeresize
23281 * Fires before the splitter is dragged
23282 * @param {Roo.SplitBar} this
23284 "beforeresize" : true,
23286 "beforeapply" : true
23289 Roo.util.Observable.call(this);
23292 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23293 onStartProxyDrag : function(x, y){
23294 this.fireEvent("beforeresize", this);
23296 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23298 o.enableDisplayMode("block");
23299 // all splitbars share the same overlay
23300 Roo.SplitBar.prototype.overlay = o;
23302 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23303 this.overlay.show();
23304 Roo.get(this.proxy).setDisplayed("block");
23305 var size = this.adapter.getElementSize(this);
23306 this.activeMinSize = this.getMinimumSize();;
23307 this.activeMaxSize = this.getMaximumSize();;
23308 var c1 = size - this.activeMinSize;
23309 var c2 = Math.max(this.activeMaxSize - size, 0);
23310 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23311 this.dd.resetConstraints();
23312 this.dd.setXConstraint(
23313 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23314 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23316 this.dd.setYConstraint(0, 0);
23318 this.dd.resetConstraints();
23319 this.dd.setXConstraint(0, 0);
23320 this.dd.setYConstraint(
23321 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23322 this.placement == Roo.SplitBar.TOP ? c2 : c1
23325 this.dragSpecs.startSize = size;
23326 this.dragSpecs.startPoint = [x, y];
23327 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23331 * @private Called after the drag operation by the DDProxy
23333 onEndProxyDrag : function(e){
23334 Roo.get(this.proxy).setDisplayed(false);
23335 var endPoint = Roo.lib.Event.getXY(e);
23337 this.overlay.hide();
23340 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23341 newSize = this.dragSpecs.startSize +
23342 (this.placement == Roo.SplitBar.LEFT ?
23343 endPoint[0] - this.dragSpecs.startPoint[0] :
23344 this.dragSpecs.startPoint[0] - endPoint[0]
23347 newSize = this.dragSpecs.startSize +
23348 (this.placement == Roo.SplitBar.TOP ?
23349 endPoint[1] - this.dragSpecs.startPoint[1] :
23350 this.dragSpecs.startPoint[1] - endPoint[1]
23353 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23354 if(newSize != this.dragSpecs.startSize){
23355 if(this.fireEvent('beforeapply', this, newSize) !== false){
23356 this.adapter.setElementSize(this, newSize);
23357 this.fireEvent("moved", this, newSize);
23358 this.fireEvent("resize", this, newSize);
23364 * Get the adapter this SplitBar uses
23365 * @return The adapter object
23367 getAdapter : function(){
23368 return this.adapter;
23372 * Set the adapter this SplitBar uses
23373 * @param {Object} adapter A SplitBar adapter object
23375 setAdapter : function(adapter){
23376 this.adapter = adapter;
23377 this.adapter.init(this);
23381 * Gets the minimum size for the resizing element
23382 * @return {Number} The minimum size
23384 getMinimumSize : function(){
23385 return this.minSize;
23389 * Sets the minimum size for the resizing element
23390 * @param {Number} minSize The minimum size
23392 setMinimumSize : function(minSize){
23393 this.minSize = minSize;
23397 * Gets the maximum size for the resizing element
23398 * @return {Number} The maximum size
23400 getMaximumSize : function(){
23401 return this.maxSize;
23405 * Sets the maximum size for the resizing element
23406 * @param {Number} maxSize The maximum size
23408 setMaximumSize : function(maxSize){
23409 this.maxSize = maxSize;
23413 * Sets the initialize size for the resizing element
23414 * @param {Number} size The initial size
23416 setCurrentSize : function(size){
23417 var oldAnimate = this.animate;
23418 this.animate = false;
23419 this.adapter.setElementSize(this, size);
23420 this.animate = oldAnimate;
23424 * Destroy this splitbar.
23425 * @param {Boolean} removeEl True to remove the element
23427 destroy : function(removeEl){
23429 this.shim.remove();
23432 this.proxy.parentNode.removeChild(this.proxy);
23440 * @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.
23442 Roo.SplitBar.createProxy = function(dir){
23443 var proxy = new Roo.Element(document.createElement("div"));
23444 proxy.unselectable();
23445 var cls = 'x-splitbar-proxy';
23446 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
23447 document.body.appendChild(proxy.dom);
23452 * @class Roo.SplitBar.BasicLayoutAdapter
23453 * Default Adapter. It assumes the splitter and resizing element are not positioned
23454 * elements and only gets/sets the width of the element. Generally used for table based layouts.
23456 Roo.SplitBar.BasicLayoutAdapter = function(){
23459 Roo.SplitBar.BasicLayoutAdapter.prototype = {
23460 // do nothing for now
23461 init : function(s){
23465 * Called before drag operations to get the current size of the resizing element.
23466 * @param {Roo.SplitBar} s The SplitBar using this adapter
23468 getElementSize : function(s){
23469 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23470 return s.resizingEl.getWidth();
23472 return s.resizingEl.getHeight();
23477 * Called after drag operations to set the size of the resizing element.
23478 * @param {Roo.SplitBar} s The SplitBar using this adapter
23479 * @param {Number} newSize The new size to set
23480 * @param {Function} onComplete A function to be invoked when resizing is complete
23482 setElementSize : function(s, newSize, onComplete){
23483 if(s.orientation == Roo.SplitBar.HORIZONTAL){
23485 s.resizingEl.setWidth(newSize);
23487 onComplete(s, newSize);
23490 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
23495 s.resizingEl.setHeight(newSize);
23497 onComplete(s, newSize);
23500 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
23507 *@class Roo.SplitBar.AbsoluteLayoutAdapter
23508 * @extends Roo.SplitBar.BasicLayoutAdapter
23509 * Adapter that moves the splitter element to align with the resized sizing element.
23510 * Used with an absolute positioned SplitBar.
23511 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
23512 * document.body, make sure you assign an id to the body element.
23514 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
23515 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
23516 this.container = Roo.get(container);
23519 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
23520 init : function(s){
23521 this.basic.init(s);
23524 getElementSize : function(s){
23525 return this.basic.getElementSize(s);
23528 setElementSize : function(s, newSize, onComplete){
23529 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
23532 moveSplitter : function(s){
23533 var yes = Roo.SplitBar;
23534 switch(s.placement){
23536 s.el.setX(s.resizingEl.getRight());
23539 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
23542 s.el.setY(s.resizingEl.getBottom());
23545 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
23552 * Orientation constant - Create a vertical SplitBar
23556 Roo.SplitBar.VERTICAL = 1;
23559 * Orientation constant - Create a horizontal SplitBar
23563 Roo.SplitBar.HORIZONTAL = 2;
23566 * Placement constant - The resizing element is to the left of the splitter element
23570 Roo.SplitBar.LEFT = 1;
23573 * Placement constant - The resizing element is to the right of the splitter element
23577 Roo.SplitBar.RIGHT = 2;
23580 * Placement constant - The resizing element is positioned above the splitter element
23584 Roo.SplitBar.TOP = 3;
23587 * Placement constant - The resizing element is positioned under splitter element
23591 Roo.SplitBar.BOTTOM = 4;
23594 * Ext JS Library 1.1.1
23595 * Copyright(c) 2006-2007, Ext JS, LLC.
23597 * Originally Released Under LGPL - original licence link has changed is not relivant.
23600 * <script type="text/javascript">
23605 * @extends Roo.util.Observable
23606 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
23607 * This class also supports single and multi selection modes. <br>
23608 * Create a data model bound view:
23610 var store = new Roo.data.Store(...);
23612 var view = new Roo.View({
23614 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
23616 singleSelect: true,
23617 selectedClass: "ydataview-selected",
23621 // listen for node click?
23622 view.on("click", function(vw, index, node, e){
23623 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
23627 dataModel.load("foobar.xml");
23629 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
23631 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
23632 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
23634 * Note: old style constructor is still suported (container, template, config)
23637 * Create a new View
23638 * @param {Object} config The config object
23641 Roo.View = function(config, depreciated_tpl, depreciated_config){
23643 if (typeof(depreciated_tpl) == 'undefined') {
23644 // new way.. - universal constructor.
23645 Roo.apply(this, config);
23646 this.el = Roo.get(this.el);
23649 this.el = Roo.get(config);
23650 this.tpl = depreciated_tpl;
23651 Roo.apply(this, depreciated_config);
23655 if(typeof(this.tpl) == "string"){
23656 this.tpl = new Roo.Template(this.tpl);
23658 // support xtype ctors..
23659 this.tpl = new Roo.factory(this.tpl, Roo);
23663 this.tpl.compile();
23670 * @event beforeclick
23671 * Fires before a click is processed. Returns false to cancel the default action.
23672 * @param {Roo.View} this
23673 * @param {Number} index The index of the target node
23674 * @param {HTMLElement} node The target node
23675 * @param {Roo.EventObject} e The raw event object
23677 "beforeclick" : true,
23680 * Fires when a template node is clicked.
23681 * @param {Roo.View} this
23682 * @param {Number} index The index of the target node
23683 * @param {HTMLElement} node The target node
23684 * @param {Roo.EventObject} e The raw event object
23689 * Fires when a template node is double clicked.
23690 * @param {Roo.View} this
23691 * @param {Number} index The index of the target node
23692 * @param {HTMLElement} node The target node
23693 * @param {Roo.EventObject} e The raw event object
23697 * @event contextmenu
23698 * Fires when a template node is right clicked.
23699 * @param {Roo.View} this
23700 * @param {Number} index The index of the target node
23701 * @param {HTMLElement} node The target node
23702 * @param {Roo.EventObject} e The raw event object
23704 "contextmenu" : true,
23706 * @event selectionchange
23707 * Fires when the selected nodes change.
23708 * @param {Roo.View} this
23709 * @param {Array} selections Array of the selected nodes
23711 "selectionchange" : true,
23714 * @event beforeselect
23715 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
23716 * @param {Roo.View} this
23717 * @param {HTMLElement} node The node to be selected
23718 * @param {Array} selections Array of currently selected nodes
23720 "beforeselect" : true,
23722 * @event preparedata
23723 * Fires on every row to render, to allow you to change the data.
23724 * @param {Roo.View} this
23725 * @param {Object} data to be rendered (change this)
23727 "preparedata" : true
23731 "click": this.onClick,
23732 "dblclick": this.onDblClick,
23733 "contextmenu": this.onContextMenu,
23737 this.selections = [];
23739 this.cmp = new Roo.CompositeElementLite([]);
23741 this.store = Roo.factory(this.store, Roo.data);
23742 this.setStore(this.store, true);
23744 Roo.View.superclass.constructor.call(this);
23747 Roo.extend(Roo.View, Roo.util.Observable, {
23750 * @cfg {Roo.data.Store} store Data store to load data from.
23755 * @cfg {String|Roo.Element} el The container element.
23760 * @cfg {String|Roo.Template} tpl The template used by this View
23765 * @cfg {String} selectedClass The css class to add to selected nodes
23767 selectedClass : "x-view-selected",
23769 * @cfg {String} emptyText The empty text to show when nothing is loaded.
23773 * @cfg {Boolean} multiSelect Allow multiple selection
23775 multiSelect : false,
23777 * @cfg {Boolean} singleSelect Allow single selection
23779 singleSelect: false,
23782 * @cfg {Boolean} toggleSelect - selecting
23784 toggleSelect : false,
23787 * Returns the element this view is bound to.
23788 * @return {Roo.Element}
23790 getEl : function(){
23795 * Refreshes the view.
23797 refresh : function(){
23799 this.clearSelections();
23800 this.el.update("");
23802 var records = this.store.getRange();
23803 if(records.length < 1){
23804 this.el.update(this.emptyText);
23807 for(var i = 0, len = records.length; i < len; i++){
23808 var data = this.prepareData(records[i].data, i, records[i]);
23809 this.fireEvent("preparedata", this, data, i, records[i]);
23810 html[html.length] = t.apply(data);
23812 this.el.update(html.join(""));
23813 this.nodes = this.el.dom.childNodes;
23814 this.updateIndexes(0);
23818 * Function to override to reformat the data that is sent to
23819 * the template for each node.
23820 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
23821 * a JSON object for an UpdateManager bound view).
23823 prepareData : function(data){
23827 onUpdate : function(ds, record){
23828 this.clearSelections();
23829 var index = this.store.indexOf(record);
23830 var n = this.nodes[index];
23831 this.tpl.insertBefore(n, this.prepareData(record.data));
23832 n.parentNode.removeChild(n);
23833 this.updateIndexes(index, index);
23836 onAdd : function(ds, records, index){
23837 this.clearSelections();
23838 if(this.nodes.length == 0){
23842 var n = this.nodes[index];
23843 for(var i = 0, len = records.length; i < len; i++){
23844 var d = this.prepareData(records[i].data);
23846 this.tpl.insertBefore(n, d);
23848 this.tpl.append(this.el, d);
23851 this.updateIndexes(index);
23854 onRemove : function(ds, record, index){
23855 this.clearSelections();
23856 this.el.dom.removeChild(this.nodes[index]);
23857 this.updateIndexes(index);
23861 * Refresh an individual node.
23862 * @param {Number} index
23864 refreshNode : function(index){
23865 this.onUpdate(this.store, this.store.getAt(index));
23868 updateIndexes : function(startIndex, endIndex){
23869 var ns = this.nodes;
23870 startIndex = startIndex || 0;
23871 endIndex = endIndex || ns.length - 1;
23872 for(var i = startIndex; i <= endIndex; i++){
23873 ns[i].nodeIndex = i;
23878 * Changes the data store this view uses and refresh the view.
23879 * @param {Store} store
23881 setStore : function(store, initial){
23882 if(!initial && this.store){
23883 this.store.un("datachanged", this.refresh);
23884 this.store.un("add", this.onAdd);
23885 this.store.un("remove", this.onRemove);
23886 this.store.un("update", this.onUpdate);
23887 this.store.un("clear", this.refresh);
23891 store.on("datachanged", this.refresh, this);
23892 store.on("add", this.onAdd, this);
23893 store.on("remove", this.onRemove, this);
23894 store.on("update", this.onUpdate, this);
23895 store.on("clear", this.refresh, this);
23904 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
23905 * @param {HTMLElement} node
23906 * @return {HTMLElement} The template node
23908 findItemFromChild : function(node){
23909 var el = this.el.dom;
23910 if(!node || node.parentNode == el){
23913 var p = node.parentNode;
23914 while(p && p != el){
23915 if(p.parentNode == el){
23924 onClick : function(e){
23925 var item = this.findItemFromChild(e.getTarget());
23927 var index = this.indexOf(item);
23928 if(this.onItemClick(item, index, e) !== false){
23929 this.fireEvent("click", this, index, item, e);
23932 this.clearSelections();
23937 onContextMenu : function(e){
23938 var item = this.findItemFromChild(e.getTarget());
23940 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
23945 onDblClick : function(e){
23946 var item = this.findItemFromChild(e.getTarget());
23948 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
23952 onItemClick : function(item, index, e)
23954 if(this.fireEvent("beforeclick", this, index, item, e) === false){
23957 if (this.toggleSelect) {
23958 var m = this.isSelected(item) ? 'unselect' : 'select';
23961 _t[m](item, true, false);
23964 if(this.multiSelect || this.singleSelect){
23965 if(this.multiSelect && e.shiftKey && this.lastSelection){
23966 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
23968 this.select(item, this.multiSelect && e.ctrlKey);
23969 this.lastSelection = item;
23971 e.preventDefault();
23977 * Get the number of selected nodes.
23980 getSelectionCount : function(){
23981 return this.selections.length;
23985 * Get the currently selected nodes.
23986 * @return {Array} An array of HTMLElements
23988 getSelectedNodes : function(){
23989 return this.selections;
23993 * Get the indexes of the selected nodes.
23996 getSelectedIndexes : function(){
23997 var indexes = [], s = this.selections;
23998 for(var i = 0, len = s.length; i < len; i++){
23999 indexes.push(s[i].nodeIndex);
24005 * Clear all selections
24006 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24008 clearSelections : function(suppressEvent){
24009 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24010 this.cmp.elements = this.selections;
24011 this.cmp.removeClass(this.selectedClass);
24012 this.selections = [];
24013 if(!suppressEvent){
24014 this.fireEvent("selectionchange", this, this.selections);
24020 * Returns true if the passed node is selected
24021 * @param {HTMLElement/Number} node The node or node index
24022 * @return {Boolean}
24024 isSelected : function(node){
24025 var s = this.selections;
24029 node = this.getNode(node);
24030 return s.indexOf(node) !== -1;
24035 * @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
24036 * @param {Boolean} keepExisting (optional) true to keep existing selections
24037 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24039 select : function(nodeInfo, keepExisting, suppressEvent){
24040 if(nodeInfo instanceof Array){
24042 this.clearSelections(true);
24044 for(var i = 0, len = nodeInfo.length; i < len; i++){
24045 this.select(nodeInfo[i], true, true);
24049 var node = this.getNode(nodeInfo);
24050 if(!node || this.isSelected(node)){
24051 return; // already selected.
24054 this.clearSelections(true);
24056 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24057 Roo.fly(node).addClass(this.selectedClass);
24058 this.selections.push(node);
24059 if(!suppressEvent){
24060 this.fireEvent("selectionchange", this, this.selections);
24068 * @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
24069 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24070 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24072 unselect : function(nodeInfo, keepExisting, suppressEvent)
24074 if(nodeInfo instanceof Array){
24075 Roo.each(this.selections, function(s) {
24076 this.unselect(s, nodeInfo);
24080 var node = this.getNode(nodeInfo);
24081 if(!node || !this.isSelected(node)){
24082 Roo.log("not selected");
24083 return; // not selected.
24087 Roo.each(this.selections, function(s) {
24089 Roo.fly(node).removeClass(this.selectedClass);
24096 this.selections= ns;
24097 this.fireEvent("selectionchange", this, this.selections);
24101 * Gets a template node.
24102 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24103 * @return {HTMLElement} The node or null if it wasn't found
24105 getNode : function(nodeInfo){
24106 if(typeof nodeInfo == "string"){
24107 return document.getElementById(nodeInfo);
24108 }else if(typeof nodeInfo == "number"){
24109 return this.nodes[nodeInfo];
24115 * Gets a range template nodes.
24116 * @param {Number} startIndex
24117 * @param {Number} endIndex
24118 * @return {Array} An array of nodes
24120 getNodes : function(start, end){
24121 var ns = this.nodes;
24122 start = start || 0;
24123 end = typeof end == "undefined" ? ns.length - 1 : end;
24126 for(var i = start; i <= end; i++){
24130 for(var i = start; i >= end; i--){
24138 * Finds the index of the passed node
24139 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24140 * @return {Number} The index of the node or -1
24142 indexOf : function(node){
24143 node = this.getNode(node);
24144 if(typeof node.nodeIndex == "number"){
24145 return node.nodeIndex;
24147 var ns = this.nodes;
24148 for(var i = 0, len = ns.length; i < len; i++){
24158 * Ext JS Library 1.1.1
24159 * Copyright(c) 2006-2007, Ext JS, LLC.
24161 * Originally Released Under LGPL - original licence link has changed is not relivant.
24164 * <script type="text/javascript">
24168 * @class Roo.JsonView
24169 * @extends Roo.View
24170 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24172 var view = new Roo.JsonView({
24173 container: "my-element",
24174 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24179 // listen for node click?
24180 view.on("click", function(vw, index, node, e){
24181 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24184 // direct load of JSON data
24185 view.load("foobar.php");
24187 // Example from my blog list
24188 var tpl = new Roo.Template(
24189 '<div class="entry">' +
24190 '<a class="entry-title" href="{link}">{title}</a>' +
24191 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24192 "</div><hr />"
24195 var moreView = new Roo.JsonView({
24196 container : "entry-list",
24200 moreView.on("beforerender", this.sortEntries, this);
24202 url: "/blog/get-posts.php",
24203 params: "allposts=true",
24204 text: "Loading Blog Entries..."
24208 * Note: old code is supported with arguments : (container, template, config)
24212 * Create a new JsonView
24214 * @param {Object} config The config object
24217 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24220 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24222 var um = this.el.getUpdateManager();
24223 um.setRenderer(this);
24224 um.on("update", this.onLoad, this);
24225 um.on("failure", this.onLoadException, this);
24228 * @event beforerender
24229 * Fires before rendering of the downloaded JSON data.
24230 * @param {Roo.JsonView} this
24231 * @param {Object} data The JSON data loaded
24235 * Fires when data is loaded.
24236 * @param {Roo.JsonView} this
24237 * @param {Object} data The JSON data loaded
24238 * @param {Object} response The raw Connect response object
24241 * @event loadexception
24242 * Fires when loading fails.
24243 * @param {Roo.JsonView} this
24244 * @param {Object} response The raw Connect response object
24247 'beforerender' : true,
24249 'loadexception' : true
24252 Roo.extend(Roo.JsonView, Roo.View, {
24254 * @type {String} The root property in the loaded JSON object that contains the data
24259 * Refreshes the view.
24261 refresh : function(){
24262 this.clearSelections();
24263 this.el.update("");
24265 var o = this.jsonData;
24266 if(o && o.length > 0){
24267 for(var i = 0, len = o.length; i < len; i++){
24268 var data = this.prepareData(o[i], i, o);
24269 html[html.length] = this.tpl.apply(data);
24272 html.push(this.emptyText);
24274 this.el.update(html.join(""));
24275 this.nodes = this.el.dom.childNodes;
24276 this.updateIndexes(0);
24280 * 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.
24281 * @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:
24284 url: "your-url.php",
24285 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24286 callback: yourFunction,
24287 scope: yourObject, //(optional scope)
24290 text: "Loading...",
24295 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24296 * 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.
24297 * @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}
24298 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24299 * @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.
24302 var um = this.el.getUpdateManager();
24303 um.update.apply(um, arguments);
24306 render : function(el, response){
24307 this.clearSelections();
24308 this.el.update("");
24311 o = Roo.util.JSON.decode(response.responseText);
24314 o = o[this.jsonRoot];
24319 * The current JSON data or null
24322 this.beforeRender();
24327 * Get the number of records in the current JSON dataset
24330 getCount : function(){
24331 return this.jsonData ? this.jsonData.length : 0;
24335 * Returns the JSON object for the specified node(s)
24336 * @param {HTMLElement/Array} node The node or an array of nodes
24337 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
24338 * you get the JSON object for the node
24340 getNodeData : function(node){
24341 if(node instanceof Array){
24343 for(var i = 0, len = node.length; i < len; i++){
24344 data.push(this.getNodeData(node[i]));
24348 return this.jsonData[this.indexOf(node)] || null;
24351 beforeRender : function(){
24352 this.snapshot = this.jsonData;
24354 this.sort.apply(this, this.sortInfo);
24356 this.fireEvent("beforerender", this, this.jsonData);
24359 onLoad : function(el, o){
24360 this.fireEvent("load", this, this.jsonData, o);
24363 onLoadException : function(el, o){
24364 this.fireEvent("loadexception", this, o);
24368 * Filter the data by a specific property.
24369 * @param {String} property A property on your JSON objects
24370 * @param {String/RegExp} value Either string that the property values
24371 * should start with, or a RegExp to test against the property
24373 filter : function(property, value){
24376 var ss = this.snapshot;
24377 if(typeof value == "string"){
24378 var vlen = value.length;
24380 this.clearFilter();
24383 value = value.toLowerCase();
24384 for(var i = 0, len = ss.length; i < len; i++){
24386 if(o[property].substr(0, vlen).toLowerCase() == value){
24390 } else if(value.exec){ // regex?
24391 for(var i = 0, len = ss.length; i < len; i++){
24393 if(value.test(o[property])){
24400 this.jsonData = data;
24406 * Filter by a function. The passed function will be called with each
24407 * object in the current dataset. If the function returns true the value is kept,
24408 * otherwise it is filtered.
24409 * @param {Function} fn
24410 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
24412 filterBy : function(fn, scope){
24415 var ss = this.snapshot;
24416 for(var i = 0, len = ss.length; i < len; i++){
24418 if(fn.call(scope || this, o)){
24422 this.jsonData = data;
24428 * Clears the current filter.
24430 clearFilter : function(){
24431 if(this.snapshot && this.jsonData != this.snapshot){
24432 this.jsonData = this.snapshot;
24439 * Sorts the data for this view and refreshes it.
24440 * @param {String} property A property on your JSON objects to sort on
24441 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
24442 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
24444 sort : function(property, dir, sortType){
24445 this.sortInfo = Array.prototype.slice.call(arguments, 0);
24448 var dsc = dir && dir.toLowerCase() == "desc";
24449 var f = function(o1, o2){
24450 var v1 = sortType ? sortType(o1[p]) : o1[p];
24451 var v2 = sortType ? sortType(o2[p]) : o2[p];
24454 return dsc ? +1 : -1;
24455 } else if(v1 > v2){
24456 return dsc ? -1 : +1;
24461 this.jsonData.sort(f);
24463 if(this.jsonData != this.snapshot){
24464 this.snapshot.sort(f);
24470 * Ext JS Library 1.1.1
24471 * Copyright(c) 2006-2007, Ext JS, LLC.
24473 * Originally Released Under LGPL - original licence link has changed is not relivant.
24476 * <script type="text/javascript">
24481 * @class Roo.ColorPalette
24482 * @extends Roo.Component
24483 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
24484 * Here's an example of typical usage:
24486 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
24487 cp.render('my-div');
24489 cp.on('select', function(palette, selColor){
24490 // do something with selColor
24494 * Create a new ColorPalette
24495 * @param {Object} config The config object
24497 Roo.ColorPalette = function(config){
24498 Roo.ColorPalette.superclass.constructor.call(this, config);
24502 * Fires when a color is selected
24503 * @param {ColorPalette} this
24504 * @param {String} color The 6-digit color hex code (without the # symbol)
24510 this.on("select", this.handler, this.scope, true);
24513 Roo.extend(Roo.ColorPalette, Roo.Component, {
24515 * @cfg {String} itemCls
24516 * The CSS class to apply to the containing element (defaults to "x-color-palette")
24518 itemCls : "x-color-palette",
24520 * @cfg {String} value
24521 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
24522 * the hex codes are case-sensitive.
24525 clickEvent:'click',
24527 ctype: "Roo.ColorPalette",
24530 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
24532 allowReselect : false,
24535 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
24536 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
24537 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
24538 * of colors with the width setting until the box is symmetrical.</p>
24539 * <p>You can override individual colors if needed:</p>
24541 var cp = new Roo.ColorPalette();
24542 cp.colors[0] = "FF0000"; // change the first box to red
24545 Or you can provide a custom array of your own for complete control:
24547 var cp = new Roo.ColorPalette();
24548 cp.colors = ["000000", "993300", "333300"];
24553 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
24554 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
24555 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
24556 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
24557 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
24561 onRender : function(container, position){
24562 var t = new Roo.MasterTemplate(
24563 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
24565 var c = this.colors;
24566 for(var i = 0, len = c.length; i < len; i++){
24569 var el = document.createElement("div");
24570 el.className = this.itemCls;
24572 container.dom.insertBefore(el, position);
24573 this.el = Roo.get(el);
24574 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
24575 if(this.clickEvent != 'click'){
24576 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
24581 afterRender : function(){
24582 Roo.ColorPalette.superclass.afterRender.call(this);
24584 var s = this.value;
24591 handleClick : function(e, t){
24592 e.preventDefault();
24593 if(!this.disabled){
24594 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
24595 this.select(c.toUpperCase());
24600 * Selects the specified color in the palette (fires the select event)
24601 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
24603 select : function(color){
24604 color = color.replace("#", "");
24605 if(color != this.value || this.allowReselect){
24608 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
24610 el.child("a.color-"+color).addClass("x-color-palette-sel");
24611 this.value = color;
24612 this.fireEvent("select", this, color);
24617 * Ext JS Library 1.1.1
24618 * Copyright(c) 2006-2007, Ext JS, LLC.
24620 * Originally Released Under LGPL - original licence link has changed is not relivant.
24623 * <script type="text/javascript">
24627 * @class Roo.DatePicker
24628 * @extends Roo.Component
24629 * Simple date picker class.
24631 * Create a new DatePicker
24632 * @param {Object} config The config object
24634 Roo.DatePicker = function(config){
24635 Roo.DatePicker.superclass.constructor.call(this, config);
24637 this.value = config && config.value ?
24638 config.value.clearTime() : new Date().clearTime();
24643 * Fires when a date is selected
24644 * @param {DatePicker} this
24645 * @param {Date} date The selected date
24649 * @event monthchange
24650 * Fires when the displayed month changes
24651 * @param {DatePicker} this
24652 * @param {Date} date The selected month
24654 'monthchange': true
24658 this.on("select", this.handler, this.scope || this);
24660 // build the disabledDatesRE
24661 if(!this.disabledDatesRE && this.disabledDates){
24662 var dd = this.disabledDates;
24664 for(var i = 0; i < dd.length; i++){
24666 if(i != dd.length-1) re += "|";
24668 this.disabledDatesRE = new RegExp(re + ")");
24672 Roo.extend(Roo.DatePicker, Roo.Component, {
24674 * @cfg {String} todayText
24675 * The text to display on the button that selects the current date (defaults to "Today")
24677 todayText : "Today",
24679 * @cfg {String} okText
24680 * The text to display on the ok button
24682 okText : " OK ", //   to give the user extra clicking room
24684 * @cfg {String} cancelText
24685 * The text to display on the cancel button
24687 cancelText : "Cancel",
24689 * @cfg {String} todayTip
24690 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
24692 todayTip : "{0} (Spacebar)",
24694 * @cfg {Date} minDate
24695 * Minimum allowable date (JavaScript date object, defaults to null)
24699 * @cfg {Date} maxDate
24700 * Maximum allowable date (JavaScript date object, defaults to null)
24704 * @cfg {String} minText
24705 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
24707 minText : "This date is before the minimum date",
24709 * @cfg {String} maxText
24710 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
24712 maxText : "This date is after the maximum date",
24714 * @cfg {String} format
24715 * The default date format string which can be overriden for localization support. The format must be
24716 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
24720 * @cfg {Array} disabledDays
24721 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
24723 disabledDays : null,
24725 * @cfg {String} disabledDaysText
24726 * The tooltip to display when the date falls on a disabled day (defaults to "")
24728 disabledDaysText : "",
24730 * @cfg {RegExp} disabledDatesRE
24731 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
24733 disabledDatesRE : null,
24735 * @cfg {String} disabledDatesText
24736 * The tooltip text to display when the date falls on a disabled date (defaults to "")
24738 disabledDatesText : "",
24740 * @cfg {Boolean} constrainToViewport
24741 * True to constrain the date picker to the viewport (defaults to true)
24743 constrainToViewport : true,
24745 * @cfg {Array} monthNames
24746 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
24748 monthNames : Date.monthNames,
24750 * @cfg {Array} dayNames
24751 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
24753 dayNames : Date.dayNames,
24755 * @cfg {String} nextText
24756 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
24758 nextText: 'Next Month (Control+Right)',
24760 * @cfg {String} prevText
24761 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
24763 prevText: 'Previous Month (Control+Left)',
24765 * @cfg {String} monthYearText
24766 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
24768 monthYearText: 'Choose a month (Control+Up/Down to move years)',
24770 * @cfg {Number} startDay
24771 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
24775 * @cfg {Bool} showClear
24776 * Show a clear button (usefull for date form elements that can be blank.)
24782 * Sets the value of the date field
24783 * @param {Date} value The date to set
24785 setValue : function(value){
24786 var old = this.value;
24787 this.value = value.clearTime(true);
24789 this.update(this.value);
24794 * Gets the current selected value of the date field
24795 * @return {Date} The selected date
24797 getValue : function(){
24802 focus : function(){
24804 this.update(this.activeDate);
24809 onRender : function(container, position){
24811 '<table cellspacing="0">',
24812 '<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>',
24813 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
24814 var dn = this.dayNames;
24815 for(var i = 0; i < 7; i++){
24816 var d = this.startDay+i;
24820 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
24822 m[m.length] = "</tr></thead><tbody><tr>";
24823 for(var i = 0; i < 42; i++) {
24824 if(i % 7 == 0 && i != 0){
24825 m[m.length] = "</tr><tr>";
24827 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
24829 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
24830 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
24832 var el = document.createElement("div");
24833 el.className = "x-date-picker";
24834 el.innerHTML = m.join("");
24836 container.dom.insertBefore(el, position);
24838 this.el = Roo.get(el);
24839 this.eventEl = Roo.get(el.firstChild);
24841 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
24842 handler: this.showPrevMonth,
24844 preventDefault:true,
24848 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
24849 handler: this.showNextMonth,
24851 preventDefault:true,
24855 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
24857 this.monthPicker = this.el.down('div.x-date-mp');
24858 this.monthPicker.enableDisplayMode('block');
24860 var kn = new Roo.KeyNav(this.eventEl, {
24861 "left" : function(e){
24863 this.showPrevMonth() :
24864 this.update(this.activeDate.add("d", -1));
24867 "right" : function(e){
24869 this.showNextMonth() :
24870 this.update(this.activeDate.add("d", 1));
24873 "up" : function(e){
24875 this.showNextYear() :
24876 this.update(this.activeDate.add("d", -7));
24879 "down" : function(e){
24881 this.showPrevYear() :
24882 this.update(this.activeDate.add("d", 7));
24885 "pageUp" : function(e){
24886 this.showNextMonth();
24889 "pageDown" : function(e){
24890 this.showPrevMonth();
24893 "enter" : function(e){
24894 e.stopPropagation();
24901 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
24903 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
24905 this.el.unselectable();
24907 this.cells = this.el.select("table.x-date-inner tbody td");
24908 this.textNodes = this.el.query("table.x-date-inner tbody span");
24910 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
24912 tooltip: this.monthYearText
24915 this.mbtn.on('click', this.showMonthPicker, this);
24916 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
24919 var today = (new Date()).dateFormat(this.format);
24921 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
24922 if (this.showClear) {
24923 baseTb.add( new Roo.Toolbar.Fill());
24926 text: String.format(this.todayText, today),
24927 tooltip: String.format(this.todayTip, today),
24928 handler: this.selectToday,
24932 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
24935 if (this.showClear) {
24937 baseTb.add( new Roo.Toolbar.Fill());
24940 cls: 'x-btn-icon x-btn-clear',
24941 handler: function() {
24943 this.fireEvent("select", this, '');
24953 this.update(this.value);
24956 createMonthPicker : function(){
24957 if(!this.monthPicker.dom.firstChild){
24958 var buf = ['<table border="0" cellspacing="0">'];
24959 for(var i = 0; i < 6; i++){
24961 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
24962 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
24964 '<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>' :
24965 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
24969 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
24971 '</button><button type="button" class="x-date-mp-cancel">',
24973 '</button></td></tr>',
24976 this.monthPicker.update(buf.join(''));
24977 this.monthPicker.on('click', this.onMonthClick, this);
24978 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
24980 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
24981 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
24983 this.mpMonths.each(function(m, a, i){
24986 m.dom.xmonth = 5 + Math.round(i * .5);
24988 m.dom.xmonth = Math.round((i-1) * .5);
24994 showMonthPicker : function(){
24995 this.createMonthPicker();
24996 var size = this.el.getSize();
24997 this.monthPicker.setSize(size);
24998 this.monthPicker.child('table').setSize(size);
25000 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25001 this.updateMPMonth(this.mpSelMonth);
25002 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25003 this.updateMPYear(this.mpSelYear);
25005 this.monthPicker.slideIn('t', {duration:.2});
25008 updateMPYear : function(y){
25010 var ys = this.mpYears.elements;
25011 for(var i = 1; i <= 10; i++){
25012 var td = ys[i-1], y2;
25014 y2 = y + Math.round(i * .5);
25015 td.firstChild.innerHTML = y2;
25018 y2 = y - (5-Math.round(i * .5));
25019 td.firstChild.innerHTML = y2;
25022 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25026 updateMPMonth : function(sm){
25027 this.mpMonths.each(function(m, a, i){
25028 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25032 selectMPMonth: function(m){
25036 onMonthClick : function(e, t){
25038 var el = new Roo.Element(t), pn;
25039 if(el.is('button.x-date-mp-cancel')){
25040 this.hideMonthPicker();
25042 else if(el.is('button.x-date-mp-ok')){
25043 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25044 this.hideMonthPicker();
25046 else if(pn = el.up('td.x-date-mp-month', 2)){
25047 this.mpMonths.removeClass('x-date-mp-sel');
25048 pn.addClass('x-date-mp-sel');
25049 this.mpSelMonth = pn.dom.xmonth;
25051 else if(pn = el.up('td.x-date-mp-year', 2)){
25052 this.mpYears.removeClass('x-date-mp-sel');
25053 pn.addClass('x-date-mp-sel');
25054 this.mpSelYear = pn.dom.xyear;
25056 else if(el.is('a.x-date-mp-prev')){
25057 this.updateMPYear(this.mpyear-10);
25059 else if(el.is('a.x-date-mp-next')){
25060 this.updateMPYear(this.mpyear+10);
25064 onMonthDblClick : function(e, t){
25066 var el = new Roo.Element(t), pn;
25067 if(pn = el.up('td.x-date-mp-month', 2)){
25068 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25069 this.hideMonthPicker();
25071 else if(pn = el.up('td.x-date-mp-year', 2)){
25072 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25073 this.hideMonthPicker();
25077 hideMonthPicker : function(disableAnim){
25078 if(this.monthPicker){
25079 if(disableAnim === true){
25080 this.monthPicker.hide();
25082 this.monthPicker.slideOut('t', {duration:.2});
25088 showPrevMonth : function(e){
25089 this.update(this.activeDate.add("mo", -1));
25093 showNextMonth : function(e){
25094 this.update(this.activeDate.add("mo", 1));
25098 showPrevYear : function(){
25099 this.update(this.activeDate.add("y", -1));
25103 showNextYear : function(){
25104 this.update(this.activeDate.add("y", 1));
25108 handleMouseWheel : function(e){
25109 var delta = e.getWheelDelta();
25111 this.showPrevMonth();
25113 } else if(delta < 0){
25114 this.showNextMonth();
25120 handleDateClick : function(e, t){
25122 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25123 this.setValue(new Date(t.dateValue));
25124 this.fireEvent("select", this, this.value);
25129 selectToday : function(){
25130 this.setValue(new Date().clearTime());
25131 this.fireEvent("select", this, this.value);
25135 update : function(date)
25137 var vd = this.activeDate;
25138 this.activeDate = date;
25140 var t = date.getTime();
25141 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25142 this.cells.removeClass("x-date-selected");
25143 this.cells.each(function(c){
25144 if(c.dom.firstChild.dateValue == t){
25145 c.addClass("x-date-selected");
25146 setTimeout(function(){
25147 try{c.dom.firstChild.focus();}catch(e){}
25156 var days = date.getDaysInMonth();
25157 var firstOfMonth = date.getFirstDateOfMonth();
25158 var startingPos = firstOfMonth.getDay()-this.startDay;
25160 if(startingPos <= this.startDay){
25164 var pm = date.add("mo", -1);
25165 var prevStart = pm.getDaysInMonth()-startingPos;
25167 var cells = this.cells.elements;
25168 var textEls = this.textNodes;
25169 days += startingPos;
25171 // convert everything to numbers so it's fast
25172 var day = 86400000;
25173 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25174 var today = new Date().clearTime().getTime();
25175 var sel = date.clearTime().getTime();
25176 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25177 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25178 var ddMatch = this.disabledDatesRE;
25179 var ddText = this.disabledDatesText;
25180 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25181 var ddaysText = this.disabledDaysText;
25182 var format = this.format;
25184 var setCellClass = function(cal, cell){
25186 var t = d.getTime();
25187 cell.firstChild.dateValue = t;
25189 cell.className += " x-date-today";
25190 cell.title = cal.todayText;
25193 cell.className += " x-date-selected";
25194 setTimeout(function(){
25195 try{cell.firstChild.focus();}catch(e){}
25200 cell.className = " x-date-disabled";
25201 cell.title = cal.minText;
25205 cell.className = " x-date-disabled";
25206 cell.title = cal.maxText;
25210 if(ddays.indexOf(d.getDay()) != -1){
25211 cell.title = ddaysText;
25212 cell.className = " x-date-disabled";
25215 if(ddMatch && format){
25216 var fvalue = d.dateFormat(format);
25217 if(ddMatch.test(fvalue)){
25218 cell.title = ddText.replace("%0", fvalue);
25219 cell.className = " x-date-disabled";
25225 for(; i < startingPos; i++) {
25226 textEls[i].innerHTML = (++prevStart);
25227 d.setDate(d.getDate()+1);
25228 cells[i].className = "x-date-prevday";
25229 setCellClass(this, cells[i]);
25231 for(; i < days; i++){
25232 intDay = i - startingPos + 1;
25233 textEls[i].innerHTML = (intDay);
25234 d.setDate(d.getDate()+1);
25235 cells[i].className = "x-date-active";
25236 setCellClass(this, cells[i]);
25239 for(; i < 42; i++) {
25240 textEls[i].innerHTML = (++extraDays);
25241 d.setDate(d.getDate()+1);
25242 cells[i].className = "x-date-nextday";
25243 setCellClass(this, cells[i]);
25246 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25247 this.fireEvent('monthchange', this, date);
25249 if(!this.internalRender){
25250 var main = this.el.dom.firstChild;
25251 var w = main.offsetWidth;
25252 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25253 Roo.fly(main).setWidth(w);
25254 this.internalRender = true;
25255 // opera does not respect the auto grow header center column
25256 // then, after it gets a width opera refuses to recalculate
25257 // without a second pass
25258 if(Roo.isOpera && !this.secondPass){
25259 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25260 this.secondPass = true;
25261 this.update.defer(10, this, [date]);
25269 * Ext JS Library 1.1.1
25270 * Copyright(c) 2006-2007, Ext JS, LLC.
25272 * Originally Released Under LGPL - original licence link has changed is not relivant.
25275 * <script type="text/javascript">
25278 * @class Roo.TabPanel
25279 * @extends Roo.util.Observable
25280 * A lightweight tab container.
25284 // basic tabs 1, built from existing content
25285 var tabs = new Roo.TabPanel("tabs1");
25286 tabs.addTab("script", "View Script");
25287 tabs.addTab("markup", "View Markup");
25288 tabs.activate("script");
25290 // more advanced tabs, built from javascript
25291 var jtabs = new Roo.TabPanel("jtabs");
25292 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25294 // set up the UpdateManager
25295 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25296 var updater = tab2.getUpdateManager();
25297 updater.setDefaultUrl("ajax1.htm");
25298 tab2.on('activate', updater.refresh, updater, true);
25300 // Use setUrl for Ajax loading
25301 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25302 tab3.setUrl("ajax2.htm", null, true);
25305 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
25308 jtabs.activate("jtabs-1");
25311 * Create a new TabPanel.
25312 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
25313 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
25315 Roo.TabPanel = function(container, config){
25317 * The container element for this TabPanel.
25318 * @type Roo.Element
25320 this.el = Roo.get(container, true);
25322 if(typeof config == "boolean"){
25323 this.tabPosition = config ? "bottom" : "top";
25325 Roo.apply(this, config);
25328 if(this.tabPosition == "bottom"){
25329 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25330 this.el.addClass("x-tabs-bottom");
25332 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
25333 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
25334 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
25336 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
25338 if(this.tabPosition != "bottom"){
25339 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
25340 * @type Roo.Element
25342 this.bodyEl = Roo.get(this.createBody(this.el.dom));
25343 this.el.addClass("x-tabs-top");
25347 this.bodyEl.setStyle("position", "relative");
25349 this.active = null;
25350 this.activateDelegate = this.activate.createDelegate(this);
25355 * Fires when the active tab changes
25356 * @param {Roo.TabPanel} this
25357 * @param {Roo.TabPanelItem} activePanel The new active tab
25361 * @event beforetabchange
25362 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
25363 * @param {Roo.TabPanel} this
25364 * @param {Object} e Set cancel to true on this object to cancel the tab change
25365 * @param {Roo.TabPanelItem} tab The tab being changed to
25367 "beforetabchange" : true
25370 Roo.EventManager.onWindowResize(this.onResize, this);
25371 this.cpad = this.el.getPadding("lr");
25372 this.hiddenCount = 0;
25375 // toolbar on the tabbar support...
25376 if (this.toolbar) {
25377 var tcfg = this.toolbar;
25378 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
25379 this.toolbar = new Roo.Toolbar(tcfg);
25380 if (Roo.isSafari) {
25381 var tbl = tcfg.container.child('table', true);
25382 tbl.setAttribute('width', '100%');
25389 Roo.TabPanel.superclass.constructor.call(this);
25392 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
25394 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
25396 tabPosition : "top",
25398 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
25400 currentTabWidth : 0,
25402 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
25406 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
25410 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
25412 preferredTabWidth : 175,
25414 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
25416 resizeTabs : false,
25418 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
25420 monitorResize : true,
25422 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
25427 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
25428 * @param {String} id The id of the div to use <b>or create</b>
25429 * @param {String} text The text for the tab
25430 * @param {String} content (optional) Content to put in the TabPanelItem body
25431 * @param {Boolean} closable (optional) True to create a close icon on the tab
25432 * @return {Roo.TabPanelItem} The created TabPanelItem
25434 addTab : function(id, text, content, closable){
25435 var item = new Roo.TabPanelItem(this, id, text, closable);
25436 this.addTabItem(item);
25438 item.setContent(content);
25444 * Returns the {@link Roo.TabPanelItem} with the specified id/index
25445 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
25446 * @return {Roo.TabPanelItem}
25448 getTab : function(id){
25449 return this.items[id];
25453 * Hides the {@link Roo.TabPanelItem} with the specified id/index
25454 * @param {String/Number} id The id or index of the TabPanelItem to hide.
25456 hideTab : function(id){
25457 var t = this.items[id];
25460 this.hiddenCount++;
25461 this.autoSizeTabs();
25466 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
25467 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
25469 unhideTab : function(id){
25470 var t = this.items[id];
25472 t.setHidden(false);
25473 this.hiddenCount--;
25474 this.autoSizeTabs();
25479 * Adds an existing {@link Roo.TabPanelItem}.
25480 * @param {Roo.TabPanelItem} item The TabPanelItem to add
25482 addTabItem : function(item){
25483 this.items[item.id] = item;
25484 this.items.push(item);
25485 if(this.resizeTabs){
25486 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
25487 this.autoSizeTabs();
25494 * Removes a {@link Roo.TabPanelItem}.
25495 * @param {String/Number} id The id or index of the TabPanelItem to remove.
25497 removeTab : function(id){
25498 var items = this.items;
25499 var tab = items[id];
25500 if(!tab) { return; }
25501 var index = items.indexOf(tab);
25502 if(this.active == tab && items.length > 1){
25503 var newTab = this.getNextAvailable(index);
25508 this.stripEl.dom.removeChild(tab.pnode.dom);
25509 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
25510 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
25512 items.splice(index, 1);
25513 delete this.items[tab.id];
25514 tab.fireEvent("close", tab);
25515 tab.purgeListeners();
25516 this.autoSizeTabs();
25519 getNextAvailable : function(start){
25520 var items = this.items;
25522 // look for a next tab that will slide over to
25523 // replace the one being removed
25524 while(index < items.length){
25525 var item = items[++index];
25526 if(item && !item.isHidden()){
25530 // if one isn't found select the previous tab (on the left)
25533 var item = items[--index];
25534 if(item && !item.isHidden()){
25542 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
25543 * @param {String/Number} id The id or index of the TabPanelItem to disable.
25545 disableTab : function(id){
25546 var tab = this.items[id];
25547 if(tab && this.active != tab){
25553 * Enables a {@link Roo.TabPanelItem} that is disabled.
25554 * @param {String/Number} id The id or index of the TabPanelItem to enable.
25556 enableTab : function(id){
25557 var tab = this.items[id];
25562 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
25563 * @param {String/Number} id The id or index of the TabPanelItem to activate.
25564 * @return {Roo.TabPanelItem} The TabPanelItem.
25566 activate : function(id){
25567 var tab = this.items[id];
25571 if(tab == this.active || tab.disabled){
25575 this.fireEvent("beforetabchange", this, e, tab);
25576 if(e.cancel !== true && !tab.disabled){
25578 this.active.hide();
25580 this.active = this.items[id];
25581 this.active.show();
25582 this.fireEvent("tabchange", this, this.active);
25588 * Gets the active {@link Roo.TabPanelItem}.
25589 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
25591 getActiveTab : function(){
25592 return this.active;
25596 * Updates the tab body element to fit the height of the container element
25597 * for overflow scrolling
25598 * @param {Number} targetHeight (optional) Override the starting height from the elements height
25600 syncHeight : function(targetHeight){
25601 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
25602 var bm = this.bodyEl.getMargins();
25603 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
25604 this.bodyEl.setHeight(newHeight);
25608 onResize : function(){
25609 if(this.monitorResize){
25610 this.autoSizeTabs();
25615 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
25617 beginUpdate : function(){
25618 this.updating = true;
25622 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
25624 endUpdate : function(){
25625 this.updating = false;
25626 this.autoSizeTabs();
25630 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
25632 autoSizeTabs : function(){
25633 var count = this.items.length;
25634 var vcount = count - this.hiddenCount;
25635 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
25636 var w = Math.max(this.el.getWidth() - this.cpad, 10);
25637 var availWidth = Math.floor(w / vcount);
25638 var b = this.stripBody;
25639 if(b.getWidth() > w){
25640 var tabs = this.items;
25641 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
25642 if(availWidth < this.minTabWidth){
25643 /*if(!this.sleft){ // incomplete scrolling code
25644 this.createScrollButtons();
25647 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
25650 if(this.currentTabWidth < this.preferredTabWidth){
25651 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
25657 * Returns the number of tabs in this TabPanel.
25660 getCount : function(){
25661 return this.items.length;
25665 * Resizes all the tabs to the passed width
25666 * @param {Number} The new width
25668 setTabWidth : function(width){
25669 this.currentTabWidth = width;
25670 for(var i = 0, len = this.items.length; i < len; i++) {
25671 if(!this.items[i].isHidden())this.items[i].setWidth(width);
25676 * Destroys this TabPanel
25677 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
25679 destroy : function(removeEl){
25680 Roo.EventManager.removeResizeListener(this.onResize, this);
25681 for(var i = 0, len = this.items.length; i < len; i++){
25682 this.items[i].purgeListeners();
25684 if(removeEl === true){
25685 this.el.update("");
25692 * @class Roo.TabPanelItem
25693 * @extends Roo.util.Observable
25694 * Represents an individual item (tab plus body) in a TabPanel.
25695 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
25696 * @param {String} id The id of this TabPanelItem
25697 * @param {String} text The text for the tab of this TabPanelItem
25698 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
25700 Roo.TabPanelItem = function(tabPanel, id, text, closable){
25702 * The {@link Roo.TabPanel} this TabPanelItem belongs to
25703 * @type Roo.TabPanel
25705 this.tabPanel = tabPanel;
25707 * The id for this TabPanelItem
25712 this.disabled = false;
25716 this.loaded = false;
25717 this.closable = closable;
25720 * The body element for this TabPanelItem.
25721 * @type Roo.Element
25723 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
25724 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
25725 this.bodyEl.setStyle("display", "block");
25726 this.bodyEl.setStyle("zoom", "1");
25729 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
25731 this.el = Roo.get(els.el, true);
25732 this.inner = Roo.get(els.inner, true);
25733 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
25734 this.pnode = Roo.get(els.el.parentNode, true);
25735 this.el.on("mousedown", this.onTabMouseDown, this);
25736 this.el.on("click", this.onTabClick, this);
25739 var c = Roo.get(els.close, true);
25740 c.dom.title = this.closeText;
25741 c.addClassOnOver("close-over");
25742 c.on("click", this.closeClick, this);
25748 * Fires when this tab becomes the active tab.
25749 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25750 * @param {Roo.TabPanelItem} this
25754 * @event beforeclose
25755 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
25756 * @param {Roo.TabPanelItem} this
25757 * @param {Object} e Set cancel to true on this object to cancel the close.
25759 "beforeclose": true,
25762 * Fires when this tab is closed.
25763 * @param {Roo.TabPanelItem} this
25767 * @event deactivate
25768 * Fires when this tab is no longer the active tab.
25769 * @param {Roo.TabPanel} tabPanel The parent TabPanel
25770 * @param {Roo.TabPanelItem} this
25772 "deactivate" : true
25774 this.hidden = false;
25776 Roo.TabPanelItem.superclass.constructor.call(this);
25779 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
25780 purgeListeners : function(){
25781 Roo.util.Observable.prototype.purgeListeners.call(this);
25782 this.el.removeAllListeners();
25785 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
25788 this.pnode.addClass("on");
25791 this.tabPanel.stripWrap.repaint();
25793 this.fireEvent("activate", this.tabPanel, this);
25797 * Returns true if this tab is the active tab.
25798 * @return {Boolean}
25800 isActive : function(){
25801 return this.tabPanel.getActiveTab() == this;
25805 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
25808 this.pnode.removeClass("on");
25810 this.fireEvent("deactivate", this.tabPanel, this);
25813 hideAction : function(){
25814 this.bodyEl.hide();
25815 this.bodyEl.setStyle("position", "absolute");
25816 this.bodyEl.setLeft("-20000px");
25817 this.bodyEl.setTop("-20000px");
25820 showAction : function(){
25821 this.bodyEl.setStyle("position", "relative");
25822 this.bodyEl.setTop("");
25823 this.bodyEl.setLeft("");
25824 this.bodyEl.show();
25828 * Set the tooltip for the tab.
25829 * @param {String} tooltip The tab's tooltip
25831 setTooltip : function(text){
25832 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
25833 this.textEl.dom.qtip = text;
25834 this.textEl.dom.removeAttribute('title');
25836 this.textEl.dom.title = text;
25840 onTabClick : function(e){
25841 e.preventDefault();
25842 this.tabPanel.activate(this.id);
25845 onTabMouseDown : function(e){
25846 e.preventDefault();
25847 this.tabPanel.activate(this.id);
25850 getWidth : function(){
25851 return this.inner.getWidth();
25854 setWidth : function(width){
25855 var iwidth = width - this.pnode.getPadding("lr");
25856 this.inner.setWidth(iwidth);
25857 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
25858 this.pnode.setWidth(width);
25862 * Show or hide the tab
25863 * @param {Boolean} hidden True to hide or false to show.
25865 setHidden : function(hidden){
25866 this.hidden = hidden;
25867 this.pnode.setStyle("display", hidden ? "none" : "");
25871 * Returns true if this tab is "hidden"
25872 * @return {Boolean}
25874 isHidden : function(){
25875 return this.hidden;
25879 * Returns the text for this tab
25882 getText : function(){
25886 autoSize : function(){
25887 //this.el.beginMeasure();
25888 this.textEl.setWidth(1);
25889 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
25890 //this.el.endMeasure();
25894 * Sets the text for the tab (Note: this also sets the tooltip text)
25895 * @param {String} text The tab's text and tooltip
25897 setText : function(text){
25899 this.textEl.update(text);
25900 this.setTooltip(text);
25901 if(!this.tabPanel.resizeTabs){
25906 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
25908 activate : function(){
25909 this.tabPanel.activate(this.id);
25913 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
25915 disable : function(){
25916 if(this.tabPanel.active != this){
25917 this.disabled = true;
25918 this.pnode.addClass("disabled");
25923 * Enables this TabPanelItem if it was previously disabled.
25925 enable : function(){
25926 this.disabled = false;
25927 this.pnode.removeClass("disabled");
25931 * Sets the content for this TabPanelItem.
25932 * @param {String} content The content
25933 * @param {Boolean} loadScripts true to look for and load scripts
25935 setContent : function(content, loadScripts){
25936 this.bodyEl.update(content, loadScripts);
25940 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
25941 * @return {Roo.UpdateManager} The UpdateManager
25943 getUpdateManager : function(){
25944 return this.bodyEl.getUpdateManager();
25948 * Set a URL to be used to load the content for this TabPanelItem.
25949 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
25950 * @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)
25951 * @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)
25952 * @return {Roo.UpdateManager} The UpdateManager
25954 setUrl : function(url, params, loadOnce){
25955 if(this.refreshDelegate){
25956 this.un('activate', this.refreshDelegate);
25958 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
25959 this.on("activate", this.refreshDelegate);
25960 return this.bodyEl.getUpdateManager();
25964 _handleRefresh : function(url, params, loadOnce){
25965 if(!loadOnce || !this.loaded){
25966 var updater = this.bodyEl.getUpdateManager();
25967 updater.update(url, params, this._setLoaded.createDelegate(this));
25972 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
25973 * Will fail silently if the setUrl method has not been called.
25974 * This does not activate the panel, just updates its content.
25976 refresh : function(){
25977 if(this.refreshDelegate){
25978 this.loaded = false;
25979 this.refreshDelegate();
25984 _setLoaded : function(){
25985 this.loaded = true;
25989 closeClick : function(e){
25992 this.fireEvent("beforeclose", this, o);
25993 if(o.cancel !== true){
25994 this.tabPanel.removeTab(this.id);
25998 * The text displayed in the tooltip for the close icon.
26001 closeText : "Close this tab"
26005 Roo.TabPanel.prototype.createStrip = function(container){
26006 var strip = document.createElement("div");
26007 strip.className = "x-tabs-wrap";
26008 container.appendChild(strip);
26012 Roo.TabPanel.prototype.createStripList = function(strip){
26013 // div wrapper for retard IE
26014 // returns the "tr" element.
26015 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26016 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26017 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26018 return strip.firstChild.firstChild.firstChild.firstChild;
26021 Roo.TabPanel.prototype.createBody = function(container){
26022 var body = document.createElement("div");
26023 Roo.id(body, "tab-body");
26024 Roo.fly(body).addClass("x-tabs-body");
26025 container.appendChild(body);
26029 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26030 var body = Roo.getDom(id);
26032 body = document.createElement("div");
26035 Roo.fly(body).addClass("x-tabs-item-body");
26036 bodyEl.insertBefore(body, bodyEl.firstChild);
26040 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26041 var td = document.createElement("td");
26042 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26043 //stripEl.appendChild(td);
26045 td.className = "x-tabs-closable";
26046 if(!this.closeTpl){
26047 this.closeTpl = new Roo.Template(
26048 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26049 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26050 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26053 var el = this.closeTpl.overwrite(td, {"text": text});
26054 var close = el.getElementsByTagName("div")[0];
26055 var inner = el.getElementsByTagName("em")[0];
26056 return {"el": el, "close": close, "inner": inner};
26059 this.tabTpl = new Roo.Template(
26060 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26061 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26064 var el = this.tabTpl.overwrite(td, {"text": text});
26065 var inner = el.getElementsByTagName("em")[0];
26066 return {"el": el, "inner": inner};
26070 * Ext JS Library 1.1.1
26071 * Copyright(c) 2006-2007, Ext JS, LLC.
26073 * Originally Released Under LGPL - original licence link has changed is not relivant.
26076 * <script type="text/javascript">
26080 * @class Roo.Button
26081 * @extends Roo.util.Observable
26082 * Simple Button class
26083 * @cfg {String} text The button text
26084 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26085 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26086 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26087 * @cfg {Object} scope The scope of the handler
26088 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26089 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26090 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26091 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26092 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26093 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26094 applies if enableToggle = true)
26095 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26096 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26097 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26099 * Create a new button
26100 * @param {Object} config The config object
26102 Roo.Button = function(renderTo, config)
26106 renderTo = config.renderTo || false;
26109 Roo.apply(this, config);
26113 * Fires when this button is clicked
26114 * @param {Button} this
26115 * @param {EventObject} e The click event
26120 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26121 * @param {Button} this
26122 * @param {Boolean} pressed
26127 * Fires when the mouse hovers over the button
26128 * @param {Button} this
26129 * @param {Event} e The event object
26131 'mouseover' : true,
26134 * Fires when the mouse exits the button
26135 * @param {Button} this
26136 * @param {Event} e The event object
26141 * Fires when the button is rendered
26142 * @param {Button} this
26147 this.menu = Roo.menu.MenuMgr.get(this.menu);
26149 // register listeners first!! - so render can be captured..
26150 Roo.util.Observable.call(this);
26152 this.render(renderTo);
26158 Roo.extend(Roo.Button, Roo.util.Observable, {
26164 * Read-only. True if this button is hidden
26169 * Read-only. True if this button is disabled
26174 * Read-only. True if this button is pressed (only if enableToggle = true)
26180 * @cfg {Number} tabIndex
26181 * The DOM tabIndex for this button (defaults to undefined)
26183 tabIndex : undefined,
26186 * @cfg {Boolean} enableToggle
26187 * True to enable pressed/not pressed toggling (defaults to false)
26189 enableToggle: false,
26191 * @cfg {Mixed} menu
26192 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26196 * @cfg {String} menuAlign
26197 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26199 menuAlign : "tl-bl?",
26202 * @cfg {String} iconCls
26203 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26205 iconCls : undefined,
26207 * @cfg {String} type
26208 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26213 menuClassTarget: 'tr',
26216 * @cfg {String} clickEvent
26217 * The type of event to map to the button's event handler (defaults to 'click')
26219 clickEvent : 'click',
26222 * @cfg {Boolean} handleMouseEvents
26223 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26225 handleMouseEvents : true,
26228 * @cfg {String} tooltipType
26229 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26231 tooltipType : 'qtip',
26234 * @cfg {String} cls
26235 * A CSS class to apply to the button's main element.
26239 * @cfg {Roo.Template} template (Optional)
26240 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26241 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26242 * require code modifications if required elements (e.g. a button) aren't present.
26246 render : function(renderTo){
26248 if(this.hideParent){
26249 this.parentEl = Roo.get(renderTo);
26251 if(!this.dhconfig){
26252 if(!this.template){
26253 if(!Roo.Button.buttonTemplate){
26254 // hideous table template
26255 Roo.Button.buttonTemplate = new Roo.Template(
26256 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26257 '<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>',
26258 "</tr></tbody></table>");
26260 this.template = Roo.Button.buttonTemplate;
26262 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26263 var btnEl = btn.child("button:first");
26264 btnEl.on('focus', this.onFocus, this);
26265 btnEl.on('blur', this.onBlur, this);
26267 btn.addClass(this.cls);
26270 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26273 btnEl.addClass(this.iconCls);
26275 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26278 if(this.tabIndex !== undefined){
26279 btnEl.dom.tabIndex = this.tabIndex;
26282 if(typeof this.tooltip == 'object'){
26283 Roo.QuickTips.tips(Roo.apply({
26287 btnEl.dom[this.tooltipType] = this.tooltip;
26291 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26295 this.el.dom.id = this.el.id = this.id;
26298 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26299 this.menu.on("show", this.onMenuShow, this);
26300 this.menu.on("hide", this.onMenuHide, this);
26302 btn.addClass("x-btn");
26303 if(Roo.isIE && !Roo.isIE7){
26304 this.autoWidth.defer(1, this);
26308 if(this.handleMouseEvents){
26309 btn.on("mouseover", this.onMouseOver, this);
26310 btn.on("mouseout", this.onMouseOut, this);
26311 btn.on("mousedown", this.onMouseDown, this);
26313 btn.on(this.clickEvent, this.onClick, this);
26314 //btn.on("mouseup", this.onMouseUp, this);
26321 Roo.ButtonToggleMgr.register(this);
26323 this.el.addClass("x-btn-pressed");
26326 var repeater = new Roo.util.ClickRepeater(btn,
26327 typeof this.repeat == "object" ? this.repeat : {}
26329 repeater.on("click", this.onClick, this);
26332 this.fireEvent('render', this);
26336 * Returns the button's underlying element
26337 * @return {Roo.Element} The element
26339 getEl : function(){
26344 * Destroys this Button and removes any listeners.
26346 destroy : function(){
26347 Roo.ButtonToggleMgr.unregister(this);
26348 this.el.removeAllListeners();
26349 this.purgeListeners();
26354 autoWidth : function(){
26356 this.el.setWidth("auto");
26357 if(Roo.isIE7 && Roo.isStrict){
26358 var ib = this.el.child('button');
26359 if(ib && ib.getWidth() > 20){
26361 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26366 this.el.beginMeasure();
26368 if(this.el.getWidth() < this.minWidth){
26369 this.el.setWidth(this.minWidth);
26372 this.el.endMeasure();
26379 * Assigns this button's click handler
26380 * @param {Function} handler The function to call when the button is clicked
26381 * @param {Object} scope (optional) Scope for the function passed in
26383 setHandler : function(handler, scope){
26384 this.handler = handler;
26385 this.scope = scope;
26389 * Sets this button's text
26390 * @param {String} text The button text
26392 setText : function(text){
26395 this.el.child("td.x-btn-center button.x-btn-text").update(text);
26401 * Gets the text for this button
26402 * @return {String} The button text
26404 getText : function(){
26412 this.hidden = false;
26414 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
26422 this.hidden = true;
26424 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
26429 * Convenience function for boolean show/hide
26430 * @param {Boolean} visible True to show, false to hide
26432 setVisible: function(visible){
26441 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
26442 * @param {Boolean} state (optional) Force a particular state
26444 toggle : function(state){
26445 state = state === undefined ? !this.pressed : state;
26446 if(state != this.pressed){
26448 this.el.addClass("x-btn-pressed");
26449 this.pressed = true;
26450 this.fireEvent("toggle", this, true);
26452 this.el.removeClass("x-btn-pressed");
26453 this.pressed = false;
26454 this.fireEvent("toggle", this, false);
26456 if(this.toggleHandler){
26457 this.toggleHandler.call(this.scope || this, this, state);
26465 focus : function(){
26466 this.el.child('button:first').focus();
26470 * Disable this button
26472 disable : function(){
26474 this.el.addClass("x-btn-disabled");
26476 this.disabled = true;
26480 * Enable this button
26482 enable : function(){
26484 this.el.removeClass("x-btn-disabled");
26486 this.disabled = false;
26490 * Convenience function for boolean enable/disable
26491 * @param {Boolean} enabled True to enable, false to disable
26493 setDisabled : function(v){
26494 this[v !== true ? "enable" : "disable"]();
26498 onClick : function(e){
26500 e.preventDefault();
26505 if(!this.disabled){
26506 if(this.enableToggle){
26509 if(this.menu && !this.menu.isVisible()){
26510 this.menu.show(this.el, this.menuAlign);
26512 this.fireEvent("click", this, e);
26514 this.el.removeClass("x-btn-over");
26515 this.handler.call(this.scope || this, this, e);
26520 onMouseOver : function(e){
26521 if(!this.disabled){
26522 this.el.addClass("x-btn-over");
26523 this.fireEvent('mouseover', this, e);
26527 onMouseOut : function(e){
26528 if(!e.within(this.el, true)){
26529 this.el.removeClass("x-btn-over");
26530 this.fireEvent('mouseout', this, e);
26534 onFocus : function(e){
26535 if(!this.disabled){
26536 this.el.addClass("x-btn-focus");
26540 onBlur : function(e){
26541 this.el.removeClass("x-btn-focus");
26544 onMouseDown : function(e){
26545 if(!this.disabled && e.button == 0){
26546 this.el.addClass("x-btn-click");
26547 Roo.get(document).on('mouseup', this.onMouseUp, this);
26551 onMouseUp : function(e){
26553 this.el.removeClass("x-btn-click");
26554 Roo.get(document).un('mouseup', this.onMouseUp, this);
26558 onMenuShow : function(e){
26559 this.el.addClass("x-btn-menu-active");
26562 onMenuHide : function(e){
26563 this.el.removeClass("x-btn-menu-active");
26567 // Private utility class used by Button
26568 Roo.ButtonToggleMgr = function(){
26571 function toggleGroup(btn, state){
26573 var g = groups[btn.toggleGroup];
26574 for(var i = 0, l = g.length; i < l; i++){
26576 g[i].toggle(false);
26583 register : function(btn){
26584 if(!btn.toggleGroup){
26587 var g = groups[btn.toggleGroup];
26589 g = groups[btn.toggleGroup] = [];
26592 btn.on("toggle", toggleGroup);
26595 unregister : function(btn){
26596 if(!btn.toggleGroup){
26599 var g = groups[btn.toggleGroup];
26602 btn.un("toggle", toggleGroup);
26608 * Ext JS Library 1.1.1
26609 * Copyright(c) 2006-2007, Ext JS, LLC.
26611 * Originally Released Under LGPL - original licence link has changed is not relivant.
26614 * <script type="text/javascript">
26618 * @class Roo.SplitButton
26619 * @extends Roo.Button
26620 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
26621 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
26622 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
26623 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
26624 * @cfg {String} arrowTooltip The title attribute of the arrow
26626 * Create a new menu button
26627 * @param {String/HTMLElement/Element} renderTo The element to append the button to
26628 * @param {Object} config The config object
26630 Roo.SplitButton = function(renderTo, config){
26631 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
26633 * @event arrowclick
26634 * Fires when this button's arrow is clicked
26635 * @param {SplitButton} this
26636 * @param {EventObject} e The click event
26638 this.addEvents({"arrowclick":true});
26641 Roo.extend(Roo.SplitButton, Roo.Button, {
26642 render : function(renderTo){
26643 // this is one sweet looking template!
26644 var tpl = new Roo.Template(
26645 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
26646 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
26647 '<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>',
26648 "</tbody></table></td><td>",
26649 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
26650 '<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>',
26651 "</tbody></table></td></tr></table>"
26653 var btn = tpl.append(renderTo, [this.text, this.type], true);
26654 var btnEl = btn.child("button");
26656 btn.addClass(this.cls);
26659 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26662 btnEl.addClass(this.iconCls);
26664 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26668 if(this.handleMouseEvents){
26669 btn.on("mouseover", this.onMouseOver, this);
26670 btn.on("mouseout", this.onMouseOut, this);
26671 btn.on("mousedown", this.onMouseDown, this);
26672 btn.on("mouseup", this.onMouseUp, this);
26674 btn.on(this.clickEvent, this.onClick, this);
26676 if(typeof this.tooltip == 'object'){
26677 Roo.QuickTips.tips(Roo.apply({
26681 btnEl.dom[this.tooltipType] = this.tooltip;
26684 if(this.arrowTooltip){
26685 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
26694 this.el.addClass("x-btn-pressed");
26696 if(Roo.isIE && !Roo.isIE7){
26697 this.autoWidth.defer(1, this);
26702 this.menu.on("show", this.onMenuShow, this);
26703 this.menu.on("hide", this.onMenuHide, this);
26705 this.fireEvent('render', this);
26709 autoWidth : function(){
26711 var tbl = this.el.child("table:first");
26712 var tbl2 = this.el.child("table:last");
26713 this.el.setWidth("auto");
26714 tbl.setWidth("auto");
26715 if(Roo.isIE7 && Roo.isStrict){
26716 var ib = this.el.child('button:first');
26717 if(ib && ib.getWidth() > 20){
26719 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
26724 this.el.beginMeasure();
26726 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
26727 tbl.setWidth(this.minWidth-tbl2.getWidth());
26730 this.el.endMeasure();
26733 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
26737 * Sets this button's click handler
26738 * @param {Function} handler The function to call when the button is clicked
26739 * @param {Object} scope (optional) Scope for the function passed above
26741 setHandler : function(handler, scope){
26742 this.handler = handler;
26743 this.scope = scope;
26747 * Sets this button's arrow click handler
26748 * @param {Function} handler The function to call when the arrow is clicked
26749 * @param {Object} scope (optional) Scope for the function passed above
26751 setArrowHandler : function(handler, scope){
26752 this.arrowHandler = handler;
26753 this.scope = scope;
26759 focus : function(){
26761 this.el.child("button:first").focus();
26766 onClick : function(e){
26767 e.preventDefault();
26768 if(!this.disabled){
26769 if(e.getTarget(".x-btn-menu-arrow-wrap")){
26770 if(this.menu && !this.menu.isVisible()){
26771 this.menu.show(this.el, this.menuAlign);
26773 this.fireEvent("arrowclick", this, e);
26774 if(this.arrowHandler){
26775 this.arrowHandler.call(this.scope || this, this, e);
26778 this.fireEvent("click", this, e);
26780 this.handler.call(this.scope || this, this, e);
26786 onMouseDown : function(e){
26787 if(!this.disabled){
26788 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
26792 onMouseUp : function(e){
26793 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
26798 // backwards compat
26799 Roo.MenuButton = Roo.SplitButton;/*
26801 * Ext JS Library 1.1.1
26802 * Copyright(c) 2006-2007, Ext JS, LLC.
26804 * Originally Released Under LGPL - original licence link has changed is not relivant.
26807 * <script type="text/javascript">
26811 * @class Roo.Toolbar
26812 * Basic Toolbar class.
26814 * Creates a new Toolbar
26815 * @param {Object} container The config object
26817 Roo.Toolbar = function(container, buttons, config)
26819 /// old consturctor format still supported..
26820 if(container instanceof Array){ // omit the container for later rendering
26821 buttons = container;
26825 if (typeof(container) == 'object' && container.xtype) {
26826 config = container;
26827 container = config.container;
26828 buttons = config.buttons || []; // not really - use items!!
26831 if (config && config.items) {
26832 xitems = config.items;
26833 delete config.items;
26835 Roo.apply(this, config);
26836 this.buttons = buttons;
26839 this.render(container);
26841 this.xitems = xitems;
26842 Roo.each(xitems, function(b) {
26848 Roo.Toolbar.prototype = {
26850 * @cfg {Array} items
26851 * array of button configs or elements to add (will be converted to a MixedCollection)
26855 * @cfg {String/HTMLElement/Element} container
26856 * The id or element that will contain the toolbar
26859 render : function(ct){
26860 this.el = Roo.get(ct);
26862 this.el.addClass(this.cls);
26864 // using a table allows for vertical alignment
26865 // 100% width is needed by Safari...
26866 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
26867 this.tr = this.el.child("tr", true);
26869 this.items = new Roo.util.MixedCollection(false, function(o){
26870 return o.id || ("item" + (++autoId));
26873 this.add.apply(this, this.buttons);
26874 delete this.buttons;
26879 * Adds element(s) to the toolbar -- this function takes a variable number of
26880 * arguments of mixed type and adds them to the toolbar.
26881 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
26883 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
26884 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
26885 * <li>Field: Any form field (equivalent to {@link #addField})</li>
26886 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
26887 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
26888 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
26889 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
26890 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
26891 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
26893 * @param {Mixed} arg2
26894 * @param {Mixed} etc.
26897 var a = arguments, l = a.length;
26898 for(var i = 0; i < l; i++){
26903 _add : function(el) {
26906 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
26909 if (el.applyTo){ // some kind of form field
26910 return this.addField(el);
26912 if (el.render){ // some kind of Toolbar.Item
26913 return this.addItem(el);
26915 if (typeof el == "string"){ // string
26916 if(el == "separator" || el == "-"){
26917 return this.addSeparator();
26920 return this.addSpacer();
26923 return this.addFill();
26925 return this.addText(el);
26928 if(el.tagName){ // element
26929 return this.addElement(el);
26931 if(typeof el == "object"){ // must be button config?
26932 return this.addButton(el);
26934 // and now what?!?!
26940 * Add an Xtype element
26941 * @param {Object} xtype Xtype Object
26942 * @return {Object} created Object
26944 addxtype : function(e){
26945 return this.add(e);
26949 * Returns the Element for this toolbar.
26950 * @return {Roo.Element}
26952 getEl : function(){
26958 * @return {Roo.Toolbar.Item} The separator item
26960 addSeparator : function(){
26961 return this.addItem(new Roo.Toolbar.Separator());
26965 * Adds a spacer element
26966 * @return {Roo.Toolbar.Spacer} The spacer item
26968 addSpacer : function(){
26969 return this.addItem(new Roo.Toolbar.Spacer());
26973 * Adds a fill element that forces subsequent additions to the right side of the toolbar
26974 * @return {Roo.Toolbar.Fill} The fill item
26976 addFill : function(){
26977 return this.addItem(new Roo.Toolbar.Fill());
26981 * Adds any standard HTML element to the toolbar
26982 * @param {String/HTMLElement/Element} el The element or id of the element to add
26983 * @return {Roo.Toolbar.Item} The element's item
26985 addElement : function(el){
26986 return this.addItem(new Roo.Toolbar.Item(el));
26989 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
26990 * @type Roo.util.MixedCollection
26995 * Adds any Toolbar.Item or subclass
26996 * @param {Roo.Toolbar.Item} item
26997 * @return {Roo.Toolbar.Item} The item
26999 addItem : function(item){
27000 var td = this.nextBlock();
27002 this.items.add(item);
27007 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27008 * @param {Object/Array} config A button config or array of configs
27009 * @return {Roo.Toolbar.Button/Array}
27011 addButton : function(config){
27012 if(config instanceof Array){
27014 for(var i = 0, len = config.length; i < len; i++) {
27015 buttons.push(this.addButton(config[i]));
27020 if(!(config instanceof Roo.Toolbar.Button)){
27022 new Roo.Toolbar.SplitButton(config) :
27023 new Roo.Toolbar.Button(config);
27025 var td = this.nextBlock();
27032 * Adds text to the toolbar
27033 * @param {String} text The text to add
27034 * @return {Roo.Toolbar.Item} The element's item
27036 addText : function(text){
27037 return this.addItem(new Roo.Toolbar.TextItem(text));
27041 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27042 * @param {Number} index The index where the item is to be inserted
27043 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27044 * @return {Roo.Toolbar.Button/Item}
27046 insertButton : function(index, item){
27047 if(item instanceof Array){
27049 for(var i = 0, len = item.length; i < len; i++) {
27050 buttons.push(this.insertButton(index + i, item[i]));
27054 if (!(item instanceof Roo.Toolbar.Button)){
27055 item = new Roo.Toolbar.Button(item);
27057 var td = document.createElement("td");
27058 this.tr.insertBefore(td, this.tr.childNodes[index]);
27060 this.items.insert(index, item);
27065 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27066 * @param {Object} config
27067 * @return {Roo.Toolbar.Item} The element's item
27069 addDom : function(config, returnEl){
27070 var td = this.nextBlock();
27071 Roo.DomHelper.overwrite(td, config);
27072 var ti = new Roo.Toolbar.Item(td.firstChild);
27074 this.items.add(ti);
27079 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27080 * @type Roo.util.MixedCollection
27085 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27086 * Note: the field should not have been rendered yet. For a field that has already been
27087 * rendered, use {@link #addElement}.
27088 * @param {Roo.form.Field} field
27089 * @return {Roo.ToolbarItem}
27093 addField : function(field) {
27094 if (!this.fields) {
27096 this.fields = new Roo.util.MixedCollection(false, function(o){
27097 return o.id || ("item" + (++autoId));
27102 var td = this.nextBlock();
27104 var ti = new Roo.Toolbar.Item(td.firstChild);
27106 this.items.add(ti);
27107 this.fields.add(field);
27118 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27119 this.el.child('div').hide();
27127 this.el.child('div').show();
27131 nextBlock : function(){
27132 var td = document.createElement("td");
27133 this.tr.appendChild(td);
27138 destroy : function(){
27139 if(this.items){ // rendered?
27140 Roo.destroy.apply(Roo, this.items.items);
27142 if(this.fields){ // rendered?
27143 Roo.destroy.apply(Roo, this.fields.items);
27145 Roo.Element.uncache(this.el, this.tr);
27150 * @class Roo.Toolbar.Item
27151 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27153 * Creates a new Item
27154 * @param {HTMLElement} el
27156 Roo.Toolbar.Item = function(el){
27157 this.el = Roo.getDom(el);
27158 this.id = Roo.id(this.el);
27159 this.hidden = false;
27162 Roo.Toolbar.Item.prototype = {
27165 * Get this item's HTML Element
27166 * @return {HTMLElement}
27168 getEl : function(){
27173 render : function(td){
27175 td.appendChild(this.el);
27179 * Removes and destroys this item.
27181 destroy : function(){
27182 this.td.parentNode.removeChild(this.td);
27189 this.hidden = false;
27190 this.td.style.display = "";
27197 this.hidden = true;
27198 this.td.style.display = "none";
27202 * Convenience function for boolean show/hide.
27203 * @param {Boolean} visible true to show/false to hide
27205 setVisible: function(visible){
27214 * Try to focus this item.
27216 focus : function(){
27217 Roo.fly(this.el).focus();
27221 * Disables this item.
27223 disable : function(){
27224 Roo.fly(this.td).addClass("x-item-disabled");
27225 this.disabled = true;
27226 this.el.disabled = true;
27230 * Enables this item.
27232 enable : function(){
27233 Roo.fly(this.td).removeClass("x-item-disabled");
27234 this.disabled = false;
27235 this.el.disabled = false;
27241 * @class Roo.Toolbar.Separator
27242 * @extends Roo.Toolbar.Item
27243 * A simple toolbar separator class
27245 * Creates a new Separator
27247 Roo.Toolbar.Separator = function(){
27248 var s = document.createElement("span");
27249 s.className = "ytb-sep";
27250 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27252 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27253 enable:Roo.emptyFn,
27254 disable:Roo.emptyFn,
27259 * @class Roo.Toolbar.Spacer
27260 * @extends Roo.Toolbar.Item
27261 * A simple element that adds extra horizontal space to a toolbar.
27263 * Creates a new Spacer
27265 Roo.Toolbar.Spacer = function(){
27266 var s = document.createElement("div");
27267 s.className = "ytb-spacer";
27268 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27270 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27271 enable:Roo.emptyFn,
27272 disable:Roo.emptyFn,
27277 * @class Roo.Toolbar.Fill
27278 * @extends Roo.Toolbar.Spacer
27279 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27281 * Creates a new Spacer
27283 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27285 render : function(td){
27286 td.style.width = '100%';
27287 Roo.Toolbar.Fill.superclass.render.call(this, td);
27292 * @class Roo.Toolbar.TextItem
27293 * @extends Roo.Toolbar.Item
27294 * A simple class that renders text directly into a toolbar.
27296 * Creates a new TextItem
27297 * @param {String} text
27299 Roo.Toolbar.TextItem = function(text){
27300 if (typeof(text) == 'object') {
27303 var s = document.createElement("span");
27304 s.className = "ytb-text";
27305 s.innerHTML = text;
27306 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
27308 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
27309 enable:Roo.emptyFn,
27310 disable:Roo.emptyFn,
27315 * @class Roo.Toolbar.Button
27316 * @extends Roo.Button
27317 * A button that renders into a toolbar.
27319 * Creates a new Button
27320 * @param {Object} config A standard {@link Roo.Button} config object
27322 Roo.Toolbar.Button = function(config){
27323 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
27325 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
27326 render : function(td){
27328 Roo.Toolbar.Button.superclass.render.call(this, td);
27332 * Removes and destroys this button
27334 destroy : function(){
27335 Roo.Toolbar.Button.superclass.destroy.call(this);
27336 this.td.parentNode.removeChild(this.td);
27340 * Shows this button
27343 this.hidden = false;
27344 this.td.style.display = "";
27348 * Hides this button
27351 this.hidden = true;
27352 this.td.style.display = "none";
27356 * Disables this item
27358 disable : function(){
27359 Roo.fly(this.td).addClass("x-item-disabled");
27360 this.disabled = true;
27364 * Enables this item
27366 enable : function(){
27367 Roo.fly(this.td).removeClass("x-item-disabled");
27368 this.disabled = false;
27371 // backwards compat
27372 Roo.ToolbarButton = Roo.Toolbar.Button;
27375 * @class Roo.Toolbar.SplitButton
27376 * @extends Roo.SplitButton
27377 * A menu button that renders into a toolbar.
27379 * Creates a new SplitButton
27380 * @param {Object} config A standard {@link Roo.SplitButton} config object
27382 Roo.Toolbar.SplitButton = function(config){
27383 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
27385 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
27386 render : function(td){
27388 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
27392 * Removes and destroys this button
27394 destroy : function(){
27395 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
27396 this.td.parentNode.removeChild(this.td);
27400 * Shows this button
27403 this.hidden = false;
27404 this.td.style.display = "";
27408 * Hides this button
27411 this.hidden = true;
27412 this.td.style.display = "none";
27416 // backwards compat
27417 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
27419 * Ext JS Library 1.1.1
27420 * Copyright(c) 2006-2007, Ext JS, LLC.
27422 * Originally Released Under LGPL - original licence link has changed is not relivant.
27425 * <script type="text/javascript">
27429 * @class Roo.PagingToolbar
27430 * @extends Roo.Toolbar
27431 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27433 * Create a new PagingToolbar
27434 * @param {Object} config The config object
27436 Roo.PagingToolbar = function(el, ds, config)
27438 // old args format still supported... - xtype is prefered..
27439 if (typeof(el) == 'object' && el.xtype) {
27440 // created from xtype...
27442 ds = el.dataSource;
27443 el = config.container;
27446 if (config.items) {
27447 items = config.items;
27451 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
27454 this.renderButtons(this.el);
27457 // supprot items array.
27459 Roo.each(items, function(e) {
27460 this.add(Roo.factory(e));
27465 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
27467 * @cfg {Roo.data.Store} dataSource
27468 * The underlying data store providing the paged data
27471 * @cfg {String/HTMLElement/Element} container
27472 * container The id or element that will contain the toolbar
27475 * @cfg {Boolean} displayInfo
27476 * True to display the displayMsg (defaults to false)
27479 * @cfg {Number} pageSize
27480 * The number of records to display per page (defaults to 20)
27484 * @cfg {String} displayMsg
27485 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27487 displayMsg : 'Displaying {0} - {1} of {2}',
27489 * @cfg {String} emptyMsg
27490 * The message to display when no records are found (defaults to "No data to display")
27492 emptyMsg : 'No data to display',
27494 * Customizable piece of the default paging text (defaults to "Page")
27497 beforePageText : "Page",
27499 * Customizable piece of the default paging text (defaults to "of %0")
27502 afterPageText : "of {0}",
27504 * Customizable piece of the default paging text (defaults to "First Page")
27507 firstText : "First Page",
27509 * Customizable piece of the default paging text (defaults to "Previous Page")
27512 prevText : "Previous Page",
27514 * Customizable piece of the default paging text (defaults to "Next Page")
27517 nextText : "Next Page",
27519 * Customizable piece of the default paging text (defaults to "Last Page")
27522 lastText : "Last Page",
27524 * Customizable piece of the default paging text (defaults to "Refresh")
27527 refreshText : "Refresh",
27530 renderButtons : function(el){
27531 Roo.PagingToolbar.superclass.render.call(this, el);
27532 this.first = this.addButton({
27533 tooltip: this.firstText,
27534 cls: "x-btn-icon x-grid-page-first",
27536 handler: this.onClick.createDelegate(this, ["first"])
27538 this.prev = this.addButton({
27539 tooltip: this.prevText,
27540 cls: "x-btn-icon x-grid-page-prev",
27542 handler: this.onClick.createDelegate(this, ["prev"])
27544 //this.addSeparator();
27545 this.add(this.beforePageText);
27546 this.field = Roo.get(this.addDom({
27551 cls: "x-grid-page-number"
27553 this.field.on("keydown", this.onPagingKeydown, this);
27554 this.field.on("focus", function(){this.dom.select();});
27555 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
27556 this.field.setHeight(18);
27557 //this.addSeparator();
27558 this.next = this.addButton({
27559 tooltip: this.nextText,
27560 cls: "x-btn-icon x-grid-page-next",
27562 handler: this.onClick.createDelegate(this, ["next"])
27564 this.last = this.addButton({
27565 tooltip: this.lastText,
27566 cls: "x-btn-icon x-grid-page-last",
27568 handler: this.onClick.createDelegate(this, ["last"])
27570 //this.addSeparator();
27571 this.loading = this.addButton({
27572 tooltip: this.refreshText,
27573 cls: "x-btn-icon x-grid-loading",
27574 handler: this.onClick.createDelegate(this, ["refresh"])
27577 if(this.displayInfo){
27578 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
27583 updateInfo : function(){
27584 if(this.displayEl){
27585 var count = this.ds.getCount();
27586 var msg = count == 0 ?
27590 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27592 this.displayEl.update(msg);
27597 onLoad : function(ds, r, o){
27598 this.cursor = o.params ? o.params.start : 0;
27599 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
27601 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
27602 this.field.dom.value = ap;
27603 this.first.setDisabled(ap == 1);
27604 this.prev.setDisabled(ap == 1);
27605 this.next.setDisabled(ap == ps);
27606 this.last.setDisabled(ap == ps);
27607 this.loading.enable();
27612 getPageData : function(){
27613 var total = this.ds.getTotalCount();
27616 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27617 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27622 onLoadError : function(){
27623 this.loading.enable();
27627 onPagingKeydown : function(e){
27628 var k = e.getKey();
27629 var d = this.getPageData();
27631 var v = this.field.dom.value, pageNum;
27632 if(!v || isNaN(pageNum = parseInt(v, 10))){
27633 this.field.dom.value = d.activePage;
27636 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27637 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27640 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))
27642 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27643 this.field.dom.value = pageNum;
27644 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27647 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27649 var v = this.field.dom.value, pageNum;
27650 var increment = (e.shiftKey) ? 10 : 1;
27651 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27653 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27654 this.field.dom.value = d.activePage;
27657 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27659 this.field.dom.value = parseInt(v, 10) + increment;
27660 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27661 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27668 beforeLoad : function(){
27670 this.loading.disable();
27675 onClick : function(which){
27679 ds.load({params:{start: 0, limit: this.pageSize}});
27682 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27685 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27688 var total = ds.getTotalCount();
27689 var extra = total % this.pageSize;
27690 var lastStart = extra ? (total - extra) : total-this.pageSize;
27691 ds.load({params:{start: lastStart, limit: this.pageSize}});
27694 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27700 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27701 * @param {Roo.data.Store} store The data store to unbind
27703 unbind : function(ds){
27704 ds.un("beforeload", this.beforeLoad, this);
27705 ds.un("load", this.onLoad, this);
27706 ds.un("loadexception", this.onLoadError, this);
27707 ds.un("remove", this.updateInfo, this);
27708 ds.un("add", this.updateInfo, this);
27709 this.ds = undefined;
27713 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27714 * @param {Roo.data.Store} store The data store to bind
27716 bind : function(ds){
27717 ds.on("beforeload", this.beforeLoad, this);
27718 ds.on("load", this.onLoad, this);
27719 ds.on("loadexception", this.onLoadError, this);
27720 ds.on("remove", this.updateInfo, this);
27721 ds.on("add", this.updateInfo, this);
27726 * Ext JS Library 1.1.1
27727 * Copyright(c) 2006-2007, Ext JS, LLC.
27729 * Originally Released Under LGPL - original licence link has changed is not relivant.
27732 * <script type="text/javascript">
27736 * @class Roo.Resizable
27737 * @extends Roo.util.Observable
27738 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
27739 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
27740 * 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
27741 * the element will be wrapped for you automatically.</p>
27742 * <p>Here is the list of valid resize handles:</p>
27745 ------ -------------------
27754 'hd' horizontal drag
27757 * <p>Here's an example showing the creation of a typical Resizable:</p>
27759 var resizer = new Roo.Resizable("element-id", {
27767 resizer.on("resize", myHandler);
27769 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
27770 * resizer.east.setDisplayed(false);</p>
27771 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
27772 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
27773 * resize operation's new size (defaults to [0, 0])
27774 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
27775 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
27776 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
27777 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
27778 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
27779 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
27780 * @cfg {Number} width The width of the element in pixels (defaults to null)
27781 * @cfg {Number} height The height of the element in pixels (defaults to null)
27782 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
27783 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
27784 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
27785 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
27786 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
27787 * in favor of the handles config option (defaults to false)
27788 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
27789 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
27790 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
27791 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
27792 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
27793 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
27794 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
27795 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
27796 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
27797 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
27798 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
27800 * Create a new resizable component
27801 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
27802 * @param {Object} config configuration options
27804 Roo.Resizable = function(el, config)
27806 this.el = Roo.get(el);
27808 if(config && config.wrap){
27809 config.resizeChild = this.el;
27810 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
27811 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
27812 this.el.setStyle("overflow", "hidden");
27813 this.el.setPositioning(config.resizeChild.getPositioning());
27814 config.resizeChild.clearPositioning();
27815 if(!config.width || !config.height){
27816 var csize = config.resizeChild.getSize();
27817 this.el.setSize(csize.width, csize.height);
27819 if(config.pinned && !config.adjustments){
27820 config.adjustments = "auto";
27824 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
27825 this.proxy.unselectable();
27826 this.proxy.enableDisplayMode('block');
27828 Roo.apply(this, config);
27831 this.disableTrackOver = true;
27832 this.el.addClass("x-resizable-pinned");
27834 // if the element isn't positioned, make it relative
27835 var position = this.el.getStyle("position");
27836 if(position != "absolute" && position != "fixed"){
27837 this.el.setStyle("position", "relative");
27839 if(!this.handles){ // no handles passed, must be legacy style
27840 this.handles = 's,e,se';
27841 if(this.multiDirectional){
27842 this.handles += ',n,w';
27845 if(this.handles == "all"){
27846 this.handles = "n s e w ne nw se sw";
27848 var hs = this.handles.split(/\s*?[,;]\s*?| /);
27849 var ps = Roo.Resizable.positions;
27850 for(var i = 0, len = hs.length; i < len; i++){
27851 if(hs[i] && ps[hs[i]]){
27852 var pos = ps[hs[i]];
27853 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
27857 this.corner = this.southeast;
27859 // updateBox = the box can move..
27860 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
27861 this.updateBox = true;
27864 this.activeHandle = null;
27866 if(this.resizeChild){
27867 if(typeof this.resizeChild == "boolean"){
27868 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
27870 this.resizeChild = Roo.get(this.resizeChild, true);
27874 if(this.adjustments == "auto"){
27875 var rc = this.resizeChild;
27876 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
27877 if(rc && (hw || hn)){
27878 rc.position("relative");
27879 rc.setLeft(hw ? hw.el.getWidth() : 0);
27880 rc.setTop(hn ? hn.el.getHeight() : 0);
27882 this.adjustments = [
27883 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
27884 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
27888 if(this.draggable){
27889 this.dd = this.dynamic ?
27890 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
27891 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
27897 * @event beforeresize
27898 * Fired before resize is allowed. Set enabled to false to cancel resize.
27899 * @param {Roo.Resizable} this
27900 * @param {Roo.EventObject} e The mousedown event
27902 "beforeresize" : true,
27905 * Fired after a resize.
27906 * @param {Roo.Resizable} this
27907 * @param {Number} width The new width
27908 * @param {Number} height The new height
27909 * @param {Roo.EventObject} e The mouseup event
27914 if(this.width !== null && this.height !== null){
27915 this.resizeTo(this.width, this.height);
27917 this.updateChildSize();
27920 this.el.dom.style.zoom = 1;
27922 Roo.Resizable.superclass.constructor.call(this);
27925 Roo.extend(Roo.Resizable, Roo.util.Observable, {
27926 resizeChild : false,
27927 adjustments : [0, 0],
27937 multiDirectional : false,
27938 disableTrackOver : false,
27939 easing : 'easeOutStrong',
27940 widthIncrement : 0,
27941 heightIncrement : 0,
27945 preserveRatio : false,
27946 transparent: false,
27952 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
27954 constrainTo: undefined,
27956 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
27958 resizeRegion: undefined,
27962 * Perform a manual resize
27963 * @param {Number} width
27964 * @param {Number} height
27966 resizeTo : function(width, height){
27967 this.el.setSize(width, height);
27968 this.updateChildSize();
27969 this.fireEvent("resize", this, width, height, null);
27973 startSizing : function(e, handle){
27974 this.fireEvent("beforeresize", this, e);
27975 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
27978 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
27979 this.overlay.unselectable();
27980 this.overlay.enableDisplayMode("block");
27981 this.overlay.on("mousemove", this.onMouseMove, this);
27982 this.overlay.on("mouseup", this.onMouseUp, this);
27984 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
27986 this.resizing = true;
27987 this.startBox = this.el.getBox();
27988 this.startPoint = e.getXY();
27989 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
27990 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
27992 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27993 this.overlay.show();
27995 if(this.constrainTo) {
27996 var ct = Roo.get(this.constrainTo);
27997 this.resizeRegion = ct.getRegion().adjust(
27998 ct.getFrameWidth('t'),
27999 ct.getFrameWidth('l'),
28000 -ct.getFrameWidth('b'),
28001 -ct.getFrameWidth('r')
28005 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28007 this.proxy.setBox(this.startBox);
28009 this.proxy.setStyle('visibility', 'visible');
28015 onMouseDown : function(handle, e){
28018 this.activeHandle = handle;
28019 this.startSizing(e, handle);
28024 onMouseUp : function(e){
28025 var size = this.resizeElement();
28026 this.resizing = false;
28028 this.overlay.hide();
28030 this.fireEvent("resize", this, size.width, size.height, e);
28034 updateChildSize : function(){
28035 if(this.resizeChild){
28037 var child = this.resizeChild;
28038 var adj = this.adjustments;
28039 if(el.dom.offsetWidth){
28040 var b = el.getSize(true);
28041 child.setSize(b.width+adj[0], b.height+adj[1]);
28043 // Second call here for IE
28044 // The first call enables instant resizing and
28045 // the second call corrects scroll bars if they
28048 setTimeout(function(){
28049 if(el.dom.offsetWidth){
28050 var b = el.getSize(true);
28051 child.setSize(b.width+adj[0], b.height+adj[1]);
28059 snap : function(value, inc, min){
28060 if(!inc || !value) return value;
28061 var newValue = value;
28062 var m = value % inc;
28065 newValue = value + (inc-m);
28067 newValue = value - m;
28070 return Math.max(min, newValue);
28074 resizeElement : function(){
28075 var box = this.proxy.getBox();
28076 if(this.updateBox){
28077 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28079 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28081 this.updateChildSize();
28089 constrain : function(v, diff, m, mx){
28092 }else if(v - diff > mx){
28099 onMouseMove : function(e){
28101 try{// try catch so if something goes wrong the user doesn't get hung
28103 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28107 //var curXY = this.startPoint;
28108 var curSize = this.curSize || this.startBox;
28109 var x = this.startBox.x, y = this.startBox.y;
28110 var ox = x, oy = y;
28111 var w = curSize.width, h = curSize.height;
28112 var ow = w, oh = h;
28113 var mw = this.minWidth, mh = this.minHeight;
28114 var mxw = this.maxWidth, mxh = this.maxHeight;
28115 var wi = this.widthIncrement;
28116 var hi = this.heightIncrement;
28118 var eventXY = e.getXY();
28119 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28120 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28122 var pos = this.activeHandle.position;
28127 w = Math.min(Math.max(mw, w), mxw);
28132 h = Math.min(Math.max(mh, h), mxh);
28137 w = Math.min(Math.max(mw, w), mxw);
28138 h = Math.min(Math.max(mh, h), mxh);
28141 diffY = this.constrain(h, diffY, mh, mxh);
28148 var adiffX = Math.abs(diffX);
28149 var sub = (adiffX % wi); // how much
28150 if (sub > (wi/2)) { // far enough to snap
28151 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28153 // remove difference..
28154 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28158 x = Math.max(this.minX, x);
28161 diffX = this.constrain(w, diffX, mw, mxw);
28167 w = Math.min(Math.max(mw, w), mxw);
28168 diffY = this.constrain(h, diffY, mh, mxh);
28173 diffX = this.constrain(w, diffX, mw, mxw);
28174 diffY = this.constrain(h, diffY, mh, mxh);
28181 diffX = this.constrain(w, diffX, mw, mxw);
28183 h = Math.min(Math.max(mh, h), mxh);
28189 var sw = this.snap(w, wi, mw);
28190 var sh = this.snap(h, hi, mh);
28191 if(sw != w || sh != h){
28214 if(this.preserveRatio){
28219 h = Math.min(Math.max(mh, h), mxh);
28224 w = Math.min(Math.max(mw, w), mxw);
28229 w = Math.min(Math.max(mw, w), mxw);
28235 w = Math.min(Math.max(mw, w), mxw);
28241 h = Math.min(Math.max(mh, h), mxh);
28249 h = Math.min(Math.max(mh, h), mxh);
28259 h = Math.min(Math.max(mh, h), mxh);
28267 if (pos == 'hdrag') {
28270 this.proxy.setBounds(x, y, w, h);
28272 this.resizeElement();
28279 handleOver : function(){
28281 this.el.addClass("x-resizable-over");
28286 handleOut : function(){
28287 if(!this.resizing){
28288 this.el.removeClass("x-resizable-over");
28293 * Returns the element this component is bound to.
28294 * @return {Roo.Element}
28296 getEl : function(){
28301 * Returns the resizeChild element (or null).
28302 * @return {Roo.Element}
28304 getResizeChild : function(){
28305 return this.resizeChild;
28309 * Destroys this resizable. If the element was wrapped and
28310 * removeEl is not true then the element remains.
28311 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
28313 destroy : function(removeEl){
28314 this.proxy.remove();
28316 this.overlay.removeAllListeners();
28317 this.overlay.remove();
28319 var ps = Roo.Resizable.positions;
28321 if(typeof ps[k] != "function" && this[ps[k]]){
28322 var h = this[ps[k]];
28323 h.el.removeAllListeners();
28328 this.el.update("");
28335 // hash to map config positions to true positions
28336 Roo.Resizable.positions = {
28337 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
28342 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
28344 // only initialize the template if resizable is used
28345 var tpl = Roo.DomHelper.createTemplate(
28346 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
28349 Roo.Resizable.Handle.prototype.tpl = tpl;
28351 this.position = pos;
28353 // show north drag fro topdra
28354 var handlepos = pos == 'hdrag' ? 'north' : pos;
28356 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
28357 if (pos == 'hdrag') {
28358 this.el.setStyle('cursor', 'pointer');
28360 this.el.unselectable();
28362 this.el.setOpacity(0);
28364 this.el.on("mousedown", this.onMouseDown, this);
28365 if(!disableTrackOver){
28366 this.el.on("mouseover", this.onMouseOver, this);
28367 this.el.on("mouseout", this.onMouseOut, this);
28372 Roo.Resizable.Handle.prototype = {
28373 afterResize : function(rz){
28377 onMouseDown : function(e){
28378 this.rz.onMouseDown(this, e);
28381 onMouseOver : function(e){
28382 this.rz.handleOver(this, e);
28385 onMouseOut : function(e){
28386 this.rz.handleOut(this, e);
28390 * Ext JS Library 1.1.1
28391 * Copyright(c) 2006-2007, Ext JS, LLC.
28393 * Originally Released Under LGPL - original licence link has changed is not relivant.
28396 * <script type="text/javascript">
28400 * @class Roo.Editor
28401 * @extends Roo.Component
28402 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
28404 * Create a new Editor
28405 * @param {Roo.form.Field} field The Field object (or descendant)
28406 * @param {Object} config The config object
28408 Roo.Editor = function(field, config){
28409 Roo.Editor.superclass.constructor.call(this, config);
28410 this.field = field;
28413 * @event beforestartedit
28414 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
28415 * false from the handler of this event.
28416 * @param {Editor} this
28417 * @param {Roo.Element} boundEl The underlying element bound to this editor
28418 * @param {Mixed} value The field value being set
28420 "beforestartedit" : true,
28423 * Fires when this editor is displayed
28424 * @param {Roo.Element} boundEl The underlying element bound to this editor
28425 * @param {Mixed} value The starting field value
28427 "startedit" : true,
28429 * @event beforecomplete
28430 * Fires after a change has been made to the field, but before the change is reflected in the underlying
28431 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
28432 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
28433 * event will not fire since no edit actually occurred.
28434 * @param {Editor} this
28435 * @param {Mixed} value The current field value
28436 * @param {Mixed} startValue The original field value
28438 "beforecomplete" : true,
28441 * Fires after editing is complete and any changed value has been written to the underlying field.
28442 * @param {Editor} this
28443 * @param {Mixed} value The current field value
28444 * @param {Mixed} startValue The original field value
28448 * @event specialkey
28449 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
28450 * {@link Roo.EventObject#getKey} to determine which key was pressed.
28451 * @param {Roo.form.Field} this
28452 * @param {Roo.EventObject} e The event object
28454 "specialkey" : true
28458 Roo.extend(Roo.Editor, Roo.Component, {
28460 * @cfg {Boolean/String} autosize
28461 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
28462 * or "height" to adopt the height only (defaults to false)
28465 * @cfg {Boolean} revertInvalid
28466 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
28467 * validation fails (defaults to true)
28470 * @cfg {Boolean} ignoreNoChange
28471 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
28472 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
28473 * will never be ignored.
28476 * @cfg {Boolean} hideEl
28477 * False to keep the bound element visible while the editor is displayed (defaults to true)
28480 * @cfg {Mixed} value
28481 * The data value of the underlying field (defaults to "")
28485 * @cfg {String} alignment
28486 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
28490 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
28491 * for bottom-right shadow (defaults to "frame")
28495 * @cfg {Boolean} constrain True to constrain the editor to the viewport
28499 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
28501 completeOnEnter : false,
28503 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
28505 cancelOnEsc : false,
28507 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
28512 onRender : function(ct, position){
28513 this.el = new Roo.Layer({
28514 shadow: this.shadow,
28520 constrain: this.constrain
28522 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
28523 if(this.field.msgTarget != 'title'){
28524 this.field.msgTarget = 'qtip';
28526 this.field.render(this.el);
28528 this.field.el.dom.setAttribute('autocomplete', 'off');
28530 this.field.on("specialkey", this.onSpecialKey, this);
28531 if(this.swallowKeys){
28532 this.field.el.swallowEvent(['keydown','keypress']);
28535 this.field.on("blur", this.onBlur, this);
28536 if(this.field.grow){
28537 this.field.on("autosize", this.el.sync, this.el, {delay:1});
28541 onSpecialKey : function(field, e)
28543 //Roo.log('editor onSpecialKey');
28544 if(this.completeOnEnter && e.getKey() == e.ENTER){
28546 this.completeEdit();
28549 // do not fire special key otherwise it might hide close the editor...
28550 if(e.getKey() == e.ENTER){
28553 if(this.cancelOnEsc && e.getKey() == e.ESC){
28557 this.fireEvent('specialkey', field, e);
28562 * Starts the editing process and shows the editor.
28563 * @param {String/HTMLElement/Element} el The element to edit
28564 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
28565 * to the innerHTML of el.
28567 startEdit : function(el, value){
28569 this.completeEdit();
28571 this.boundEl = Roo.get(el);
28572 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
28573 if(!this.rendered){
28574 this.render(this.parentEl || document.body);
28576 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
28579 this.startValue = v;
28580 this.field.setValue(v);
28582 var sz = this.boundEl.getSize();
28583 switch(this.autoSize){
28585 this.setSize(sz.width, "");
28588 this.setSize("", sz.height);
28591 this.setSize(sz.width, sz.height);
28594 this.el.alignTo(this.boundEl, this.alignment);
28595 this.editing = true;
28597 Roo.QuickTips.disable();
28603 * Sets the height and width of this editor.
28604 * @param {Number} width The new width
28605 * @param {Number} height The new height
28607 setSize : function(w, h){
28608 this.field.setSize(w, h);
28615 * Realigns the editor to the bound field based on the current alignment config value.
28617 realign : function(){
28618 this.el.alignTo(this.boundEl, this.alignment);
28622 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
28623 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
28625 completeEdit : function(remainVisible){
28629 var v = this.getValue();
28630 if(this.revertInvalid !== false && !this.field.isValid()){
28631 v = this.startValue;
28632 this.cancelEdit(true);
28634 if(String(v) === String(this.startValue) && this.ignoreNoChange){
28635 this.editing = false;
28639 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
28640 this.editing = false;
28641 if(this.updateEl && this.boundEl){
28642 this.boundEl.update(v);
28644 if(remainVisible !== true){
28647 this.fireEvent("complete", this, v, this.startValue);
28652 onShow : function(){
28654 if(this.hideEl !== false){
28655 this.boundEl.hide();
28658 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
28659 this.fixIEFocus = true;
28660 this.deferredFocus.defer(50, this);
28662 this.field.focus();
28664 this.fireEvent("startedit", this.boundEl, this.startValue);
28667 deferredFocus : function(){
28669 this.field.focus();
28674 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
28675 * reverted to the original starting value.
28676 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
28677 * cancel (defaults to false)
28679 cancelEdit : function(remainVisible){
28681 this.setValue(this.startValue);
28682 if(remainVisible !== true){
28689 onBlur : function(){
28690 if(this.allowBlur !== true && this.editing){
28691 this.completeEdit();
28696 onHide : function(){
28698 this.completeEdit();
28702 if(this.field.collapse){
28703 this.field.collapse();
28706 if(this.hideEl !== false){
28707 this.boundEl.show();
28710 Roo.QuickTips.enable();
28715 * Sets the data value of the editor
28716 * @param {Mixed} value Any valid value supported by the underlying field
28718 setValue : function(v){
28719 this.field.setValue(v);
28723 * Gets the data value of the editor
28724 * @return {Mixed} The data value
28726 getValue : function(){
28727 return this.field.getValue();
28731 * Ext JS Library 1.1.1
28732 * Copyright(c) 2006-2007, Ext JS, LLC.
28734 * Originally Released Under LGPL - original licence link has changed is not relivant.
28737 * <script type="text/javascript">
28741 * @class Roo.BasicDialog
28742 * @extends Roo.util.Observable
28743 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
28745 var dlg = new Roo.BasicDialog("my-dlg", {
28754 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
28755 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
28756 dlg.addButton('Cancel', dlg.hide, dlg);
28759 <b>A Dialog should always be a direct child of the body element.</b>
28760 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
28761 * @cfg {String} title Default text to display in the title bar (defaults to null)
28762 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28763 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
28764 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
28765 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
28766 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
28767 * (defaults to null with no animation)
28768 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
28769 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
28770 * property for valid values (defaults to 'all')
28771 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
28772 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
28773 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
28774 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
28775 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
28776 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
28777 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
28778 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
28779 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
28780 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
28781 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
28782 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
28783 * draggable = true (defaults to false)
28784 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
28785 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
28786 * shadow (defaults to false)
28787 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
28788 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
28789 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
28790 * @cfg {Array} buttons Array of buttons
28791 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
28793 * Create a new BasicDialog.
28794 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
28795 * @param {Object} config Configuration options
28797 Roo.BasicDialog = function(el, config){
28798 this.el = Roo.get(el);
28799 var dh = Roo.DomHelper;
28800 if(!this.el && config && config.autoCreate){
28801 if(typeof config.autoCreate == "object"){
28802 if(!config.autoCreate.id){
28803 config.autoCreate.id = el;
28805 this.el = dh.append(document.body,
28806 config.autoCreate, true);
28808 this.el = dh.append(document.body,
28809 {tag: "div", id: el, style:'visibility:hidden;'}, true);
28813 el.setDisplayed(true);
28814 el.hide = this.hideAction;
28816 el.addClass("x-dlg");
28818 Roo.apply(this, config);
28820 this.proxy = el.createProxy("x-dlg-proxy");
28821 this.proxy.hide = this.hideAction;
28822 this.proxy.setOpacity(.5);
28826 el.setWidth(config.width);
28829 el.setHeight(config.height);
28831 this.size = el.getSize();
28832 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
28833 this.xy = [config.x,config.y];
28835 this.xy = el.getCenterXY(true);
28837 /** The header element @type Roo.Element */
28838 this.header = el.child("> .x-dlg-hd");
28839 /** The body element @type Roo.Element */
28840 this.body = el.child("> .x-dlg-bd");
28841 /** The footer element @type Roo.Element */
28842 this.footer = el.child("> .x-dlg-ft");
28845 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
28848 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
28851 this.header.unselectable();
28853 this.header.update(this.title);
28855 // this element allows the dialog to be focused for keyboard event
28856 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
28857 this.focusEl.swallowEvent("click", true);
28859 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
28861 // wrap the body and footer for special rendering
28862 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
28864 this.bwrap.dom.appendChild(this.footer.dom);
28867 this.bg = this.el.createChild({
28868 tag: "div", cls:"x-dlg-bg",
28869 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
28871 this.centerBg = this.bg.child("div.x-dlg-bg-center");
28874 if(this.autoScroll !== false && !this.autoTabs){
28875 this.body.setStyle("overflow", "auto");
28878 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
28880 if(this.closable !== false){
28881 this.el.addClass("x-dlg-closable");
28882 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
28883 this.close.on("click", this.closeClick, this);
28884 this.close.addClassOnOver("x-dlg-close-over");
28886 if(this.collapsible !== false){
28887 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
28888 this.collapseBtn.on("click", this.collapseClick, this);
28889 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
28890 this.header.on("dblclick", this.collapseClick, this);
28892 if(this.resizable !== false){
28893 this.el.addClass("x-dlg-resizable");
28894 this.resizer = new Roo.Resizable(el, {
28895 minWidth: this.minWidth || 80,
28896 minHeight:this.minHeight || 80,
28897 handles: this.resizeHandles || "all",
28900 this.resizer.on("beforeresize", this.beforeResize, this);
28901 this.resizer.on("resize", this.onResize, this);
28903 if(this.draggable !== false){
28904 el.addClass("x-dlg-draggable");
28905 if (!this.proxyDrag) {
28906 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
28909 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
28911 dd.setHandleElId(this.header.id);
28912 dd.endDrag = this.endMove.createDelegate(this);
28913 dd.startDrag = this.startMove.createDelegate(this);
28914 dd.onDrag = this.onDrag.createDelegate(this);
28919 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
28920 this.mask.enableDisplayMode("block");
28922 this.el.addClass("x-dlg-modal");
28925 this.shadow = new Roo.Shadow({
28926 mode : typeof this.shadow == "string" ? this.shadow : "sides",
28927 offset : this.shadowOffset
28930 this.shadowOffset = 0;
28932 if(Roo.useShims && this.shim !== false){
28933 this.shim = this.el.createShim();
28934 this.shim.hide = this.hideAction;
28942 if (this.buttons) {
28943 var bts= this.buttons;
28945 Roo.each(bts, function(b) {
28954 * Fires when a key is pressed
28955 * @param {Roo.BasicDialog} this
28956 * @param {Roo.EventObject} e
28961 * Fires when this dialog is moved by the user.
28962 * @param {Roo.BasicDialog} this
28963 * @param {Number} x The new page X
28964 * @param {Number} y The new page Y
28969 * Fires when this dialog is resized by the user.
28970 * @param {Roo.BasicDialog} this
28971 * @param {Number} width The new width
28972 * @param {Number} height The new height
28976 * @event beforehide
28977 * Fires before this dialog is hidden.
28978 * @param {Roo.BasicDialog} this
28980 "beforehide" : true,
28983 * Fires when this dialog is hidden.
28984 * @param {Roo.BasicDialog} this
28988 * @event beforeshow
28989 * Fires before this dialog is shown.
28990 * @param {Roo.BasicDialog} this
28992 "beforeshow" : true,
28995 * Fires when this dialog is shown.
28996 * @param {Roo.BasicDialog} this
29000 el.on("keydown", this.onKeyDown, this);
29001 el.on("mousedown", this.toFront, this);
29002 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29004 Roo.DialogManager.register(this);
29005 Roo.BasicDialog.superclass.constructor.call(this);
29008 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29009 shadowOffset: Roo.isIE ? 6 : 5,
29012 minButtonWidth: 75,
29013 defaultButton: null,
29014 buttonAlign: "right",
29019 * Sets the dialog title text
29020 * @param {String} text The title text to display
29021 * @return {Roo.BasicDialog} this
29023 setTitle : function(text){
29024 this.header.update(text);
29029 closeClick : function(){
29034 collapseClick : function(){
29035 this[this.collapsed ? "expand" : "collapse"]();
29039 * Collapses the dialog to its minimized state (only the title bar is visible).
29040 * Equivalent to the user clicking the collapse dialog button.
29042 collapse : function(){
29043 if(!this.collapsed){
29044 this.collapsed = true;
29045 this.el.addClass("x-dlg-collapsed");
29046 this.restoreHeight = this.el.getHeight();
29047 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29052 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29053 * clicking the expand dialog button.
29055 expand : function(){
29056 if(this.collapsed){
29057 this.collapsed = false;
29058 this.el.removeClass("x-dlg-collapsed");
29059 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29064 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29065 * @return {Roo.TabPanel} The tabs component
29067 initTabs : function(){
29068 var tabs = this.getTabs();
29069 while(tabs.getTab(0)){
29072 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29074 tabs.addTab(Roo.id(dom), dom.title);
29082 beforeResize : function(){
29083 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29087 onResize : function(){
29088 this.refreshSize();
29089 this.syncBodyHeight();
29090 this.adjustAssets();
29092 this.fireEvent("resize", this, this.size.width, this.size.height);
29096 onKeyDown : function(e){
29097 if(this.isVisible()){
29098 this.fireEvent("keydown", this, e);
29103 * Resizes the dialog.
29104 * @param {Number} width
29105 * @param {Number} height
29106 * @return {Roo.BasicDialog} this
29108 resizeTo : function(width, height){
29109 this.el.setSize(width, height);
29110 this.size = {width: width, height: height};
29111 this.syncBodyHeight();
29112 if(this.fixedcenter){
29115 if(this.isVisible()){
29116 this.constrainXY();
29117 this.adjustAssets();
29119 this.fireEvent("resize", this, width, height);
29125 * Resizes the dialog to fit the specified content size.
29126 * @param {Number} width
29127 * @param {Number} height
29128 * @return {Roo.BasicDialog} this
29130 setContentSize : function(w, h){
29131 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29132 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29133 //if(!this.el.isBorderBox()){
29134 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29135 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29138 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29139 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29141 this.resizeTo(w, h);
29146 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29147 * executed in response to a particular key being pressed while the dialog is active.
29148 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29149 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29150 * @param {Function} fn The function to call
29151 * @param {Object} scope (optional) The scope of the function
29152 * @return {Roo.BasicDialog} this
29154 addKeyListener : function(key, fn, scope){
29155 var keyCode, shift, ctrl, alt;
29156 if(typeof key == "object" && !(key instanceof Array)){
29157 keyCode = key["key"];
29158 shift = key["shift"];
29159 ctrl = key["ctrl"];
29164 var handler = function(dlg, e){
29165 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29166 var k = e.getKey();
29167 if(keyCode instanceof Array){
29168 for(var i = 0, len = keyCode.length; i < len; i++){
29169 if(keyCode[i] == k){
29170 fn.call(scope || window, dlg, k, e);
29176 fn.call(scope || window, dlg, k, e);
29181 this.on("keydown", handler);
29186 * Returns the TabPanel component (creates it if it doesn't exist).
29187 * Note: If you wish to simply check for the existence of tabs without creating them,
29188 * check for a null 'tabs' property.
29189 * @return {Roo.TabPanel} The tabs component
29191 getTabs : function(){
29193 this.el.addClass("x-dlg-auto-tabs");
29194 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29195 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29201 * Adds a button to the footer section of the dialog.
29202 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29203 * object or a valid Roo.DomHelper element config
29204 * @param {Function} handler The function called when the button is clicked
29205 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29206 * @return {Roo.Button} The new button
29208 addButton : function(config, handler, scope){
29209 var dh = Roo.DomHelper;
29211 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29213 if(!this.btnContainer){
29214 var tb = this.footer.createChild({
29216 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29217 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29219 this.btnContainer = tb.firstChild.firstChild.firstChild;
29224 minWidth: this.minButtonWidth,
29227 if(typeof config == "string"){
29228 bconfig.text = config;
29231 bconfig.dhconfig = config;
29233 Roo.apply(bconfig, config);
29237 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29238 bconfig.position = Math.max(0, bconfig.position);
29239 fc = this.btnContainer.childNodes[bconfig.position];
29242 var btn = new Roo.Button(
29244 this.btnContainer.insertBefore(document.createElement("td"),fc)
29245 : this.btnContainer.appendChild(document.createElement("td")),
29246 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29249 this.syncBodyHeight();
29252 * Array of all the buttons that have been added to this dialog via addButton
29257 this.buttons.push(btn);
29262 * Sets the default button to be focused when the dialog is displayed.
29263 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29264 * @return {Roo.BasicDialog} this
29266 setDefaultButton : function(btn){
29267 this.defaultButton = btn;
29272 getHeaderFooterHeight : function(safe){
29275 height += this.header.getHeight();
29278 var fm = this.footer.getMargins();
29279 height += (this.footer.getHeight()+fm.top+fm.bottom);
29281 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29282 height += this.centerBg.getPadding("tb");
29287 syncBodyHeight : function(){
29288 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
29289 var height = this.size.height - this.getHeaderFooterHeight(false);
29290 bd.setHeight(height-bd.getMargins("tb"));
29291 var hh = this.header.getHeight();
29292 var h = this.size.height-hh;
29294 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29295 bw.setHeight(h-cb.getPadding("tb"));
29296 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
29297 bd.setWidth(bw.getWidth(true));
29299 this.tabs.syncHeight();
29301 this.tabs.el.repaint();
29307 * Restores the previous state of the dialog if Roo.state is configured.
29308 * @return {Roo.BasicDialog} this
29310 restoreState : function(){
29311 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
29312 if(box && box.width){
29313 this.xy = [box.x, box.y];
29314 this.resizeTo(box.width, box.height);
29320 beforeShow : function(){
29322 if(this.fixedcenter){
29323 this.xy = this.el.getCenterXY(true);
29326 Roo.get(document.body).addClass("x-body-masked");
29327 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29330 this.constrainXY();
29334 animShow : function(){
29335 var b = Roo.get(this.animateTarget).getBox();
29336 this.proxy.setSize(b.width, b.height);
29337 this.proxy.setLocation(b.x, b.y);
29339 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
29340 true, .35, this.showEl.createDelegate(this));
29344 * Shows the dialog.
29345 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
29346 * @return {Roo.BasicDialog} this
29348 show : function(animateTarget){
29349 if (this.fireEvent("beforeshow", this) === false){
29352 if(this.syncHeightBeforeShow){
29353 this.syncBodyHeight();
29354 }else if(this.firstShow){
29355 this.firstShow = false;
29356 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
29358 this.animateTarget = animateTarget || this.animateTarget;
29359 if(!this.el.isVisible()){
29361 if(this.animateTarget && Roo.get(this.animateTarget)){
29371 showEl : function(){
29373 this.el.setXY(this.xy);
29375 this.adjustAssets(true);
29378 // IE peekaboo bug - fix found by Dave Fenwick
29382 this.fireEvent("show", this);
29386 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
29387 * dialog itself will receive focus.
29389 focus : function(){
29390 if(this.defaultButton){
29391 this.defaultButton.focus();
29393 this.focusEl.focus();
29398 constrainXY : function(){
29399 if(this.constraintoviewport !== false){
29400 if(!this.viewSize){
29401 if(this.container){
29402 var s = this.container.getSize();
29403 this.viewSize = [s.width, s.height];
29405 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
29408 var s = Roo.get(this.container||document).getScroll();
29410 var x = this.xy[0], y = this.xy[1];
29411 var w = this.size.width, h = this.size.height;
29412 var vw = this.viewSize[0], vh = this.viewSize[1];
29413 // only move it if it needs it
29415 // first validate right/bottom
29416 if(x + w > vw+s.left){
29420 if(y + h > vh+s.top){
29424 // then make sure top/left isn't negative
29436 if(this.isVisible()){
29437 this.el.setLocation(x, y);
29438 this.adjustAssets();
29445 onDrag : function(){
29446 if(!this.proxyDrag){
29447 this.xy = this.el.getXY();
29448 this.adjustAssets();
29453 adjustAssets : function(doShow){
29454 var x = this.xy[0], y = this.xy[1];
29455 var w = this.size.width, h = this.size.height;
29456 if(doShow === true){
29458 this.shadow.show(this.el);
29464 if(this.shadow && this.shadow.isVisible()){
29465 this.shadow.show(this.el);
29467 if(this.shim && this.shim.isVisible()){
29468 this.shim.setBounds(x, y, w, h);
29473 adjustViewport : function(w, h){
29475 w = Roo.lib.Dom.getViewWidth();
29476 h = Roo.lib.Dom.getViewHeight();
29479 this.viewSize = [w, h];
29480 if(this.modal && this.mask.isVisible()){
29481 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
29482 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29484 if(this.isVisible()){
29485 this.constrainXY();
29490 * Destroys this dialog and all its supporting elements (including any tabs, shim,
29491 * shadow, proxy, mask, etc.) Also removes all event listeners.
29492 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29494 destroy : function(removeEl){
29495 if(this.isVisible()){
29496 this.animateTarget = null;
29499 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
29501 this.tabs.destroy(removeEl);
29514 for(var i = 0, len = this.buttons.length; i < len; i++){
29515 this.buttons[i].destroy();
29518 this.el.removeAllListeners();
29519 if(removeEl === true){
29520 this.el.update("");
29523 Roo.DialogManager.unregister(this);
29527 startMove : function(){
29528 if(this.proxyDrag){
29531 if(this.constraintoviewport !== false){
29532 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
29537 endMove : function(){
29538 if(!this.proxyDrag){
29539 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
29541 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
29544 this.refreshSize();
29545 this.adjustAssets();
29547 this.fireEvent("move", this, this.xy[0], this.xy[1]);
29551 * Brings this dialog to the front of any other visible dialogs
29552 * @return {Roo.BasicDialog} this
29554 toFront : function(){
29555 Roo.DialogManager.bringToFront(this);
29560 * Sends this dialog to the back (under) of any other visible dialogs
29561 * @return {Roo.BasicDialog} this
29563 toBack : function(){
29564 Roo.DialogManager.sendToBack(this);
29569 * Centers this dialog in the viewport
29570 * @return {Roo.BasicDialog} this
29572 center : function(){
29573 var xy = this.el.getCenterXY(true);
29574 this.moveTo(xy[0], xy[1]);
29579 * Moves the dialog's top-left corner to the specified point
29580 * @param {Number} x
29581 * @param {Number} y
29582 * @return {Roo.BasicDialog} this
29584 moveTo : function(x, y){
29586 if(this.isVisible()){
29587 this.el.setXY(this.xy);
29588 this.adjustAssets();
29594 * Aligns the dialog to the specified element
29595 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29596 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
29597 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29598 * @return {Roo.BasicDialog} this
29600 alignTo : function(element, position, offsets){
29601 this.xy = this.el.getAlignToXY(element, position, offsets);
29602 if(this.isVisible()){
29603 this.el.setXY(this.xy);
29604 this.adjustAssets();
29610 * Anchors an element to another element and realigns it when the window is resized.
29611 * @param {String/HTMLElement/Roo.Element} element The element to align to.
29612 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
29613 * @param {Array} offsets (optional) Offset the positioning by [x, y]
29614 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
29615 * is a number, it is used as the buffer delay (defaults to 50ms).
29616 * @return {Roo.BasicDialog} this
29618 anchorTo : function(el, alignment, offsets, monitorScroll){
29619 var action = function(){
29620 this.alignTo(el, alignment, offsets);
29622 Roo.EventManager.onWindowResize(action, this);
29623 var tm = typeof monitorScroll;
29624 if(tm != 'undefined'){
29625 Roo.EventManager.on(window, 'scroll', action, this,
29626 {buffer: tm == 'number' ? monitorScroll : 50});
29633 * Returns true if the dialog is visible
29634 * @return {Boolean}
29636 isVisible : function(){
29637 return this.el.isVisible();
29641 animHide : function(callback){
29642 var b = Roo.get(this.animateTarget).getBox();
29644 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
29646 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
29647 this.hideEl.createDelegate(this, [callback]));
29651 * Hides the dialog.
29652 * @param {Function} callback (optional) Function to call when the dialog is hidden
29653 * @return {Roo.BasicDialog} this
29655 hide : function(callback){
29656 if (this.fireEvent("beforehide", this) === false){
29660 this.shadow.hide();
29665 // sometimes animateTarget seems to get set.. causing problems...
29666 // this just double checks..
29667 if(this.animateTarget && Roo.get(this.animateTarget)) {
29668 this.animHide(callback);
29671 this.hideEl(callback);
29677 hideEl : function(callback){
29681 Roo.get(document.body).removeClass("x-body-masked");
29683 this.fireEvent("hide", this);
29684 if(typeof callback == "function"){
29690 hideAction : function(){
29691 this.setLeft("-10000px");
29692 this.setTop("-10000px");
29693 this.setStyle("visibility", "hidden");
29697 refreshSize : function(){
29698 this.size = this.el.getSize();
29699 this.xy = this.el.getXY();
29700 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
29704 // z-index is managed by the DialogManager and may be overwritten at any time
29705 setZIndex : function(index){
29707 this.mask.setStyle("z-index", index);
29710 this.shim.setStyle("z-index", ++index);
29713 this.shadow.setZIndex(++index);
29715 this.el.setStyle("z-index", ++index);
29717 this.proxy.setStyle("z-index", ++index);
29720 this.resizer.proxy.setStyle("z-index", ++index);
29723 this.lastZIndex = index;
29727 * Returns the element for this dialog
29728 * @return {Roo.Element} The underlying dialog Element
29730 getEl : function(){
29736 * @class Roo.DialogManager
29737 * Provides global access to BasicDialogs that have been created and
29738 * support for z-indexing (layering) multiple open dialogs.
29740 Roo.DialogManager = function(){
29742 var accessList = [];
29746 var sortDialogs = function(d1, d2){
29747 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
29751 var orderDialogs = function(){
29752 accessList.sort(sortDialogs);
29753 var seed = Roo.DialogManager.zseed;
29754 for(var i = 0, len = accessList.length; i < len; i++){
29755 var dlg = accessList[i];
29757 dlg.setZIndex(seed + (i*10));
29764 * The starting z-index for BasicDialogs (defaults to 9000)
29765 * @type Number The z-index value
29770 register : function(dlg){
29771 list[dlg.id] = dlg;
29772 accessList.push(dlg);
29776 unregister : function(dlg){
29777 delete list[dlg.id];
29780 if(!accessList.indexOf){
29781 for( i = 0, len = accessList.length; i < len; i++){
29782 if(accessList[i] == dlg){
29783 accessList.splice(i, 1);
29788 i = accessList.indexOf(dlg);
29790 accessList.splice(i, 1);
29796 * Gets a registered dialog by id
29797 * @param {String/Object} id The id of the dialog or a dialog
29798 * @return {Roo.BasicDialog} this
29800 get : function(id){
29801 return typeof id == "object" ? id : list[id];
29805 * Brings the specified dialog to the front
29806 * @param {String/Object} dlg The id of the dialog or a dialog
29807 * @return {Roo.BasicDialog} this
29809 bringToFront : function(dlg){
29810 dlg = this.get(dlg);
29813 dlg._lastAccess = new Date().getTime();
29820 * Sends the specified dialog to the back
29821 * @param {String/Object} dlg The id of the dialog or a dialog
29822 * @return {Roo.BasicDialog} this
29824 sendToBack : function(dlg){
29825 dlg = this.get(dlg);
29826 dlg._lastAccess = -(new Date().getTime());
29832 * Hides all dialogs
29834 hideAll : function(){
29835 for(var id in list){
29836 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
29845 * @class Roo.LayoutDialog
29846 * @extends Roo.BasicDialog
29847 * Dialog which provides adjustments for working with a layout in a Dialog.
29848 * Add your necessary layout config options to the dialog's config.<br>
29849 * Example usage (including a nested layout):
29852 dialog = new Roo.LayoutDialog("download-dlg", {
29861 // layout config merges with the dialog config
29863 tabPosition: "top",
29864 alwaysShowTabs: true
29867 dialog.addKeyListener(27, dialog.hide, dialog);
29868 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
29869 dialog.addButton("Build It!", this.getDownload, this);
29871 // we can even add nested layouts
29872 var innerLayout = new Roo.BorderLayout("dl-inner", {
29882 innerLayout.beginUpdate();
29883 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
29884 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
29885 innerLayout.endUpdate(true);
29887 var layout = dialog.getLayout();
29888 layout.beginUpdate();
29889 layout.add("center", new Roo.ContentPanel("standard-panel",
29890 {title: "Download the Source", fitToFrame:true}));
29891 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
29892 {title: "Build your own roo.js"}));
29893 layout.getRegion("center").showPanel(sp);
29894 layout.endUpdate();
29898 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
29899 * @param {Object} config configuration options
29901 Roo.LayoutDialog = function(el, cfg){
29904 if (typeof(cfg) == 'undefined') {
29905 config = Roo.apply({}, el);
29906 // not sure why we use documentElement here.. - it should always be body.
29907 // IE7 borks horribly if we use documentElement.
29908 // webkit also does not like documentElement - it creates a body element...
29909 el = Roo.get( document.body || document.documentElement ).createChild();
29910 //config.autoCreate = true;
29914 config.autoTabs = false;
29915 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
29916 this.body.setStyle({overflow:"hidden", position:"relative"});
29917 this.layout = new Roo.BorderLayout(this.body.dom, config);
29918 this.layout.monitorWindowResize = false;
29919 this.el.addClass("x-dlg-auto-layout");
29920 // fix case when center region overwrites center function
29921 this.center = Roo.BasicDialog.prototype.center;
29922 this.on("show", this.layout.layout, this.layout, true);
29923 if (config.items) {
29924 var xitems = config.items;
29925 delete config.items;
29926 Roo.each(xitems, this.addxtype, this);
29931 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
29933 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
29936 endUpdate : function(){
29937 this.layout.endUpdate();
29941 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
29944 beginUpdate : function(){
29945 this.layout.beginUpdate();
29949 * Get the BorderLayout for this dialog
29950 * @return {Roo.BorderLayout}
29952 getLayout : function(){
29953 return this.layout;
29956 showEl : function(){
29957 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
29959 this.layout.layout();
29964 // Use the syncHeightBeforeShow config option to control this automatically
29965 syncBodyHeight : function(){
29966 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
29967 if(this.layout){this.layout.layout();}
29971 * Add an xtype element (actually adds to the layout.)
29972 * @return {Object} xdata xtype object data.
29975 addxtype : function(c) {
29976 return this.layout.addxtype(c);
29980 * Ext JS Library 1.1.1
29981 * Copyright(c) 2006-2007, Ext JS, LLC.
29983 * Originally Released Under LGPL - original licence link has changed is not relivant.
29986 * <script type="text/javascript">
29990 * @class Roo.MessageBox
29991 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
29995 Roo.Msg.alert('Status', 'Changes saved successfully.');
29997 // Prompt for user data:
29998 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30000 // process text value...
30004 // Show a dialog using config options:
30006 title:'Save Changes?',
30007 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30008 buttons: Roo.Msg.YESNOCANCEL,
30015 Roo.MessageBox = function(){
30016 var dlg, opt, mask, waitTimer;
30017 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30018 var buttons, activeTextEl, bwidth;
30021 var handleButton = function(button){
30023 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30027 var handleHide = function(){
30028 if(opt && opt.cls){
30029 dlg.el.removeClass(opt.cls);
30032 Roo.TaskMgr.stop(waitTimer);
30038 var updateButtons = function(b){
30041 buttons["ok"].hide();
30042 buttons["cancel"].hide();
30043 buttons["yes"].hide();
30044 buttons["no"].hide();
30045 dlg.footer.dom.style.display = 'none';
30048 dlg.footer.dom.style.display = '';
30049 for(var k in buttons){
30050 if(typeof buttons[k] != "function"){
30053 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30054 width += buttons[k].el.getWidth()+15;
30064 var handleEsc = function(d, k, e){
30065 if(opt && opt.closable !== false){
30075 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30076 * @return {Roo.BasicDialog} The BasicDialog element
30078 getDialog : function(){
30080 dlg = new Roo.BasicDialog("x-msg-box", {
30085 constraintoviewport:false,
30087 collapsible : false,
30090 width:400, height:100,
30091 buttonAlign:"center",
30092 closeClick : function(){
30093 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30094 handleButton("no");
30096 handleButton("cancel");
30100 dlg.on("hide", handleHide);
30102 dlg.addKeyListener(27, handleEsc);
30104 var bt = this.buttonText;
30105 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30106 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30107 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30108 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30109 bodyEl = dlg.body.createChild({
30111 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>'
30113 msgEl = bodyEl.dom.firstChild;
30114 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30115 textboxEl.enableDisplayMode();
30116 textboxEl.addKeyListener([10,13], function(){
30117 if(dlg.isVisible() && opt && opt.buttons){
30118 if(opt.buttons.ok){
30119 handleButton("ok");
30120 }else if(opt.buttons.yes){
30121 handleButton("yes");
30125 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30126 textareaEl.enableDisplayMode();
30127 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30128 progressEl.enableDisplayMode();
30129 var pf = progressEl.dom.firstChild;
30131 pp = Roo.get(pf.firstChild);
30132 pp.setHeight(pf.offsetHeight);
30140 * Updates the message box body text
30141 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30142 * the XHTML-compliant non-breaking space character '&#160;')
30143 * @return {Roo.MessageBox} This message box
30145 updateText : function(text){
30146 if(!dlg.isVisible() && !opt.width){
30147 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30149 msgEl.innerHTML = text || ' ';
30151 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30152 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30154 Math.min(opt.width || cw , this.maxWidth),
30155 Math.max(opt.minWidth || this.minWidth, bwidth)
30158 activeTextEl.setWidth(w);
30160 if(dlg.isVisible()){
30161 dlg.fixedcenter = false;
30163 // to big, make it scroll. = But as usual stupid IE does not support
30166 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30167 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30168 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30170 bodyEl.dom.style.height = '';
30171 bodyEl.dom.style.overflowY = '';
30174 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30176 bodyEl.dom.style.overflowX = '';
30179 dlg.setContentSize(w, bodyEl.getHeight());
30180 if(dlg.isVisible()){
30181 dlg.fixedcenter = true;
30187 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30188 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30189 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30190 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30191 * @return {Roo.MessageBox} This message box
30193 updateProgress : function(value, text){
30195 this.updateText(text);
30197 if (pp) { // weird bug on my firefox - for some reason this is not defined
30198 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30204 * Returns true if the message box is currently displayed
30205 * @return {Boolean} True if the message box is visible, else false
30207 isVisible : function(){
30208 return dlg && dlg.isVisible();
30212 * Hides the message box if it is displayed
30215 if(this.isVisible()){
30221 * Displays a new message box, or reinitializes an existing message box, based on the config options
30222 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30223 * The following config object properties are supported:
30225 Property Type Description
30226 ---------- --------------- ------------------------------------------------------------------------------------
30227 animEl String/Element An id or Element from which the message box should animate as it opens and
30228 closes (defaults to undefined)
30229 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30230 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30231 closable Boolean False to hide the top-right close button (defaults to true). Note that
30232 progress and wait dialogs will ignore this property and always hide the
30233 close button as they can only be closed programmatically.
30234 cls String A custom CSS class to apply to the message box element
30235 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30236 displayed (defaults to 75)
30237 fn Function A callback function to execute after closing the dialog. The arguments to the
30238 function will be btn (the name of the button that was clicked, if applicable,
30239 e.g. "ok"), and text (the value of the active text field, if applicable).
30240 Progress and wait dialogs will ignore this option since they do not respond to
30241 user actions and can only be closed programmatically, so any required function
30242 should be called by the same code after it closes the dialog.
30243 icon String A CSS class that provides a background image to be used as an icon for
30244 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30245 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30246 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30247 modal Boolean False to allow user interaction with the page while the message box is
30248 displayed (defaults to true)
30249 msg String A string that will replace the existing message box body text (defaults
30250 to the XHTML-compliant non-breaking space character ' ')
30251 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30252 progress Boolean True to display a progress bar (defaults to false)
30253 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30254 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30255 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30256 title String The title text
30257 value String The string value to set into the active textbox element if displayed
30258 wait Boolean True to display a progress bar (defaults to false)
30259 width Number The width of the dialog in pixels
30266 msg: 'Please enter your address:',
30268 buttons: Roo.MessageBox.OKCANCEL,
30271 animEl: 'addAddressBtn'
30274 * @param {Object} config Configuration options
30275 * @return {Roo.MessageBox} This message box
30277 show : function(options)
30280 // this causes nightmares if you show one dialog after another
30281 // especially on callbacks..
30283 if(this.isVisible()){
30286 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30287 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30288 Roo.log("New Dialog Message:" + options.msg )
30289 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30290 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30293 var d = this.getDialog();
30295 d.setTitle(opt.title || " ");
30296 d.close.setDisplayed(opt.closable !== false);
30297 activeTextEl = textboxEl;
30298 opt.prompt = opt.prompt || (opt.multiline ? true : false);
30303 textareaEl.setHeight(typeof opt.multiline == "number" ?
30304 opt.multiline : this.defaultTextHeight);
30305 activeTextEl = textareaEl;
30314 progressEl.setDisplayed(opt.progress === true);
30315 this.updateProgress(0);
30316 activeTextEl.dom.value = opt.value || "";
30318 dlg.setDefaultButton(activeTextEl);
30320 var bs = opt.buttons;
30323 db = buttons["ok"];
30324 }else if(bs && bs.yes){
30325 db = buttons["yes"];
30327 dlg.setDefaultButton(db);
30329 bwidth = updateButtons(opt.buttons);
30330 this.updateText(opt.msg);
30332 d.el.addClass(opt.cls);
30334 d.proxyDrag = opt.proxyDrag === true;
30335 d.modal = opt.modal !== false;
30336 d.mask = opt.modal !== false ? mask : false;
30337 if(!d.isVisible()){
30338 // force it to the end of the z-index stack so it gets a cursor in FF
30339 document.body.appendChild(dlg.el.dom);
30340 d.animateTarget = null;
30341 d.show(options.animEl);
30347 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
30348 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
30349 * and closing the message box when the process is complete.
30350 * @param {String} title The title bar text
30351 * @param {String} msg The message box body text
30352 * @return {Roo.MessageBox} This message box
30354 progress : function(title, msg){
30361 minWidth: this.minProgressWidth,
30368 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
30369 * If a callback function is passed it will be called after the user clicks the button, and the
30370 * id of the button that was clicked will be passed as the only parameter to the callback
30371 * (could also be the top-right close button).
30372 * @param {String} title The title bar text
30373 * @param {String} msg The message box body text
30374 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30375 * @param {Object} scope (optional) The scope of the callback function
30376 * @return {Roo.MessageBox} This message box
30378 alert : function(title, msg, fn, scope){
30391 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
30392 * interaction while waiting for a long-running process to complete that does not have defined intervals.
30393 * You are responsible for closing the message box when the process is complete.
30394 * @param {String} msg The message box body text
30395 * @param {String} title (optional) The title bar text
30396 * @return {Roo.MessageBox} This message box
30398 wait : function(msg, title){
30409 waitTimer = Roo.TaskMgr.start({
30411 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
30419 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
30420 * If a callback function is passed it will be called after the user clicks either button, and the id of the
30421 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
30422 * @param {String} title The title bar text
30423 * @param {String} msg The message box body text
30424 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30425 * @param {Object} scope (optional) The scope of the callback function
30426 * @return {Roo.MessageBox} This message box
30428 confirm : function(title, msg, fn, scope){
30432 buttons: this.YESNO,
30441 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
30442 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
30443 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
30444 * (could also be the top-right close button) and the text that was entered will be passed as the two
30445 * parameters to the callback.
30446 * @param {String} title The title bar text
30447 * @param {String} msg The message box body text
30448 * @param {Function} fn (optional) The callback function invoked after the message box is closed
30449 * @param {Object} scope (optional) The scope of the callback function
30450 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
30451 * property, or the height in pixels to create the textbox (defaults to false / single-line)
30452 * @return {Roo.MessageBox} This message box
30454 prompt : function(title, msg, fn, scope, multiline){
30458 buttons: this.OKCANCEL,
30463 multiline: multiline,
30470 * Button config that displays a single OK button
30475 * Button config that displays Yes and No buttons
30478 YESNO : {yes:true, no:true},
30480 * Button config that displays OK and Cancel buttons
30483 OKCANCEL : {ok:true, cancel:true},
30485 * Button config that displays Yes, No and Cancel buttons
30488 YESNOCANCEL : {yes:true, no:true, cancel:true},
30491 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
30494 defaultTextHeight : 75,
30496 * The maximum width in pixels of the message box (defaults to 600)
30501 * The minimum width in pixels of the message box (defaults to 100)
30506 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
30507 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
30510 minProgressWidth : 250,
30512 * An object containing the default button text strings that can be overriden for localized language support.
30513 * Supported properties are: ok, cancel, yes and no.
30514 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
30527 * Shorthand for {@link Roo.MessageBox}
30529 Roo.Msg = Roo.MessageBox;/*
30531 * Ext JS Library 1.1.1
30532 * Copyright(c) 2006-2007, Ext JS, LLC.
30534 * Originally Released Under LGPL - original licence link has changed is not relivant.
30537 * <script type="text/javascript">
30540 * @class Roo.QuickTips
30541 * Provides attractive and customizable tooltips for any element.
30544 Roo.QuickTips = function(){
30545 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
30546 var ce, bd, xy, dd;
30547 var visible = false, disabled = true, inited = false;
30548 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
30550 var onOver = function(e){
30554 var t = e.getTarget();
30555 if(!t || t.nodeType !== 1 || t == document || t == document.body){
30558 if(ce && t == ce.el){
30559 clearTimeout(hideProc);
30562 if(t && tagEls[t.id]){
30563 tagEls[t.id].el = t;
30564 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
30567 var ttp, et = Roo.fly(t);
30568 var ns = cfg.namespace;
30569 if(tm.interceptTitles && t.title){
30572 t.removeAttribute("title");
30573 e.preventDefault();
30575 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
30578 showProc = show.defer(tm.showDelay, tm, [{
30581 width: et.getAttributeNS(ns, cfg.width),
30582 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
30583 title: et.getAttributeNS(ns, cfg.title),
30584 cls: et.getAttributeNS(ns, cfg.cls)
30589 var onOut = function(e){
30590 clearTimeout(showProc);
30591 var t = e.getTarget();
30592 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
30593 hideProc = setTimeout(hide, tm.hideDelay);
30597 var onMove = function(e){
30603 if(tm.trackMouse && ce){
30608 var onDown = function(e){
30609 clearTimeout(showProc);
30610 clearTimeout(hideProc);
30612 if(tm.hideOnClick){
30615 tm.enable.defer(100, tm);
30620 var getPad = function(){
30621 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
30624 var show = function(o){
30628 clearTimeout(dismissProc);
30630 if(removeCls){ // in case manually hidden
30631 el.removeClass(removeCls);
30635 el.addClass(ce.cls);
30636 removeCls = ce.cls;
30639 tipTitle.update(ce.title);
30642 tipTitle.update('');
30645 el.dom.style.width = tm.maxWidth+'px';
30646 //tipBody.dom.style.width = '';
30647 tipBodyText.update(o.text);
30648 var p = getPad(), w = ce.width;
30650 var td = tipBodyText.dom;
30651 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
30652 if(aw > tm.maxWidth){
30654 }else if(aw < tm.minWidth){
30660 //tipBody.setWidth(w);
30661 el.setWidth(parseInt(w, 10) + p);
30662 if(ce.autoHide === false){
30663 close.setDisplayed(true);
30668 close.setDisplayed(false);
30674 el.avoidY = xy[1]-18;
30679 el.setStyle("visibility", "visible");
30680 el.fadeIn({callback: afterShow});
30686 var afterShow = function(){
30690 if(tm.autoDismiss && ce.autoHide !== false){
30691 dismissProc = setTimeout(hide, tm.autoDismissDelay);
30696 var hide = function(noanim){
30697 clearTimeout(dismissProc);
30698 clearTimeout(hideProc);
30700 if(el.isVisible()){
30702 if(noanim !== true && tm.animate){
30703 el.fadeOut({callback: afterHide});
30710 var afterHide = function(){
30713 el.removeClass(removeCls);
30720 * @cfg {Number} minWidth
30721 * The minimum width of the quick tip (defaults to 40)
30725 * @cfg {Number} maxWidth
30726 * The maximum width of the quick tip (defaults to 300)
30730 * @cfg {Boolean} interceptTitles
30731 * True to automatically use the element's DOM title value if available (defaults to false)
30733 interceptTitles : false,
30735 * @cfg {Boolean} trackMouse
30736 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
30738 trackMouse : false,
30740 * @cfg {Boolean} hideOnClick
30741 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
30743 hideOnClick : true,
30745 * @cfg {Number} showDelay
30746 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
30750 * @cfg {Number} hideDelay
30751 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
30755 * @cfg {Boolean} autoHide
30756 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
30757 * Used in conjunction with hideDelay.
30762 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
30763 * (defaults to true). Used in conjunction with autoDismissDelay.
30765 autoDismiss : true,
30768 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
30770 autoDismissDelay : 5000,
30772 * @cfg {Boolean} animate
30773 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
30778 * @cfg {String} title
30779 * Title text to display (defaults to ''). This can be any valid HTML markup.
30783 * @cfg {String} text
30784 * Body text to display (defaults to ''). This can be any valid HTML markup.
30788 * @cfg {String} cls
30789 * A CSS class to apply to the base quick tip element (defaults to '').
30793 * @cfg {Number} width
30794 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
30795 * minWidth or maxWidth.
30800 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
30801 * or display QuickTips in a page.
30804 tm = Roo.QuickTips;
30805 cfg = tm.tagConfig;
30807 if(!Roo.isReady){ // allow calling of init() before onReady
30808 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
30811 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
30812 el.fxDefaults = {stopFx: true};
30813 // maximum custom styling
30814 //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>');
30815 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>');
30816 tipTitle = el.child('h3');
30817 tipTitle.enableDisplayMode("block");
30818 tipBody = el.child('div.x-tip-bd');
30819 tipBodyText = el.child('div.x-tip-bd-inner');
30820 //bdLeft = el.child('div.x-tip-bd-left');
30821 //bdRight = el.child('div.x-tip-bd-right');
30822 close = el.child('div.x-tip-close');
30823 close.enableDisplayMode("block");
30824 close.on("click", hide);
30825 var d = Roo.get(document);
30826 d.on("mousedown", onDown);
30827 d.on("mouseover", onOver);
30828 d.on("mouseout", onOut);
30829 d.on("mousemove", onMove);
30830 esc = d.addKeyListener(27, hide);
30833 dd = el.initDD("default", null, {
30834 onDrag : function(){
30838 dd.setHandleElId(tipTitle.id);
30847 * Configures a new quick tip instance and assigns it to a target element. The following config options
30850 Property Type Description
30851 ---------- --------------------- ------------------------------------------------------------------------
30852 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
30854 * @param {Object} config The config object
30856 register : function(config){
30857 var cs = config instanceof Array ? config : arguments;
30858 for(var i = 0, len = cs.length; i < len; i++) {
30860 var target = c.target;
30862 if(target instanceof Array){
30863 for(var j = 0, jlen = target.length; j < jlen; j++){
30864 tagEls[target[j]] = c;
30867 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
30874 * Removes this quick tip from its element and destroys it.
30875 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
30877 unregister : function(el){
30878 delete tagEls[Roo.id(el)];
30882 * Enable this quick tip.
30884 enable : function(){
30885 if(inited && disabled){
30887 if(locks.length < 1){
30894 * Disable this quick tip.
30896 disable : function(){
30898 clearTimeout(showProc);
30899 clearTimeout(hideProc);
30900 clearTimeout(dismissProc);
30908 * Returns true if the quick tip is enabled, else false.
30910 isEnabled : function(){
30917 attribute : "qtip",
30927 // backwards compat
30928 Roo.QuickTips.tips = Roo.QuickTips.register;/*
30930 * Ext JS Library 1.1.1
30931 * Copyright(c) 2006-2007, Ext JS, LLC.
30933 * Originally Released Under LGPL - original licence link has changed is not relivant.
30936 * <script type="text/javascript">
30941 * @class Roo.tree.TreePanel
30942 * @extends Roo.data.Tree
30944 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
30945 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
30946 * @cfg {Boolean} enableDD true to enable drag and drop
30947 * @cfg {Boolean} enableDrag true to enable just drag
30948 * @cfg {Boolean} enableDrop true to enable just drop
30949 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
30950 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
30951 * @cfg {String} ddGroup The DD group this TreePanel belongs to
30952 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
30953 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
30954 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
30955 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
30956 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30957 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
30958 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
30959 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
30960 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
30961 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
30962 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
30963 * @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>
30964 * @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>
30967 * @param {String/HTMLElement/Element} el The container element
30968 * @param {Object} config
30970 Roo.tree.TreePanel = function(el, config){
30972 var loader = false;
30974 root = config.root;
30975 delete config.root;
30977 if (config.loader) {
30978 loader = config.loader;
30979 delete config.loader;
30982 Roo.apply(this, config);
30983 Roo.tree.TreePanel.superclass.constructor.call(this);
30984 this.el = Roo.get(el);
30985 this.el.addClass('x-tree');
30986 //console.log(root);
30988 this.setRootNode( Roo.factory(root, Roo.tree));
30991 this.loader = Roo.factory(loader, Roo.tree);
30994 * Read-only. The id of the container element becomes this TreePanel's id.
30996 this.id = this.el.id;
30999 * @event beforeload
31000 * Fires before a node is loaded, return false to cancel
31001 * @param {Node} node The node being loaded
31003 "beforeload" : true,
31006 * Fires when a node is loaded
31007 * @param {Node} node The node that was loaded
31011 * @event textchange
31012 * Fires when the text for a node is changed
31013 * @param {Node} node The node
31014 * @param {String} text The new text
31015 * @param {String} oldText The old text
31017 "textchange" : true,
31019 * @event beforeexpand
31020 * Fires before a node is expanded, return false to cancel.
31021 * @param {Node} node The node
31022 * @param {Boolean} deep
31023 * @param {Boolean} anim
31025 "beforeexpand" : true,
31027 * @event beforecollapse
31028 * Fires before a node is collapsed, return false to cancel.
31029 * @param {Node} node The node
31030 * @param {Boolean} deep
31031 * @param {Boolean} anim
31033 "beforecollapse" : true,
31036 * Fires when a node is expanded
31037 * @param {Node} node The node
31041 * @event disabledchange
31042 * Fires when the disabled status of a node changes
31043 * @param {Node} node The node
31044 * @param {Boolean} disabled
31046 "disabledchange" : true,
31049 * Fires when a node is collapsed
31050 * @param {Node} node The node
31054 * @event beforeclick
31055 * Fires before click processing on a node. Return false to cancel the default action.
31056 * @param {Node} node The node
31057 * @param {Roo.EventObject} e The event object
31059 "beforeclick":true,
31061 * @event checkchange
31062 * Fires when a node with a checkbox's checked property changes
31063 * @param {Node} this This node
31064 * @param {Boolean} checked
31066 "checkchange":true,
31069 * Fires when a node is clicked
31070 * @param {Node} node The node
31071 * @param {Roo.EventObject} e The event object
31076 * Fires when a node is double clicked
31077 * @param {Node} node The node
31078 * @param {Roo.EventObject} e The event object
31082 * @event contextmenu
31083 * Fires when a node is right clicked
31084 * @param {Node} node The node
31085 * @param {Roo.EventObject} e The event object
31087 "contextmenu":true,
31089 * @event beforechildrenrendered
31090 * Fires right before the child nodes for a node are rendered
31091 * @param {Node} node The node
31093 "beforechildrenrendered":true,
31096 * Fires when a node starts being dragged
31097 * @param {Roo.tree.TreePanel} this
31098 * @param {Roo.tree.TreeNode} node
31099 * @param {event} e The raw browser event
31101 "startdrag" : true,
31104 * Fires when a drag operation is complete
31105 * @param {Roo.tree.TreePanel} this
31106 * @param {Roo.tree.TreeNode} node
31107 * @param {event} e The raw browser event
31112 * Fires when a dragged node is dropped on a valid DD target
31113 * @param {Roo.tree.TreePanel} this
31114 * @param {Roo.tree.TreeNode} node
31115 * @param {DD} dd The dd it was dropped on
31116 * @param {event} e The raw browser event
31120 * @event beforenodedrop
31121 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31122 * passed to handlers has the following properties:<br />
31123 * <ul style="padding:5px;padding-left:16px;">
31124 * <li>tree - The TreePanel</li>
31125 * <li>target - The node being targeted for the drop</li>
31126 * <li>data - The drag data from the drag source</li>
31127 * <li>point - The point of the drop - append, above or below</li>
31128 * <li>source - The drag source</li>
31129 * <li>rawEvent - Raw mouse event</li>
31130 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31131 * to be inserted by setting them on this object.</li>
31132 * <li>cancel - Set this to true to cancel the drop.</li>
31134 * @param {Object} dropEvent
31136 "beforenodedrop" : true,
31139 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31140 * passed to handlers has the following properties:<br />
31141 * <ul style="padding:5px;padding-left:16px;">
31142 * <li>tree - The TreePanel</li>
31143 * <li>target - The node being targeted for the drop</li>
31144 * <li>data - The drag data from the drag source</li>
31145 * <li>point - The point of the drop - append, above or below</li>
31146 * <li>source - The drag source</li>
31147 * <li>rawEvent - Raw mouse event</li>
31148 * <li>dropNode - Dropped node(s).</li>
31150 * @param {Object} dropEvent
31154 * @event nodedragover
31155 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31156 * passed to handlers has the following properties:<br />
31157 * <ul style="padding:5px;padding-left:16px;">
31158 * <li>tree - The TreePanel</li>
31159 * <li>target - The node being targeted for the drop</li>
31160 * <li>data - The drag data from the drag source</li>
31161 * <li>point - The point of the drop - append, above or below</li>
31162 * <li>source - The drag source</li>
31163 * <li>rawEvent - Raw mouse event</li>
31164 * <li>dropNode - Drop node(s) provided by the source.</li>
31165 * <li>cancel - Set this to true to signal drop not allowed.</li>
31167 * @param {Object} dragOverEvent
31169 "nodedragover" : true
31172 if(this.singleExpand){
31173 this.on("beforeexpand", this.restrictExpand, this);
31176 this.editor.tree = this;
31177 this.editor = Roo.factory(this.editor, Roo.tree);
31180 if (this.selModel) {
31181 this.selModel = Roo.factory(this.selModel, Roo.tree);
31185 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31186 rootVisible : true,
31187 animate: Roo.enableFx,
31190 hlDrop : Roo.enableFx,
31194 rendererTip: false,
31196 restrictExpand : function(node){
31197 var p = node.parentNode;
31199 if(p.expandedChild && p.expandedChild.parentNode == p){
31200 p.expandedChild.collapse();
31202 p.expandedChild = node;
31206 // private override
31207 setRootNode : function(node){
31208 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31209 if(!this.rootVisible){
31210 node.ui = new Roo.tree.RootTreeNodeUI(node);
31216 * Returns the container element for this TreePanel
31218 getEl : function(){
31223 * Returns the default TreeLoader for this TreePanel
31225 getLoader : function(){
31226 return this.loader;
31232 expandAll : function(){
31233 this.root.expand(true);
31237 * Collapse all nodes
31239 collapseAll : function(){
31240 this.root.collapse(true);
31244 * Returns the selection model used by this TreePanel
31246 getSelectionModel : function(){
31247 if(!this.selModel){
31248 this.selModel = new Roo.tree.DefaultSelectionModel();
31250 return this.selModel;
31254 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31255 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31256 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31259 getChecked : function(a, startNode){
31260 startNode = startNode || this.root;
31262 var f = function(){
31263 if(this.attributes.checked){
31264 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31267 startNode.cascade(f);
31272 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31273 * @param {String} path
31274 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31275 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31276 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31278 expandPath : function(path, attr, callback){
31279 attr = attr || "id";
31280 var keys = path.split(this.pathSeparator);
31281 var curNode = this.root;
31282 if(curNode.attributes[attr] != keys[1]){ // invalid root
31284 callback(false, null);
31289 var f = function(){
31290 if(++index == keys.length){
31292 callback(true, curNode);
31296 var c = curNode.findChild(attr, keys[index]);
31299 callback(false, curNode);
31304 c.expand(false, false, f);
31306 curNode.expand(false, false, f);
31310 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31311 * @param {String} path
31312 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31313 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
31314 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
31316 selectPath : function(path, attr, callback){
31317 attr = attr || "id";
31318 var keys = path.split(this.pathSeparator);
31319 var v = keys.pop();
31320 if(keys.length > 0){
31321 var f = function(success, node){
31322 if(success && node){
31323 var n = node.findChild(attr, v);
31329 }else if(callback){
31330 callback(false, n);
31334 callback(false, n);
31338 this.expandPath(keys.join(this.pathSeparator), attr, f);
31340 this.root.select();
31342 callback(true, this.root);
31347 getTreeEl : function(){
31352 * Trigger rendering of this TreePanel
31354 render : function(){
31355 if (this.innerCt) {
31356 return this; // stop it rendering more than once!!
31359 this.innerCt = this.el.createChild({tag:"ul",
31360 cls:"x-tree-root-ct " +
31361 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
31363 if(this.containerScroll){
31364 Roo.dd.ScrollManager.register(this.el);
31366 if((this.enableDD || this.enableDrop) && !this.dropZone){
31368 * The dropZone used by this tree if drop is enabled
31369 * @type Roo.tree.TreeDropZone
31371 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
31372 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
31375 if((this.enableDD || this.enableDrag) && !this.dragZone){
31377 * The dragZone used by this tree if drag is enabled
31378 * @type Roo.tree.TreeDragZone
31380 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
31381 ddGroup: this.ddGroup || "TreeDD",
31382 scroll: this.ddScroll
31385 this.getSelectionModel().init(this);
31387 console.log("ROOT not set in tree");
31390 this.root.render();
31391 if(!this.rootVisible){
31392 this.root.renderChildren();
31398 * Ext JS Library 1.1.1
31399 * Copyright(c) 2006-2007, Ext JS, LLC.
31401 * Originally Released Under LGPL - original licence link has changed is not relivant.
31404 * <script type="text/javascript">
31409 * @class Roo.tree.DefaultSelectionModel
31410 * @extends Roo.util.Observable
31411 * The default single selection for a TreePanel.
31412 * @param {Object} cfg Configuration
31414 Roo.tree.DefaultSelectionModel = function(cfg){
31415 this.selNode = null;
31421 * @event selectionchange
31422 * Fires when the selected node changes
31423 * @param {DefaultSelectionModel} this
31424 * @param {TreeNode} node the new selection
31426 "selectionchange" : true,
31429 * @event beforeselect
31430 * Fires before the selected node changes, return false to cancel the change
31431 * @param {DefaultSelectionModel} this
31432 * @param {TreeNode} node the new selection
31433 * @param {TreeNode} node the old selection
31435 "beforeselect" : true
31438 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
31441 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
31442 init : function(tree){
31444 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31445 tree.on("click", this.onNodeClick, this);
31448 onNodeClick : function(node, e){
31449 if (e.ctrlKey && this.selNode == node) {
31450 this.unselect(node);
31458 * @param {TreeNode} node The node to select
31459 * @return {TreeNode} The selected node
31461 select : function(node){
31462 var last = this.selNode;
31463 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
31465 last.ui.onSelectedChange(false);
31467 this.selNode = node;
31468 node.ui.onSelectedChange(true);
31469 this.fireEvent("selectionchange", this, node, last);
31476 * @param {TreeNode} node The node to unselect
31478 unselect : function(node){
31479 if(this.selNode == node){
31480 this.clearSelections();
31485 * Clear all selections
31487 clearSelections : function(){
31488 var n = this.selNode;
31490 n.ui.onSelectedChange(false);
31491 this.selNode = null;
31492 this.fireEvent("selectionchange", this, null);
31498 * Get the selected node
31499 * @return {TreeNode} The selected node
31501 getSelectedNode : function(){
31502 return this.selNode;
31506 * Returns true if the node is selected
31507 * @param {TreeNode} node The node to check
31508 * @return {Boolean}
31510 isSelected : function(node){
31511 return this.selNode == node;
31515 * Selects the node above the selected node in the tree, intelligently walking the nodes
31516 * @return TreeNode The new selection
31518 selectPrevious : function(){
31519 var s = this.selNode || this.lastSelNode;
31523 var ps = s.previousSibling;
31525 if(!ps.isExpanded() || ps.childNodes.length < 1){
31526 return this.select(ps);
31528 var lc = ps.lastChild;
31529 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
31532 return this.select(lc);
31534 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
31535 return this.select(s.parentNode);
31541 * Selects the node above the selected node in the tree, intelligently walking the nodes
31542 * @return TreeNode The new selection
31544 selectNext : function(){
31545 var s = this.selNode || this.lastSelNode;
31549 if(s.firstChild && s.isExpanded()){
31550 return this.select(s.firstChild);
31551 }else if(s.nextSibling){
31552 return this.select(s.nextSibling);
31553 }else if(s.parentNode){
31555 s.parentNode.bubble(function(){
31556 if(this.nextSibling){
31557 newS = this.getOwnerTree().selModel.select(this.nextSibling);
31566 onKeyDown : function(e){
31567 var s = this.selNode || this.lastSelNode;
31568 // undesirable, but required
31573 var k = e.getKey();
31581 this.selectPrevious();
31584 e.preventDefault();
31585 if(s.hasChildNodes()){
31586 if(!s.isExpanded()){
31588 }else if(s.firstChild){
31589 this.select(s.firstChild, e);
31594 e.preventDefault();
31595 if(s.hasChildNodes() && s.isExpanded()){
31597 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
31598 this.select(s.parentNode, e);
31606 * @class Roo.tree.MultiSelectionModel
31607 * @extends Roo.util.Observable
31608 * Multi selection for a TreePanel.
31609 * @param {Object} cfg Configuration
31611 Roo.tree.MultiSelectionModel = function(){
31612 this.selNodes = [];
31616 * @event selectionchange
31617 * Fires when the selected nodes change
31618 * @param {MultiSelectionModel} this
31619 * @param {Array} nodes Array of the selected nodes
31621 "selectionchange" : true
31623 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
31627 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
31628 init : function(tree){
31630 tree.getTreeEl().on("keydown", this.onKeyDown, this);
31631 tree.on("click", this.onNodeClick, this);
31634 onNodeClick : function(node, e){
31635 this.select(node, e, e.ctrlKey);
31640 * @param {TreeNode} node The node to select
31641 * @param {EventObject} e (optional) An event associated with the selection
31642 * @param {Boolean} keepExisting True to retain existing selections
31643 * @return {TreeNode} The selected node
31645 select : function(node, e, keepExisting){
31646 if(keepExisting !== true){
31647 this.clearSelections(true);
31649 if(this.isSelected(node)){
31650 this.lastSelNode = node;
31653 this.selNodes.push(node);
31654 this.selMap[node.id] = node;
31655 this.lastSelNode = node;
31656 node.ui.onSelectedChange(true);
31657 this.fireEvent("selectionchange", this, this.selNodes);
31663 * @param {TreeNode} node The node to unselect
31665 unselect : function(node){
31666 if(this.selMap[node.id]){
31667 node.ui.onSelectedChange(false);
31668 var sn = this.selNodes;
31671 index = sn.indexOf(node);
31673 for(var i = 0, len = sn.length; i < len; i++){
31681 this.selNodes.splice(index, 1);
31683 delete this.selMap[node.id];
31684 this.fireEvent("selectionchange", this, this.selNodes);
31689 * Clear all selections
31691 clearSelections : function(suppressEvent){
31692 var sn = this.selNodes;
31694 for(var i = 0, len = sn.length; i < len; i++){
31695 sn[i].ui.onSelectedChange(false);
31697 this.selNodes = [];
31699 if(suppressEvent !== true){
31700 this.fireEvent("selectionchange", this, this.selNodes);
31706 * Returns true if the node is selected
31707 * @param {TreeNode} node The node to check
31708 * @return {Boolean}
31710 isSelected : function(node){
31711 return this.selMap[node.id] ? true : false;
31715 * Returns an array of the selected nodes
31718 getSelectedNodes : function(){
31719 return this.selNodes;
31722 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
31724 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
31726 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
31729 * Ext JS Library 1.1.1
31730 * Copyright(c) 2006-2007, Ext JS, LLC.
31732 * Originally Released Under LGPL - original licence link has changed is not relivant.
31735 * <script type="text/javascript">
31739 * @class Roo.tree.TreeNode
31740 * @extends Roo.data.Node
31741 * @cfg {String} text The text for this node
31742 * @cfg {Boolean} expanded true to start the node expanded
31743 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
31744 * @cfg {Boolean} allowDrop false if this node cannot be drop on
31745 * @cfg {Boolean} disabled true to start the node disabled
31746 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
31747 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
31748 * @cfg {String} cls A css class to be added to the node
31749 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
31750 * @cfg {String} href URL of the link used for the node (defaults to #)
31751 * @cfg {String} hrefTarget target frame for the link
31752 * @cfg {String} qtip An Ext QuickTip for the node
31753 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
31754 * @cfg {Boolean} singleClickExpand True for single click expand on this node
31755 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
31756 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
31757 * (defaults to undefined with no checkbox rendered)
31759 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
31761 Roo.tree.TreeNode = function(attributes){
31762 attributes = attributes || {};
31763 if(typeof attributes == "string"){
31764 attributes = {text: attributes};
31766 this.childrenRendered = false;
31767 this.rendered = false;
31768 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
31769 this.expanded = attributes.expanded === true;
31770 this.isTarget = attributes.isTarget !== false;
31771 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
31772 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
31775 * Read-only. The text for this node. To change it use setText().
31778 this.text = attributes.text;
31780 * True if this node is disabled.
31783 this.disabled = attributes.disabled === true;
31787 * @event textchange
31788 * Fires when the text for this node is changed
31789 * @param {Node} this This node
31790 * @param {String} text The new text
31791 * @param {String} oldText The old text
31793 "textchange" : true,
31795 * @event beforeexpand
31796 * Fires before this node is expanded, return false to cancel.
31797 * @param {Node} this This node
31798 * @param {Boolean} deep
31799 * @param {Boolean} anim
31801 "beforeexpand" : true,
31803 * @event beforecollapse
31804 * Fires before this node is collapsed, return false to cancel.
31805 * @param {Node} this This node
31806 * @param {Boolean} deep
31807 * @param {Boolean} anim
31809 "beforecollapse" : true,
31812 * Fires when this node is expanded
31813 * @param {Node} this This node
31817 * @event disabledchange
31818 * Fires when the disabled status of this node changes
31819 * @param {Node} this This node
31820 * @param {Boolean} disabled
31822 "disabledchange" : true,
31825 * Fires when this node is collapsed
31826 * @param {Node} this This node
31830 * @event beforeclick
31831 * Fires before click processing. Return false to cancel the default action.
31832 * @param {Node} this This node
31833 * @param {Roo.EventObject} e The event object
31835 "beforeclick":true,
31837 * @event checkchange
31838 * Fires when a node with a checkbox's checked property changes
31839 * @param {Node} this This node
31840 * @param {Boolean} checked
31842 "checkchange":true,
31845 * Fires when this node is clicked
31846 * @param {Node} this This node
31847 * @param {Roo.EventObject} e The event object
31852 * Fires when this node is double clicked
31853 * @param {Node} this This node
31854 * @param {Roo.EventObject} e The event object
31858 * @event contextmenu
31859 * Fires when this node is right clicked
31860 * @param {Node} this This node
31861 * @param {Roo.EventObject} e The event object
31863 "contextmenu":true,
31865 * @event beforechildrenrendered
31866 * Fires right before the child nodes for this node are rendered
31867 * @param {Node} this This node
31869 "beforechildrenrendered":true
31872 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
31875 * Read-only. The UI for this node
31878 this.ui = new uiClass(this);
31880 // finally support items[]
31881 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
31886 Roo.each(this.attributes.items, function(c) {
31887 this.appendChild(Roo.factory(c,Roo.Tree));
31889 delete this.attributes.items;
31894 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
31895 preventHScroll: true,
31897 * Returns true if this node is expanded
31898 * @return {Boolean}
31900 isExpanded : function(){
31901 return this.expanded;
31905 * Returns the UI object for this node
31906 * @return {TreeNodeUI}
31908 getUI : function(){
31912 // private override
31913 setFirstChild : function(node){
31914 var of = this.firstChild;
31915 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
31916 if(this.childrenRendered && of && node != of){
31917 of.renderIndent(true, true);
31920 this.renderIndent(true, true);
31924 // private override
31925 setLastChild : function(node){
31926 var ol = this.lastChild;
31927 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
31928 if(this.childrenRendered && ol && node != ol){
31929 ol.renderIndent(true, true);
31932 this.renderIndent(true, true);
31936 // these methods are overridden to provide lazy rendering support
31937 // private override
31938 appendChild : function()
31940 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
31941 if(node && this.childrenRendered){
31944 this.ui.updateExpandIcon();
31948 // private override
31949 removeChild : function(node){
31950 this.ownerTree.getSelectionModel().unselect(node);
31951 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
31952 // if it's been rendered remove dom node
31953 if(this.childrenRendered){
31956 if(this.childNodes.length < 1){
31957 this.collapse(false, false);
31959 this.ui.updateExpandIcon();
31961 if(!this.firstChild) {
31962 this.childrenRendered = false;
31967 // private override
31968 insertBefore : function(node, refNode){
31969 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
31970 if(newNode && refNode && this.childrenRendered){
31973 this.ui.updateExpandIcon();
31978 * Sets the text for this node
31979 * @param {String} text
31981 setText : function(text){
31982 var oldText = this.text;
31984 this.attributes.text = text;
31985 if(this.rendered){ // event without subscribing
31986 this.ui.onTextChange(this, text, oldText);
31988 this.fireEvent("textchange", this, text, oldText);
31992 * Triggers selection of this node
31994 select : function(){
31995 this.getOwnerTree().getSelectionModel().select(this);
31999 * Triggers deselection of this node
32001 unselect : function(){
32002 this.getOwnerTree().getSelectionModel().unselect(this);
32006 * Returns true if this node is selected
32007 * @return {Boolean}
32009 isSelected : function(){
32010 return this.getOwnerTree().getSelectionModel().isSelected(this);
32014 * Expand this node.
32015 * @param {Boolean} deep (optional) True to expand all children as well
32016 * @param {Boolean} anim (optional) false to cancel the default animation
32017 * @param {Function} callback (optional) A callback to be called when
32018 * expanding this node completes (does not wait for deep expand to complete).
32019 * Called with 1 parameter, this node.
32021 expand : function(deep, anim, callback){
32022 if(!this.expanded){
32023 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32026 if(!this.childrenRendered){
32027 this.renderChildren();
32029 this.expanded = true;
32030 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32031 this.ui.animExpand(function(){
32032 this.fireEvent("expand", this);
32033 if(typeof callback == "function"){
32037 this.expandChildNodes(true);
32039 }.createDelegate(this));
32043 this.fireEvent("expand", this);
32044 if(typeof callback == "function"){
32049 if(typeof callback == "function"){
32054 this.expandChildNodes(true);
32058 isHiddenRoot : function(){
32059 return this.isRoot && !this.getOwnerTree().rootVisible;
32063 * Collapse this node.
32064 * @param {Boolean} deep (optional) True to collapse all children as well
32065 * @param {Boolean} anim (optional) false to cancel the default animation
32067 collapse : function(deep, anim){
32068 if(this.expanded && !this.isHiddenRoot()){
32069 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32072 this.expanded = false;
32073 if((this.getOwnerTree().animate && anim !== false) || anim){
32074 this.ui.animCollapse(function(){
32075 this.fireEvent("collapse", this);
32077 this.collapseChildNodes(true);
32079 }.createDelegate(this));
32082 this.ui.collapse();
32083 this.fireEvent("collapse", this);
32087 var cs = this.childNodes;
32088 for(var i = 0, len = cs.length; i < len; i++) {
32089 cs[i].collapse(true, false);
32095 delayedExpand : function(delay){
32096 if(!this.expandProcId){
32097 this.expandProcId = this.expand.defer(delay, this);
32102 cancelExpand : function(){
32103 if(this.expandProcId){
32104 clearTimeout(this.expandProcId);
32106 this.expandProcId = false;
32110 * Toggles expanded/collapsed state of the node
32112 toggle : function(){
32121 * Ensures all parent nodes are expanded
32123 ensureVisible : function(callback){
32124 var tree = this.getOwnerTree();
32125 tree.expandPath(this.parentNode.getPath(), false, function(){
32126 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32127 Roo.callback(callback);
32128 }.createDelegate(this));
32132 * Expand all child nodes
32133 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32135 expandChildNodes : function(deep){
32136 var cs = this.childNodes;
32137 for(var i = 0, len = cs.length; i < len; i++) {
32138 cs[i].expand(deep);
32143 * Collapse all child nodes
32144 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32146 collapseChildNodes : function(deep){
32147 var cs = this.childNodes;
32148 for(var i = 0, len = cs.length; i < len; i++) {
32149 cs[i].collapse(deep);
32154 * Disables this node
32156 disable : function(){
32157 this.disabled = true;
32159 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32160 this.ui.onDisableChange(this, true);
32162 this.fireEvent("disabledchange", this, true);
32166 * Enables this node
32168 enable : function(){
32169 this.disabled = false;
32170 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32171 this.ui.onDisableChange(this, false);
32173 this.fireEvent("disabledchange", this, false);
32177 renderChildren : function(suppressEvent){
32178 if(suppressEvent !== false){
32179 this.fireEvent("beforechildrenrendered", this);
32181 var cs = this.childNodes;
32182 for(var i = 0, len = cs.length; i < len; i++){
32183 cs[i].render(true);
32185 this.childrenRendered = true;
32189 sort : function(fn, scope){
32190 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32191 if(this.childrenRendered){
32192 var cs = this.childNodes;
32193 for(var i = 0, len = cs.length; i < len; i++){
32194 cs[i].render(true);
32200 render : function(bulkRender){
32201 this.ui.render(bulkRender);
32202 if(!this.rendered){
32203 this.rendered = true;
32205 this.expanded = false;
32206 this.expand(false, false);
32212 renderIndent : function(deep, refresh){
32214 this.ui.childIndent = null;
32216 this.ui.renderIndent();
32217 if(deep === true && this.childrenRendered){
32218 var cs = this.childNodes;
32219 for(var i = 0, len = cs.length; i < len; i++){
32220 cs[i].renderIndent(true, refresh);
32226 * Ext JS Library 1.1.1
32227 * Copyright(c) 2006-2007, Ext JS, LLC.
32229 * Originally Released Under LGPL - original licence link has changed is not relivant.
32232 * <script type="text/javascript">
32236 * @class Roo.tree.AsyncTreeNode
32237 * @extends Roo.tree.TreeNode
32238 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32240 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32242 Roo.tree.AsyncTreeNode = function(config){
32243 this.loaded = false;
32244 this.loading = false;
32245 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32247 * @event beforeload
32248 * Fires before this node is loaded, return false to cancel
32249 * @param {Node} this This node
32251 this.addEvents({'beforeload':true, 'load': true});
32254 * Fires when this node is loaded
32255 * @param {Node} this This node
32258 * The loader used by this node (defaults to using the tree's defined loader)
32263 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32264 expand : function(deep, anim, callback){
32265 if(this.loading){ // if an async load is already running, waiting til it's done
32267 var f = function(){
32268 if(!this.loading){ // done loading
32269 clearInterval(timer);
32270 this.expand(deep, anim, callback);
32272 }.createDelegate(this);
32273 timer = setInterval(f, 200);
32277 if(this.fireEvent("beforeload", this) === false){
32280 this.loading = true;
32281 this.ui.beforeLoad(this);
32282 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32284 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32288 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32292 * Returns true if this node is currently loading
32293 * @return {Boolean}
32295 isLoading : function(){
32296 return this.loading;
32299 loadComplete : function(deep, anim, callback){
32300 this.loading = false;
32301 this.loaded = true;
32302 this.ui.afterLoad(this);
32303 this.fireEvent("load", this);
32304 this.expand(deep, anim, callback);
32308 * Returns true if this node has been loaded
32309 * @return {Boolean}
32311 isLoaded : function(){
32312 return this.loaded;
32315 hasChildNodes : function(){
32316 if(!this.isLeaf() && !this.loaded){
32319 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
32324 * Trigger a reload for this node
32325 * @param {Function} callback
32327 reload : function(callback){
32328 this.collapse(false, false);
32329 while(this.firstChild){
32330 this.removeChild(this.firstChild);
32332 this.childrenRendered = false;
32333 this.loaded = false;
32334 if(this.isHiddenRoot()){
32335 this.expanded = false;
32337 this.expand(false, false, callback);
32341 * Ext JS Library 1.1.1
32342 * Copyright(c) 2006-2007, Ext JS, LLC.
32344 * Originally Released Under LGPL - original licence link has changed is not relivant.
32347 * <script type="text/javascript">
32351 * @class Roo.tree.TreeNodeUI
32353 * @param {Object} node The node to render
32354 * The TreeNode UI implementation is separate from the
32355 * tree implementation. Unless you are customizing the tree UI,
32356 * you should never have to use this directly.
32358 Roo.tree.TreeNodeUI = function(node){
32360 this.rendered = false;
32361 this.animating = false;
32362 this.emptyIcon = Roo.BLANK_IMAGE_URL;
32365 Roo.tree.TreeNodeUI.prototype = {
32366 removeChild : function(node){
32368 this.ctNode.removeChild(node.ui.getEl());
32372 beforeLoad : function(){
32373 this.addClass("x-tree-node-loading");
32376 afterLoad : function(){
32377 this.removeClass("x-tree-node-loading");
32380 onTextChange : function(node, text, oldText){
32382 this.textNode.innerHTML = text;
32386 onDisableChange : function(node, state){
32387 this.disabled = state;
32389 this.addClass("x-tree-node-disabled");
32391 this.removeClass("x-tree-node-disabled");
32395 onSelectedChange : function(state){
32398 this.addClass("x-tree-selected");
32401 this.removeClass("x-tree-selected");
32405 onMove : function(tree, node, oldParent, newParent, index, refNode){
32406 this.childIndent = null;
32408 var targetNode = newParent.ui.getContainer();
32409 if(!targetNode){//target not rendered
32410 this.holder = document.createElement("div");
32411 this.holder.appendChild(this.wrap);
32414 var insertBefore = refNode ? refNode.ui.getEl() : null;
32416 targetNode.insertBefore(this.wrap, insertBefore);
32418 targetNode.appendChild(this.wrap);
32420 this.node.renderIndent(true);
32424 addClass : function(cls){
32426 Roo.fly(this.elNode).addClass(cls);
32430 removeClass : function(cls){
32432 Roo.fly(this.elNode).removeClass(cls);
32436 remove : function(){
32438 this.holder = document.createElement("div");
32439 this.holder.appendChild(this.wrap);
32443 fireEvent : function(){
32444 return this.node.fireEvent.apply(this.node, arguments);
32447 initEvents : function(){
32448 this.node.on("move", this.onMove, this);
32449 var E = Roo.EventManager;
32450 var a = this.anchor;
32452 var el = Roo.fly(a, '_treeui');
32454 if(Roo.isOpera){ // opera render bug ignores the CSS
32455 el.setStyle("text-decoration", "none");
32458 el.on("click", this.onClick, this);
32459 el.on("dblclick", this.onDblClick, this);
32462 Roo.EventManager.on(this.checkbox,
32463 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
32466 el.on("contextmenu", this.onContextMenu, this);
32468 var icon = Roo.fly(this.iconNode);
32469 icon.on("click", this.onClick, this);
32470 icon.on("dblclick", this.onDblClick, this);
32471 icon.on("contextmenu", this.onContextMenu, this);
32472 E.on(this.ecNode, "click", this.ecClick, this, true);
32474 if(this.node.disabled){
32475 this.addClass("x-tree-node-disabled");
32477 if(this.node.hidden){
32478 this.addClass("x-tree-node-disabled");
32480 var ot = this.node.getOwnerTree();
32481 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
32482 if(dd && (!this.node.isRoot || ot.rootVisible)){
32483 Roo.dd.Registry.register(this.elNode, {
32485 handles: this.getDDHandles(),
32491 getDDHandles : function(){
32492 return [this.iconNode, this.textNode];
32497 this.wrap.style.display = "none";
32503 this.wrap.style.display = "";
32507 onContextMenu : function(e){
32508 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
32509 e.preventDefault();
32511 this.fireEvent("contextmenu", this.node, e);
32515 onClick : function(e){
32520 if(this.fireEvent("beforeclick", this.node, e) !== false){
32521 if(!this.disabled && this.node.attributes.href){
32522 this.fireEvent("click", this.node, e);
32525 e.preventDefault();
32530 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
32531 this.node.toggle();
32534 this.fireEvent("click", this.node, e);
32540 onDblClick : function(e){
32541 e.preventDefault();
32546 this.toggleCheck();
32548 if(!this.animating && this.node.hasChildNodes()){
32549 this.node.toggle();
32551 this.fireEvent("dblclick", this.node, e);
32554 onCheckChange : function(){
32555 var checked = this.checkbox.checked;
32556 this.node.attributes.checked = checked;
32557 this.fireEvent('checkchange', this.node, checked);
32560 ecClick : function(e){
32561 if(!this.animating && this.node.hasChildNodes()){
32562 this.node.toggle();
32566 startDrop : function(){
32567 this.dropping = true;
32570 // delayed drop so the click event doesn't get fired on a drop
32571 endDrop : function(){
32572 setTimeout(function(){
32573 this.dropping = false;
32574 }.createDelegate(this), 50);
32577 expand : function(){
32578 this.updateExpandIcon();
32579 this.ctNode.style.display = "";
32582 focus : function(){
32583 if(!this.node.preventHScroll){
32584 try{this.anchor.focus();
32586 }else if(!Roo.isIE){
32588 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
32589 var l = noscroll.scrollLeft;
32590 this.anchor.focus();
32591 noscroll.scrollLeft = l;
32596 toggleCheck : function(value){
32597 var cb = this.checkbox;
32599 cb.checked = (value === undefined ? !cb.checked : value);
32605 this.anchor.blur();
32609 animExpand : function(callback){
32610 var ct = Roo.get(this.ctNode);
32612 if(!this.node.hasChildNodes()){
32613 this.updateExpandIcon();
32614 this.ctNode.style.display = "";
32615 Roo.callback(callback);
32618 this.animating = true;
32619 this.updateExpandIcon();
32622 callback : function(){
32623 this.animating = false;
32624 Roo.callback(callback);
32627 duration: this.node.ownerTree.duration || .25
32631 highlight : function(){
32632 var tree = this.node.getOwnerTree();
32633 Roo.fly(this.wrap).highlight(
32634 tree.hlColor || "C3DAF9",
32635 {endColor: tree.hlBaseColor}
32639 collapse : function(){
32640 this.updateExpandIcon();
32641 this.ctNode.style.display = "none";
32644 animCollapse : function(callback){
32645 var ct = Roo.get(this.ctNode);
32646 ct.enableDisplayMode('block');
32649 this.animating = true;
32650 this.updateExpandIcon();
32653 callback : function(){
32654 this.animating = false;
32655 Roo.callback(callback);
32658 duration: this.node.ownerTree.duration || .25
32662 getContainer : function(){
32663 return this.ctNode;
32666 getEl : function(){
32670 appendDDGhost : function(ghostNode){
32671 ghostNode.appendChild(this.elNode.cloneNode(true));
32674 getDDRepairXY : function(){
32675 return Roo.lib.Dom.getXY(this.iconNode);
32678 onRender : function(){
32682 render : function(bulkRender){
32683 var n = this.node, a = n.attributes;
32684 var targetNode = n.parentNode ?
32685 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
32687 if(!this.rendered){
32688 this.rendered = true;
32690 this.renderElements(n, a, targetNode, bulkRender);
32693 if(this.textNode.setAttributeNS){
32694 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
32696 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
32699 this.textNode.setAttribute("ext:qtip", a.qtip);
32701 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
32704 }else if(a.qtipCfg){
32705 a.qtipCfg.target = Roo.id(this.textNode);
32706 Roo.QuickTips.register(a.qtipCfg);
32709 if(!this.node.expanded){
32710 this.updateExpandIcon();
32713 if(bulkRender === true) {
32714 targetNode.appendChild(this.wrap);
32719 renderElements : function(n, a, targetNode, bulkRender)
32721 // add some indent caching, this helps performance when rendering a large tree
32722 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
32723 var t = n.getOwnerTree();
32724 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
32725 if (typeof(n.attributes.html) != 'undefined') {
32726 txt = n.attributes.html;
32728 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
32729 var cb = typeof a.checked == 'boolean';
32730 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
32731 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
32732 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
32733 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
32734 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
32735 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
32736 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
32737 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
32738 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
32739 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
32742 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
32743 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
32744 n.nextSibling.ui.getEl(), buf.join(""));
32746 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
32749 this.elNode = this.wrap.childNodes[0];
32750 this.ctNode = this.wrap.childNodes[1];
32751 var cs = this.elNode.childNodes;
32752 this.indentNode = cs[0];
32753 this.ecNode = cs[1];
32754 this.iconNode = cs[2];
32757 this.checkbox = cs[3];
32760 this.anchor = cs[index];
32761 this.textNode = cs[index].firstChild;
32764 getAnchor : function(){
32765 return this.anchor;
32768 getTextEl : function(){
32769 return this.textNode;
32772 getIconEl : function(){
32773 return this.iconNode;
32776 isChecked : function(){
32777 return this.checkbox ? this.checkbox.checked : false;
32780 updateExpandIcon : function(){
32782 var n = this.node, c1, c2;
32783 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
32784 var hasChild = n.hasChildNodes();
32788 c1 = "x-tree-node-collapsed";
32789 c2 = "x-tree-node-expanded";
32792 c1 = "x-tree-node-expanded";
32793 c2 = "x-tree-node-collapsed";
32796 this.removeClass("x-tree-node-leaf");
32797 this.wasLeaf = false;
32799 if(this.c1 != c1 || this.c2 != c2){
32800 Roo.fly(this.elNode).replaceClass(c1, c2);
32801 this.c1 = c1; this.c2 = c2;
32804 // this changes non-leafs into leafs if they have no children.
32805 // it's not very rational behaviour..
32807 if(!this.wasLeaf && this.node.leaf){
32808 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
32811 this.wasLeaf = true;
32814 var ecc = "x-tree-ec-icon "+cls;
32815 if(this.ecc != ecc){
32816 this.ecNode.className = ecc;
32822 getChildIndent : function(){
32823 if(!this.childIndent){
32827 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
32829 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
32831 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
32836 this.childIndent = buf.join("");
32838 return this.childIndent;
32841 renderIndent : function(){
32844 var p = this.node.parentNode;
32846 indent = p.ui.getChildIndent();
32848 if(this.indentMarkup != indent){ // don't rerender if not required
32849 this.indentNode.innerHTML = indent;
32850 this.indentMarkup = indent;
32852 this.updateExpandIcon();
32857 Roo.tree.RootTreeNodeUI = function(){
32858 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
32860 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
32861 render : function(){
32862 if(!this.rendered){
32863 var targetNode = this.node.ownerTree.innerCt.dom;
32864 this.node.expanded = true;
32865 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
32866 this.wrap = this.ctNode = targetNode.firstChild;
32869 collapse : function(){
32871 expand : function(){
32875 * Ext JS Library 1.1.1
32876 * Copyright(c) 2006-2007, Ext JS, LLC.
32878 * Originally Released Under LGPL - original licence link has changed is not relivant.
32881 * <script type="text/javascript">
32884 * @class Roo.tree.TreeLoader
32885 * @extends Roo.util.Observable
32886 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
32887 * nodes from a specified URL. The response must be a javascript Array definition
32888 * who's elements are node definition objects. eg:
32893 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
32894 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
32901 * The old style respose with just an array is still supported, but not recommended.
32904 * A server request is sent, and child nodes are loaded only when a node is expanded.
32905 * The loading node's id is passed to the server under the parameter name "node" to
32906 * enable the server to produce the correct child nodes.
32908 * To pass extra parameters, an event handler may be attached to the "beforeload"
32909 * event, and the parameters specified in the TreeLoader's baseParams property:
32911 myTreeLoader.on("beforeload", function(treeLoader, node) {
32912 this.baseParams.category = node.attributes.category;
32915 * This would pass an HTTP parameter called "category" to the server containing
32916 * the value of the Node's "category" attribute.
32918 * Creates a new Treeloader.
32919 * @param {Object} config A config object containing config properties.
32921 Roo.tree.TreeLoader = function(config){
32922 this.baseParams = {};
32923 this.requestMethod = "POST";
32924 Roo.apply(this, config);
32929 * @event beforeload
32930 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
32931 * @param {Object} This TreeLoader object.
32932 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32933 * @param {Object} callback The callback function specified in the {@link #load} call.
32938 * Fires when the node has been successfuly loaded.
32939 * @param {Object} This TreeLoader object.
32940 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32941 * @param {Object} response The response object containing the data from the server.
32945 * @event loadexception
32946 * Fires if the network request failed.
32947 * @param {Object} This TreeLoader object.
32948 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
32949 * @param {Object} response The response object containing the data from the server.
32951 loadexception : true,
32954 * Fires before a node is created, enabling you to return custom Node types
32955 * @param {Object} This TreeLoader object.
32956 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
32961 Roo.tree.TreeLoader.superclass.constructor.call(this);
32964 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
32966 * @cfg {String} dataUrl The URL from which to request a Json string which
32967 * specifies an array of node definition object representing the child nodes
32971 * @cfg {Object} baseParams (optional) An object containing properties which
32972 * specify HTTP parameters to be passed to each request for child nodes.
32975 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
32976 * created by this loader. If the attributes sent by the server have an attribute in this object,
32977 * they take priority.
32980 * @cfg {Object} uiProviders (optional) An object containing properties which
32982 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
32983 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
32984 * <i>uiProvider</i> attribute of a returned child node is a string rather
32985 * than a reference to a TreeNodeUI implementation, this that string value
32986 * is used as a property name in the uiProviders object. You can define the provider named
32987 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
32992 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
32993 * child nodes before loading.
32995 clearOnLoad : true,
32998 * @cfg {String} root (optional) Default to false. Use this to read data from an object
32999 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33000 * Grid query { data : [ .....] }
33005 * @cfg {String} queryParam (optional)
33006 * Name of the query as it will be passed on the querystring (defaults to 'node')
33007 * eg. the request will be ?node=[id]
33014 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33015 * This is called automatically when a node is expanded, but may be used to reload
33016 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33017 * @param {Roo.tree.TreeNode} node
33018 * @param {Function} callback
33020 load : function(node, callback){
33021 if(this.clearOnLoad){
33022 while(node.firstChild){
33023 node.removeChild(node.firstChild);
33026 if(node.attributes.children){ // preloaded json children
33027 var cs = node.attributes.children;
33028 for(var i = 0, len = cs.length; i < len; i++){
33029 node.appendChild(this.createNode(cs[i]));
33031 if(typeof callback == "function"){
33034 }else if(this.dataUrl){
33035 this.requestData(node, callback);
33039 getParams: function(node){
33040 var buf = [], bp = this.baseParams;
33041 for(var key in bp){
33042 if(typeof bp[key] != "function"){
33043 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33046 var n = this.queryParam === false ? 'node' : this.queryParam;
33047 buf.push(n + "=", encodeURIComponent(node.id));
33048 return buf.join("");
33051 requestData : function(node, callback){
33052 if(this.fireEvent("beforeload", this, node, callback) !== false){
33053 this.transId = Roo.Ajax.request({
33054 method:this.requestMethod,
33055 url: this.dataUrl||this.url,
33056 success: this.handleResponse,
33057 failure: this.handleFailure,
33059 argument: {callback: callback, node: node},
33060 params: this.getParams(node)
33063 // if the load is cancelled, make sure we notify
33064 // the node that we are done
33065 if(typeof callback == "function"){
33071 isLoading : function(){
33072 return this.transId ? true : false;
33075 abort : function(){
33076 if(this.isLoading()){
33077 Roo.Ajax.abort(this.transId);
33082 createNode : function(attr)
33084 // apply baseAttrs, nice idea Corey!
33085 if(this.baseAttrs){
33086 Roo.applyIf(attr, this.baseAttrs);
33088 if(this.applyLoader !== false){
33089 attr.loader = this;
33091 // uiProvider = depreciated..
33093 if(typeof(attr.uiProvider) == 'string'){
33094 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33095 /** eval:var:attr */ eval(attr.uiProvider);
33097 if(typeof(this.uiProviders['default']) != 'undefined') {
33098 attr.uiProvider = this.uiProviders['default'];
33101 this.fireEvent('create', this, attr);
33103 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33105 new Roo.tree.TreeNode(attr) :
33106 new Roo.tree.AsyncTreeNode(attr));
33109 processResponse : function(response, node, callback)
33111 var json = response.responseText;
33114 var o = Roo.decode(json);
33116 if (this.root === false && typeof(o.success) != undefined) {
33117 this.root = 'data'; // the default behaviour for list like data..
33120 if (this.root !== false && !o.success) {
33121 // it's a failure condition.
33122 var a = response.argument;
33123 this.fireEvent("loadexception", this, a.node, response);
33124 Roo.log("Load failed - should have a handler really");
33130 if (this.root !== false) {
33134 for(var i = 0, len = o.length; i < len; i++){
33135 var n = this.createNode(o[i]);
33137 node.appendChild(n);
33140 if(typeof callback == "function"){
33141 callback(this, node);
33144 this.handleFailure(response);
33148 handleResponse : function(response){
33149 this.transId = false;
33150 var a = response.argument;
33151 this.processResponse(response, a.node, a.callback);
33152 this.fireEvent("load", this, a.node, response);
33155 handleFailure : function(response)
33157 // should handle failure better..
33158 this.transId = false;
33159 var a = response.argument;
33160 this.fireEvent("loadexception", this, a.node, response);
33161 if(typeof a.callback == "function"){
33162 a.callback(this, a.node);
33167 * Ext JS Library 1.1.1
33168 * Copyright(c) 2006-2007, Ext JS, LLC.
33170 * Originally Released Under LGPL - original licence link has changed is not relivant.
33173 * <script type="text/javascript">
33177 * @class Roo.tree.TreeFilter
33178 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33179 * @param {TreePanel} tree
33180 * @param {Object} config (optional)
33182 Roo.tree.TreeFilter = function(tree, config){
33184 this.filtered = {};
33185 Roo.apply(this, config);
33188 Roo.tree.TreeFilter.prototype = {
33195 * Filter the data by a specific attribute.
33196 * @param {String/RegExp} value Either string that the attribute value
33197 * should start with or a RegExp to test against the attribute
33198 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33199 * @param {TreeNode} startNode (optional) The node to start the filter at.
33201 filter : function(value, attr, startNode){
33202 attr = attr || "text";
33204 if(typeof value == "string"){
33205 var vlen = value.length;
33206 // auto clear empty filter
33207 if(vlen == 0 && this.clearBlank){
33211 value = value.toLowerCase();
33213 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33215 }else if(value.exec){ // regex?
33217 return value.test(n.attributes[attr]);
33220 throw 'Illegal filter type, must be string or regex';
33222 this.filterBy(f, null, startNode);
33226 * Filter by a function. The passed function will be called with each
33227 * node in the tree (or from the startNode). If the function returns true, the node is kept
33228 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33229 * @param {Function} fn The filter function
33230 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33232 filterBy : function(fn, scope, startNode){
33233 startNode = startNode || this.tree.root;
33234 if(this.autoClear){
33237 var af = this.filtered, rv = this.reverse;
33238 var f = function(n){
33239 if(n == startNode){
33245 var m = fn.call(scope || n, n);
33253 startNode.cascade(f);
33256 if(typeof id != "function"){
33258 if(n && n.parentNode){
33259 n.parentNode.removeChild(n);
33267 * Clears the current filter. Note: with the "remove" option
33268 * set a filter cannot be cleared.
33270 clear : function(){
33272 var af = this.filtered;
33274 if(typeof id != "function"){
33281 this.filtered = {};
33286 * Ext JS Library 1.1.1
33287 * Copyright(c) 2006-2007, Ext JS, LLC.
33289 * Originally Released Under LGPL - original licence link has changed is not relivant.
33292 * <script type="text/javascript">
33297 * @class Roo.tree.TreeSorter
33298 * Provides sorting of nodes in a TreePanel
33300 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
33301 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
33302 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
33303 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
33304 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
33305 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
33307 * @param {TreePanel} tree
33308 * @param {Object} config
33310 Roo.tree.TreeSorter = function(tree, config){
33311 Roo.apply(this, config);
33312 tree.on("beforechildrenrendered", this.doSort, this);
33313 tree.on("append", this.updateSort, this);
33314 tree.on("insert", this.updateSort, this);
33316 var dsc = this.dir && this.dir.toLowerCase() == "desc";
33317 var p = this.property || "text";
33318 var sortType = this.sortType;
33319 var fs = this.folderSort;
33320 var cs = this.caseSensitive === true;
33321 var leafAttr = this.leafAttr || 'leaf';
33323 this.sortFn = function(n1, n2){
33325 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
33328 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
33332 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
33333 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
33335 return dsc ? +1 : -1;
33337 return dsc ? -1 : +1;
33344 Roo.tree.TreeSorter.prototype = {
33345 doSort : function(node){
33346 node.sort(this.sortFn);
33349 compareNodes : function(n1, n2){
33350 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
33353 updateSort : function(tree, node){
33354 if(node.childrenRendered){
33355 this.doSort.defer(1, this, [node]);
33360 * Ext JS Library 1.1.1
33361 * Copyright(c) 2006-2007, Ext JS, LLC.
33363 * Originally Released Under LGPL - original licence link has changed is not relivant.
33366 * <script type="text/javascript">
33369 if(Roo.dd.DropZone){
33371 Roo.tree.TreeDropZone = function(tree, config){
33372 this.allowParentInsert = false;
33373 this.allowContainerDrop = false;
33374 this.appendOnly = false;
33375 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
33377 this.lastInsertClass = "x-tree-no-status";
33378 this.dragOverData = {};
33381 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
33382 ddGroup : "TreeDD",
33384 expandDelay : 1000,
33386 expandNode : function(node){
33387 if(node.hasChildNodes() && !node.isExpanded()){
33388 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
33392 queueExpand : function(node){
33393 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
33396 cancelExpand : function(){
33397 if(this.expandProcId){
33398 clearTimeout(this.expandProcId);
33399 this.expandProcId = false;
33403 isValidDropPoint : function(n, pt, dd, e, data){
33404 if(!n || !data){ return false; }
33405 var targetNode = n.node;
33406 var dropNode = data.node;
33407 // default drop rules
33408 if(!(targetNode && targetNode.isTarget && pt)){
33411 if(pt == "append" && targetNode.allowChildren === false){
33414 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
33417 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
33420 // reuse the object
33421 var overEvent = this.dragOverData;
33422 overEvent.tree = this.tree;
33423 overEvent.target = targetNode;
33424 overEvent.data = data;
33425 overEvent.point = pt;
33426 overEvent.source = dd;
33427 overEvent.rawEvent = e;
33428 overEvent.dropNode = dropNode;
33429 overEvent.cancel = false;
33430 var result = this.tree.fireEvent("nodedragover", overEvent);
33431 return overEvent.cancel === false && result !== false;
33434 getDropPoint : function(e, n, dd){
33437 return tn.allowChildren !== false ? "append" : false; // always append for root
33439 var dragEl = n.ddel;
33440 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
33441 var y = Roo.lib.Event.getPageY(e);
33442 //var noAppend = tn.allowChildren === false || tn.isLeaf();
33444 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
33445 var noAppend = tn.allowChildren === false;
33446 if(this.appendOnly || tn.parentNode.allowChildren === false){
33447 return noAppend ? false : "append";
33449 var noBelow = false;
33450 if(!this.allowParentInsert){
33451 noBelow = tn.hasChildNodes() && tn.isExpanded();
33453 var q = (b - t) / (noAppend ? 2 : 3);
33454 if(y >= t && y < (t + q)){
33456 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
33463 onNodeEnter : function(n, dd, e, data){
33464 this.cancelExpand();
33467 onNodeOver : function(n, dd, e, data){
33468 var pt = this.getDropPoint(e, n, dd);
33471 // auto node expand check
33472 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
33473 this.queueExpand(node);
33474 }else if(pt != "append"){
33475 this.cancelExpand();
33478 // set the insert point style on the target node
33479 var returnCls = this.dropNotAllowed;
33480 if(this.isValidDropPoint(n, pt, dd, e, data)){
33485 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
33486 cls = "x-tree-drag-insert-above";
33487 }else if(pt == "below"){
33488 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
33489 cls = "x-tree-drag-insert-below";
33491 returnCls = "x-tree-drop-ok-append";
33492 cls = "x-tree-drag-append";
33494 if(this.lastInsertClass != cls){
33495 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
33496 this.lastInsertClass = cls;
33503 onNodeOut : function(n, dd, e, data){
33504 this.cancelExpand();
33505 this.removeDropIndicators(n);
33508 onNodeDrop : function(n, dd, e, data){
33509 var point = this.getDropPoint(e, n, dd);
33510 var targetNode = n.node;
33511 targetNode.ui.startDrop();
33512 if(!this.isValidDropPoint(n, point, dd, e, data)){
33513 targetNode.ui.endDrop();
33516 // first try to find the drop node
33517 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
33520 target: targetNode,
33525 dropNode: dropNode,
33528 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
33529 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
33530 targetNode.ui.endDrop();
33533 // allow target changing
33534 targetNode = dropEvent.target;
33535 if(point == "append" && !targetNode.isExpanded()){
33536 targetNode.expand(false, null, function(){
33537 this.completeDrop(dropEvent);
33538 }.createDelegate(this));
33540 this.completeDrop(dropEvent);
33545 completeDrop : function(de){
33546 var ns = de.dropNode, p = de.point, t = de.target;
33547 if(!(ns instanceof Array)){
33551 for(var i = 0, len = ns.length; i < len; i++){
33554 t.parentNode.insertBefore(n, t);
33555 }else if(p == "below"){
33556 t.parentNode.insertBefore(n, t.nextSibling);
33562 if(this.tree.hlDrop){
33566 this.tree.fireEvent("nodedrop", de);
33569 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
33570 if(this.tree.hlDrop){
33571 dropNode.ui.focus();
33572 dropNode.ui.highlight();
33574 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
33577 getTree : function(){
33581 removeDropIndicators : function(n){
33584 Roo.fly(el).removeClass([
33585 "x-tree-drag-insert-above",
33586 "x-tree-drag-insert-below",
33587 "x-tree-drag-append"]);
33588 this.lastInsertClass = "_noclass";
33592 beforeDragDrop : function(target, e, id){
33593 this.cancelExpand();
33597 afterRepair : function(data){
33598 if(data && Roo.enableFx){
33599 data.node.ui.highlight();
33608 * Ext JS Library 1.1.1
33609 * Copyright(c) 2006-2007, Ext JS, LLC.
33611 * Originally Released Under LGPL - original licence link has changed is not relivant.
33614 * <script type="text/javascript">
33618 if(Roo.dd.DragZone){
33619 Roo.tree.TreeDragZone = function(tree, config){
33620 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
33624 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
33625 ddGroup : "TreeDD",
33627 onBeforeDrag : function(data, e){
33629 return n && n.draggable && !n.disabled;
33632 onInitDrag : function(e){
33633 var data = this.dragData;
33634 this.tree.getSelectionModel().select(data.node);
33635 this.proxy.update("");
33636 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
33637 this.tree.fireEvent("startdrag", this.tree, data.node, e);
33640 getRepairXY : function(e, data){
33641 return data.node.ui.getDDRepairXY();
33644 onEndDrag : function(data, e){
33645 this.tree.fireEvent("enddrag", this.tree, data.node, e);
33648 onValidDrop : function(dd, e, id){
33649 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
33653 beforeInvalidDrop : function(e, id){
33654 // this scrolls the original position back into view
33655 var sm = this.tree.getSelectionModel();
33656 sm.clearSelections();
33657 sm.select(this.dragData.node);
33662 * Ext JS Library 1.1.1
33663 * Copyright(c) 2006-2007, Ext JS, LLC.
33665 * Originally Released Under LGPL - original licence link has changed is not relivant.
33668 * <script type="text/javascript">
33671 * @class Roo.tree.TreeEditor
33672 * @extends Roo.Editor
33673 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
33674 * as the editor field.
33676 * @param {Object} config (used to be the tree panel.)
33677 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
33679 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
33680 * @cfg {Roo.form.TextField|Object} field The field configuration
33684 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
33687 if (oldconfig) { // old style..
33688 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
33691 tree = config.tree;
33692 config.field = config.field || {};
33693 config.field.xtype = 'TextField';
33694 field = Roo.factory(config.field, Roo.form);
33696 config = config || {};
33701 * @event beforenodeedit
33702 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
33703 * false from the handler of this event.
33704 * @param {Editor} this
33705 * @param {Roo.tree.Node} node
33707 "beforenodeedit" : true
33711 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
33715 tree.on('beforeclick', this.beforeNodeClick, this);
33716 tree.getTreeEl().on('mousedown', this.hide, this);
33717 this.on('complete', this.updateNode, this);
33718 this.on('beforestartedit', this.fitToTree, this);
33719 this.on('startedit', this.bindScroll, this, {delay:10});
33720 this.on('specialkey', this.onSpecialKey, this);
33723 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
33725 * @cfg {String} alignment
33726 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
33732 * @cfg {Boolean} hideEl
33733 * True to hide the bound element while the editor is displayed (defaults to false)
33737 * @cfg {String} cls
33738 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
33740 cls: "x-small-editor x-tree-editor",
33742 * @cfg {Boolean} shim
33743 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
33749 * @cfg {Number} maxWidth
33750 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
33751 * the containing tree element's size, it will be automatically limited for you to the container width, taking
33752 * scroll and client offsets into account prior to each edit.
33759 fitToTree : function(ed, el){
33760 var td = this.tree.getTreeEl().dom, nd = el.dom;
33761 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
33762 td.scrollLeft = nd.offsetLeft;
33766 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
33767 this.setSize(w, '');
33769 return this.fireEvent('beforenodeedit', this, this.editNode);
33774 triggerEdit : function(node){
33775 this.completeEdit();
33776 this.editNode = node;
33777 this.startEdit(node.ui.textNode, node.text);
33781 bindScroll : function(){
33782 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
33786 beforeNodeClick : function(node, e){
33787 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
33788 this.lastClick = new Date();
33789 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
33791 this.triggerEdit(node);
33798 updateNode : function(ed, value){
33799 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
33800 this.editNode.setText(value);
33804 onHide : function(){
33805 Roo.tree.TreeEditor.superclass.onHide.call(this);
33807 this.editNode.ui.focus();
33812 onSpecialKey : function(field, e){
33813 var k = e.getKey();
33817 }else if(k == e.ENTER && !e.hasModifier()){
33819 this.completeEdit();
33822 });//<Script type="text/javascript">
33825 * Ext JS Library 1.1.1
33826 * Copyright(c) 2006-2007, Ext JS, LLC.
33828 * Originally Released Under LGPL - original licence link has changed is not relivant.
33831 * <script type="text/javascript">
33835 * Not documented??? - probably should be...
33838 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
33839 //focus: Roo.emptyFn, // prevent odd scrolling behavior
33841 renderElements : function(n, a, targetNode, bulkRender){
33842 //consel.log("renderElements?");
33843 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33845 var t = n.getOwnerTree();
33846 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
33848 var cols = t.columns;
33849 var bw = t.borderWidth;
33851 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33852 var cb = typeof a.checked == "boolean";
33853 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33854 var colcls = 'x-t-' + tid + '-c0';
33856 '<li class="x-tree-node">',
33859 '<div class="x-tree-node-el ', a.cls,'">',
33861 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
33864 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
33865 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
33866 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
33867 (a.icon ? ' x-tree-node-inline-icon' : ''),
33868 (a.iconCls ? ' '+a.iconCls : ''),
33869 '" unselectable="on" />',
33870 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
33871 (a.checked ? 'checked="checked" />' : ' />')) : ''),
33873 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33874 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
33875 '<span unselectable="on" qtip="' + tx + '">',
33879 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
33880 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
33882 for(var i = 1, len = cols.length; i < len; i++){
33884 colcls = 'x-t-' + tid + '-c' +i;
33885 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
33886 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
33887 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
33893 '<div class="x-clear"></div></div>',
33894 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33897 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33898 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33899 n.nextSibling.ui.getEl(), buf.join(""));
33901 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33903 var el = this.wrap.firstChild;
33905 this.elNode = el.firstChild;
33906 this.ranchor = el.childNodes[1];
33907 this.ctNode = this.wrap.childNodes[1];
33908 var cs = el.firstChild.childNodes;
33909 this.indentNode = cs[0];
33910 this.ecNode = cs[1];
33911 this.iconNode = cs[2];
33914 this.checkbox = cs[3];
33917 this.anchor = cs[index];
33919 this.textNode = cs[index].firstChild;
33921 //el.on("click", this.onClick, this);
33922 //el.on("dblclick", this.onDblClick, this);
33925 // console.log(this);
33927 initEvents : function(){
33928 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
33931 var a = this.ranchor;
33933 var el = Roo.get(a);
33935 if(Roo.isOpera){ // opera render bug ignores the CSS
33936 el.setStyle("text-decoration", "none");
33939 el.on("click", this.onClick, this);
33940 el.on("dblclick", this.onDblClick, this);
33941 el.on("contextmenu", this.onContextMenu, this);
33945 /*onSelectedChange : function(state){
33948 this.addClass("x-tree-selected");
33951 this.removeClass("x-tree-selected");
33954 addClass : function(cls){
33956 Roo.fly(this.elRow).addClass(cls);
33962 removeClass : function(cls){
33964 Roo.fly(this.elRow).removeClass(cls);
33970 });//<Script type="text/javascript">
33974 * Ext JS Library 1.1.1
33975 * Copyright(c) 2006-2007, Ext JS, LLC.
33977 * Originally Released Under LGPL - original licence link has changed is not relivant.
33980 * <script type="text/javascript">
33985 * @class Roo.tree.ColumnTree
33986 * @extends Roo.data.TreePanel
33987 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
33988 * @cfg {int} borderWidth compined right/left border allowance
33990 * @param {String/HTMLElement/Element} el The container element
33991 * @param {Object} config
33993 Roo.tree.ColumnTree = function(el, config)
33995 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
33999 * Fire this event on a container when it resizes
34000 * @param {int} w Width
34001 * @param {int} h Height
34005 this.on('resize', this.onResize, this);
34008 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34012 borderWidth: Roo.isBorderBox ? 0 : 2,
34015 render : function(){
34016 // add the header.....
34018 Roo.tree.ColumnTree.superclass.render.apply(this);
34020 this.el.addClass('x-column-tree');
34022 this.headers = this.el.createChild(
34023 {cls:'x-tree-headers'},this.innerCt.dom);
34025 var cols = this.columns, c;
34026 var totalWidth = 0;
34028 var len = cols.length;
34029 for(var i = 0; i < len; i++){
34031 totalWidth += c.width;
34032 this.headEls.push(this.headers.createChild({
34033 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34035 cls:'x-tree-hd-text',
34038 style:'width:'+(c.width-this.borderWidth)+'px;'
34041 this.headers.createChild({cls:'x-clear'});
34042 // prevent floats from wrapping when clipped
34043 this.headers.setWidth(totalWidth);
34044 //this.innerCt.setWidth(totalWidth);
34045 this.innerCt.setStyle({ overflow: 'auto' });
34046 this.onResize(this.width, this.height);
34050 onResize : function(w,h)
34055 this.innerCt.setWidth(this.width);
34056 this.innerCt.setHeight(this.height-20);
34059 var cols = this.columns, c;
34060 var totalWidth = 0;
34062 var len = cols.length;
34063 for(var i = 0; i < len; i++){
34065 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34066 // it's the expander..
34067 expEl = this.headEls[i];
34070 totalWidth += c.width;
34074 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34076 this.headers.setWidth(w-20);
34085 * Ext JS Library 1.1.1
34086 * Copyright(c) 2006-2007, Ext JS, LLC.
34088 * Originally Released Under LGPL - original licence link has changed is not relivant.
34091 * <script type="text/javascript">
34095 * @class Roo.menu.Menu
34096 * @extends Roo.util.Observable
34097 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34098 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34100 * Creates a new Menu
34101 * @param {Object} config Configuration options
34103 Roo.menu.Menu = function(config){
34104 Roo.apply(this, config);
34105 this.id = this.id || Roo.id();
34108 * @event beforeshow
34109 * Fires before this menu is displayed
34110 * @param {Roo.menu.Menu} this
34114 * @event beforehide
34115 * Fires before this menu is hidden
34116 * @param {Roo.menu.Menu} this
34121 * Fires after this menu is displayed
34122 * @param {Roo.menu.Menu} this
34127 * Fires after this menu is hidden
34128 * @param {Roo.menu.Menu} this
34133 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34134 * @param {Roo.menu.Menu} this
34135 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34136 * @param {Roo.EventObject} e
34141 * Fires when the mouse is hovering over this menu
34142 * @param {Roo.menu.Menu} this
34143 * @param {Roo.EventObject} e
34144 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34149 * Fires when the mouse exits this menu
34150 * @param {Roo.menu.Menu} this
34151 * @param {Roo.EventObject} e
34152 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34157 * Fires when a menu item contained in this menu is clicked
34158 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34159 * @param {Roo.EventObject} e
34163 if (this.registerMenu) {
34164 Roo.menu.MenuMgr.register(this);
34167 var mis = this.items;
34168 this.items = new Roo.util.MixedCollection();
34170 this.add.apply(this, mis);
34174 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34176 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34180 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34181 * for bottom-right shadow (defaults to "sides")
34185 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34186 * this menu (defaults to "tl-tr?")
34188 subMenuAlign : "tl-tr?",
34190 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34191 * relative to its element of origin (defaults to "tl-bl?")
34193 defaultAlign : "tl-bl?",
34195 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34197 allowOtherMenus : false,
34199 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34201 registerMenu : true,
34206 render : function(){
34210 var el = this.el = new Roo.Layer({
34212 shadow:this.shadow,
34214 parentEl: this.parentEl || document.body,
34218 this.keyNav = new Roo.menu.MenuNav(this);
34221 el.addClass("x-menu-plain");
34224 el.addClass(this.cls);
34226 // generic focus element
34227 this.focusEl = el.createChild({
34228 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34230 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34231 ul.on("click", this.onClick, this);
34232 ul.on("mouseover", this.onMouseOver, this);
34233 ul.on("mouseout", this.onMouseOut, this);
34234 this.items.each(function(item){
34235 var li = document.createElement("li");
34236 li.className = "x-menu-list-item";
34237 ul.dom.appendChild(li);
34238 item.render(li, this);
34245 autoWidth : function(){
34246 var el = this.el, ul = this.ul;
34250 var w = this.width;
34253 }else if(Roo.isIE){
34254 el.setWidth(this.minWidth);
34255 var t = el.dom.offsetWidth; // force recalc
34256 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34261 delayAutoWidth : function(){
34264 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34266 this.awTask.delay(20);
34271 findTargetItem : function(e){
34272 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34273 if(t && t.menuItemId){
34274 return this.items.get(t.menuItemId);
34279 onClick : function(e){
34281 if(t = this.findTargetItem(e)){
34283 this.fireEvent("click", this, t, e);
34288 setActiveItem : function(item, autoExpand){
34289 if(item != this.activeItem){
34290 if(this.activeItem){
34291 this.activeItem.deactivate();
34293 this.activeItem = item;
34294 item.activate(autoExpand);
34295 }else if(autoExpand){
34301 tryActivate : function(start, step){
34302 var items = this.items;
34303 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
34304 var item = items.get(i);
34305 if(!item.disabled && item.canActivate){
34306 this.setActiveItem(item, false);
34314 onMouseOver : function(e){
34316 if(t = this.findTargetItem(e)){
34317 if(t.canActivate && !t.disabled){
34318 this.setActiveItem(t, true);
34321 this.fireEvent("mouseover", this, e, t);
34325 onMouseOut : function(e){
34327 if(t = this.findTargetItem(e)){
34328 if(t == this.activeItem && t.shouldDeactivate(e)){
34329 this.activeItem.deactivate();
34330 delete this.activeItem;
34333 this.fireEvent("mouseout", this, e, t);
34337 * Read-only. Returns true if the menu is currently displayed, else false.
34340 isVisible : function(){
34341 return this.el && !this.hidden;
34345 * Displays this menu relative to another element
34346 * @param {String/HTMLElement/Roo.Element} element The element to align to
34347 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
34348 * the element (defaults to this.defaultAlign)
34349 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34351 show : function(el, pos, parentMenu){
34352 this.parentMenu = parentMenu;
34356 this.fireEvent("beforeshow", this);
34357 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
34361 * Displays this menu at a specific xy position
34362 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
34363 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
34365 showAt : function(xy, parentMenu, /* private: */_e){
34366 this.parentMenu = parentMenu;
34371 this.fireEvent("beforeshow", this);
34372 xy = this.el.adjustForConstraints(xy);
34376 this.hidden = false;
34378 this.fireEvent("show", this);
34381 focus : function(){
34383 this.doFocus.defer(50, this);
34387 doFocus : function(){
34389 this.focusEl.focus();
34394 * Hides this menu and optionally all parent menus
34395 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
34397 hide : function(deep){
34398 if(this.el && this.isVisible()){
34399 this.fireEvent("beforehide", this);
34400 if(this.activeItem){
34401 this.activeItem.deactivate();
34402 this.activeItem = null;
34405 this.hidden = true;
34406 this.fireEvent("hide", this);
34408 if(deep === true && this.parentMenu){
34409 this.parentMenu.hide(true);
34414 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
34415 * Any of the following are valid:
34417 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
34418 * <li>An HTMLElement object which will be converted to a menu item</li>
34419 * <li>A menu item config object that will be created as a new menu item</li>
34420 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
34421 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
34426 var menu = new Roo.menu.Menu();
34428 // Create a menu item to add by reference
34429 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
34431 // Add a bunch of items at once using different methods.
34432 // Only the last item added will be returned.
34433 var item = menu.add(
34434 menuItem, // add existing item by ref
34435 'Dynamic Item', // new TextItem
34436 '-', // new separator
34437 { text: 'Config Item' } // new item by config
34440 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
34441 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
34444 var a = arguments, l = a.length, item;
34445 for(var i = 0; i < l; i++){
34447 if ((typeof(el) == "object") && el.xtype && el.xns) {
34448 el = Roo.factory(el, Roo.menu);
34451 if(el.render){ // some kind of Item
34452 item = this.addItem(el);
34453 }else if(typeof el == "string"){ // string
34454 if(el == "separator" || el == "-"){
34455 item = this.addSeparator();
34457 item = this.addText(el);
34459 }else if(el.tagName || el.el){ // element
34460 item = this.addElement(el);
34461 }else if(typeof el == "object"){ // must be menu item config?
34462 item = this.addMenuItem(el);
34469 * Returns this menu's underlying {@link Roo.Element} object
34470 * @return {Roo.Element} The element
34472 getEl : function(){
34480 * Adds a separator bar to the menu
34481 * @return {Roo.menu.Item} The menu item that was added
34483 addSeparator : function(){
34484 return this.addItem(new Roo.menu.Separator());
34488 * Adds an {@link Roo.Element} object to the menu
34489 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
34490 * @return {Roo.menu.Item} The menu item that was added
34492 addElement : function(el){
34493 return this.addItem(new Roo.menu.BaseItem(el));
34497 * Adds an existing object based on {@link Roo.menu.Item} to the menu
34498 * @param {Roo.menu.Item} item The menu item to add
34499 * @return {Roo.menu.Item} The menu item that was added
34501 addItem : function(item){
34502 this.items.add(item);
34504 var li = document.createElement("li");
34505 li.className = "x-menu-list-item";
34506 this.ul.dom.appendChild(li);
34507 item.render(li, this);
34508 this.delayAutoWidth();
34514 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
34515 * @param {Object} config A MenuItem config object
34516 * @return {Roo.menu.Item} The menu item that was added
34518 addMenuItem : function(config){
34519 if(!(config instanceof Roo.menu.Item)){
34520 if(typeof config.checked == "boolean"){ // must be check menu item config?
34521 config = new Roo.menu.CheckItem(config);
34523 config = new Roo.menu.Item(config);
34526 return this.addItem(config);
34530 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
34531 * @param {String} text The text to display in the menu item
34532 * @return {Roo.menu.Item} The menu item that was added
34534 addText : function(text){
34535 return this.addItem(new Roo.menu.TextItem({ text : text }));
34539 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
34540 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
34541 * @param {Roo.menu.Item} item The menu item to add
34542 * @return {Roo.menu.Item} The menu item that was added
34544 insert : function(index, item){
34545 this.items.insert(index, item);
34547 var li = document.createElement("li");
34548 li.className = "x-menu-list-item";
34549 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
34550 item.render(li, this);
34551 this.delayAutoWidth();
34557 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
34558 * @param {Roo.menu.Item} item The menu item to remove
34560 remove : function(item){
34561 this.items.removeKey(item.id);
34566 * Removes and destroys all items in the menu
34568 removeAll : function(){
34570 while(f = this.items.first()){
34576 // MenuNav is a private utility class used internally by the Menu
34577 Roo.menu.MenuNav = function(menu){
34578 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
34579 this.scope = this.menu = menu;
34582 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
34583 doRelay : function(e, h){
34584 var k = e.getKey();
34585 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
34586 this.menu.tryActivate(0, 1);
34589 return h.call(this.scope || this, e, this.menu);
34592 up : function(e, m){
34593 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
34594 m.tryActivate(m.items.length-1, -1);
34598 down : function(e, m){
34599 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
34600 m.tryActivate(0, 1);
34604 right : function(e, m){
34606 m.activeItem.expandMenu(true);
34610 left : function(e, m){
34612 if(m.parentMenu && m.parentMenu.activeItem){
34613 m.parentMenu.activeItem.activate();
34617 enter : function(e, m){
34619 e.stopPropagation();
34620 m.activeItem.onClick(e);
34621 m.fireEvent("click", this, m.activeItem);
34627 * Ext JS Library 1.1.1
34628 * Copyright(c) 2006-2007, Ext JS, LLC.
34630 * Originally Released Under LGPL - original licence link has changed is not relivant.
34633 * <script type="text/javascript">
34637 * @class Roo.menu.MenuMgr
34638 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
34641 Roo.menu.MenuMgr = function(){
34642 var menus, active, groups = {}, attached = false, lastShow = new Date();
34644 // private - called when first menu is created
34647 active = new Roo.util.MixedCollection();
34648 Roo.get(document).addKeyListener(27, function(){
34649 if(active.length > 0){
34656 function hideAll(){
34657 if(active && active.length > 0){
34658 var c = active.clone();
34659 c.each(function(m){
34666 function onHide(m){
34668 if(active.length < 1){
34669 Roo.get(document).un("mousedown", onMouseDown);
34675 function onShow(m){
34676 var last = active.last();
34677 lastShow = new Date();
34680 Roo.get(document).on("mousedown", onMouseDown);
34684 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
34685 m.parentMenu.activeChild = m;
34686 }else if(last && last.isVisible()){
34687 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
34692 function onBeforeHide(m){
34694 m.activeChild.hide();
34696 if(m.autoHideTimer){
34697 clearTimeout(m.autoHideTimer);
34698 delete m.autoHideTimer;
34703 function onBeforeShow(m){
34704 var pm = m.parentMenu;
34705 if(!pm && !m.allowOtherMenus){
34707 }else if(pm && pm.activeChild && active != m){
34708 pm.activeChild.hide();
34713 function onMouseDown(e){
34714 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
34720 function onBeforeCheck(mi, state){
34722 var g = groups[mi.group];
34723 for(var i = 0, l = g.length; i < l; i++){
34725 g[i].setChecked(false);
34734 * Hides all menus that are currently visible
34736 hideAll : function(){
34741 register : function(menu){
34745 menus[menu.id] = menu;
34746 menu.on("beforehide", onBeforeHide);
34747 menu.on("hide", onHide);
34748 menu.on("beforeshow", onBeforeShow);
34749 menu.on("show", onShow);
34750 var g = menu.group;
34751 if(g && menu.events["checkchange"]){
34755 groups[g].push(menu);
34756 menu.on("checkchange", onCheck);
34761 * Returns a {@link Roo.menu.Menu} object
34762 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
34763 * be used to generate and return a new Menu instance.
34765 get : function(menu){
34766 if(typeof menu == "string"){ // menu id
34767 return menus[menu];
34768 }else if(menu.events){ // menu instance
34770 }else if(typeof menu.length == 'number'){ // array of menu items?
34771 return new Roo.menu.Menu({items:menu});
34772 }else{ // otherwise, must be a config
34773 return new Roo.menu.Menu(menu);
34778 unregister : function(menu){
34779 delete menus[menu.id];
34780 menu.un("beforehide", onBeforeHide);
34781 menu.un("hide", onHide);
34782 menu.un("beforeshow", onBeforeShow);
34783 menu.un("show", onShow);
34784 var g = menu.group;
34785 if(g && menu.events["checkchange"]){
34786 groups[g].remove(menu);
34787 menu.un("checkchange", onCheck);
34792 registerCheckable : function(menuItem){
34793 var g = menuItem.group;
34798 groups[g].push(menuItem);
34799 menuItem.on("beforecheckchange", onBeforeCheck);
34804 unregisterCheckable : function(menuItem){
34805 var g = menuItem.group;
34807 groups[g].remove(menuItem);
34808 menuItem.un("beforecheckchange", onBeforeCheck);
34814 * Ext JS Library 1.1.1
34815 * Copyright(c) 2006-2007, Ext JS, LLC.
34817 * Originally Released Under LGPL - original licence link has changed is not relivant.
34820 * <script type="text/javascript">
34825 * @class Roo.menu.BaseItem
34826 * @extends Roo.Component
34827 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
34828 * management and base configuration options shared by all menu components.
34830 * Creates a new BaseItem
34831 * @param {Object} config Configuration options
34833 Roo.menu.BaseItem = function(config){
34834 Roo.menu.BaseItem.superclass.constructor.call(this, config);
34839 * Fires when this item is clicked
34840 * @param {Roo.menu.BaseItem} this
34841 * @param {Roo.EventObject} e
34846 * Fires when this item is activated
34847 * @param {Roo.menu.BaseItem} this
34851 * @event deactivate
34852 * Fires when this item is deactivated
34853 * @param {Roo.menu.BaseItem} this
34859 this.on("click", this.handler, this.scope, true);
34863 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
34865 * @cfg {Function} handler
34866 * A function that will handle the click event of this menu item (defaults to undefined)
34869 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
34871 canActivate : false,
34873 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
34875 activeClass : "x-menu-item-active",
34877 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
34879 hideOnClick : true,
34881 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
34886 ctype: "Roo.menu.BaseItem",
34889 actionMode : "container",
34892 render : function(container, parentMenu){
34893 this.parentMenu = parentMenu;
34894 Roo.menu.BaseItem.superclass.render.call(this, container);
34895 this.container.menuItemId = this.id;
34899 onRender : function(container, position){
34900 this.el = Roo.get(this.el);
34901 container.dom.appendChild(this.el.dom);
34905 onClick : function(e){
34906 if(!this.disabled && this.fireEvent("click", this, e) !== false
34907 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
34908 this.handleClick(e);
34915 activate : function(){
34919 var li = this.container;
34920 li.addClass(this.activeClass);
34921 this.region = li.getRegion().adjust(2, 2, -2, -2);
34922 this.fireEvent("activate", this);
34927 deactivate : function(){
34928 this.container.removeClass(this.activeClass);
34929 this.fireEvent("deactivate", this);
34933 shouldDeactivate : function(e){
34934 return !this.region || !this.region.contains(e.getPoint());
34938 handleClick : function(e){
34939 if(this.hideOnClick){
34940 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
34945 expandMenu : function(autoActivate){
34950 hideMenu : function(){
34955 * Ext JS Library 1.1.1
34956 * Copyright(c) 2006-2007, Ext JS, LLC.
34958 * Originally Released Under LGPL - original licence link has changed is not relivant.
34961 * <script type="text/javascript">
34965 * @class Roo.menu.Adapter
34966 * @extends Roo.menu.BaseItem
34967 * 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.
34968 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
34970 * Creates a new Adapter
34971 * @param {Object} config Configuration options
34973 Roo.menu.Adapter = function(component, config){
34974 Roo.menu.Adapter.superclass.constructor.call(this, config);
34975 this.component = component;
34977 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
34979 canActivate : true,
34982 onRender : function(container, position){
34983 this.component.render(container);
34984 this.el = this.component.getEl();
34988 activate : function(){
34992 this.component.focus();
34993 this.fireEvent("activate", this);
34998 deactivate : function(){
34999 this.fireEvent("deactivate", this);
35003 disable : function(){
35004 this.component.disable();
35005 Roo.menu.Adapter.superclass.disable.call(this);
35009 enable : function(){
35010 this.component.enable();
35011 Roo.menu.Adapter.superclass.enable.call(this);
35015 * Ext JS Library 1.1.1
35016 * Copyright(c) 2006-2007, Ext JS, LLC.
35018 * Originally Released Under LGPL - original licence link has changed is not relivant.
35021 * <script type="text/javascript">
35025 * @class Roo.menu.TextItem
35026 * @extends Roo.menu.BaseItem
35027 * Adds a static text string to a menu, usually used as either a heading or group separator.
35028 * Note: old style constructor with text is still supported.
35031 * Creates a new TextItem
35032 * @param {Object} cfg Configuration
35034 Roo.menu.TextItem = function(cfg){
35035 if (typeof(cfg) == 'string') {
35038 Roo.apply(this,cfg);
35041 Roo.menu.TextItem.superclass.constructor.call(this);
35044 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35046 * @cfg {Boolean} text Text to show on item.
35051 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35053 hideOnClick : false,
35055 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35057 itemCls : "x-menu-text",
35060 onRender : function(){
35061 var s = document.createElement("span");
35062 s.className = this.itemCls;
35063 s.innerHTML = this.text;
35065 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35069 * Ext JS Library 1.1.1
35070 * Copyright(c) 2006-2007, Ext JS, LLC.
35072 * Originally Released Under LGPL - original licence link has changed is not relivant.
35075 * <script type="text/javascript">
35079 * @class Roo.menu.Separator
35080 * @extends Roo.menu.BaseItem
35081 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35082 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35084 * @param {Object} config Configuration options
35086 Roo.menu.Separator = function(config){
35087 Roo.menu.Separator.superclass.constructor.call(this, config);
35090 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35092 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35094 itemCls : "x-menu-sep",
35096 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35098 hideOnClick : false,
35101 onRender : function(li){
35102 var s = document.createElement("span");
35103 s.className = this.itemCls;
35104 s.innerHTML = " ";
35106 li.addClass("x-menu-sep-li");
35107 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35111 * Ext JS Library 1.1.1
35112 * Copyright(c) 2006-2007, Ext JS, LLC.
35114 * Originally Released Under LGPL - original licence link has changed is not relivant.
35117 * <script type="text/javascript">
35120 * @class Roo.menu.Item
35121 * @extends Roo.menu.BaseItem
35122 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35123 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35124 * activation and click handling.
35126 * Creates a new Item
35127 * @param {Object} config Configuration options
35129 Roo.menu.Item = function(config){
35130 Roo.menu.Item.superclass.constructor.call(this, config);
35132 this.menu = Roo.menu.MenuMgr.get(this.menu);
35135 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35138 * @cfg {String} text
35139 * The text to show on the menu item.
35143 * @cfg {String} HTML to render in menu
35144 * The text to show on the menu item (HTML version).
35148 * @cfg {String} icon
35149 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35153 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35155 itemCls : "x-menu-item",
35157 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35159 canActivate : true,
35161 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35164 // doc'd in BaseItem
35168 ctype: "Roo.menu.Item",
35171 onRender : function(container, position){
35172 var el = document.createElement("a");
35173 el.hideFocus = true;
35174 el.unselectable = "on";
35175 el.href = this.href || "#";
35176 if(this.hrefTarget){
35177 el.target = this.hrefTarget;
35179 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35181 var html = this.html.length ? this.html : String.format('{0}',this.text);
35183 el.innerHTML = String.format(
35184 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35185 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35187 Roo.menu.Item.superclass.onRender.call(this, container, position);
35191 * Sets the text to display in this menu item
35192 * @param {String} text The text to display
35193 * @param {Boolean} isHTML true to indicate text is pure html.
35195 setText : function(text, isHTML){
35203 var html = this.html.length ? this.html : String.format('{0}',this.text);
35205 this.el.update(String.format(
35206 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35207 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35208 this.parentMenu.autoWidth();
35213 handleClick : function(e){
35214 if(!this.href){ // if no link defined, stop the event automatically
35217 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35221 activate : function(autoExpand){
35222 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35232 shouldDeactivate : function(e){
35233 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35234 if(this.menu && this.menu.isVisible()){
35235 return !this.menu.getEl().getRegion().contains(e.getPoint());
35243 deactivate : function(){
35244 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35249 expandMenu : function(autoActivate){
35250 if(!this.disabled && this.menu){
35251 clearTimeout(this.hideTimer);
35252 delete this.hideTimer;
35253 if(!this.menu.isVisible() && !this.showTimer){
35254 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35255 }else if (this.menu.isVisible() && autoActivate){
35256 this.menu.tryActivate(0, 1);
35262 deferExpand : function(autoActivate){
35263 delete this.showTimer;
35264 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35266 this.menu.tryActivate(0, 1);
35271 hideMenu : function(){
35272 clearTimeout(this.showTimer);
35273 delete this.showTimer;
35274 if(!this.hideTimer && this.menu && this.menu.isVisible()){
35275 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
35280 deferHide : function(){
35281 delete this.hideTimer;
35286 * Ext JS Library 1.1.1
35287 * Copyright(c) 2006-2007, Ext JS, LLC.
35289 * Originally Released Under LGPL - original licence link has changed is not relivant.
35292 * <script type="text/javascript">
35296 * @class Roo.menu.CheckItem
35297 * @extends Roo.menu.Item
35298 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
35300 * Creates a new CheckItem
35301 * @param {Object} config Configuration options
35303 Roo.menu.CheckItem = function(config){
35304 Roo.menu.CheckItem.superclass.constructor.call(this, config);
35307 * @event beforecheckchange
35308 * Fires before the checked value is set, providing an opportunity to cancel if needed
35309 * @param {Roo.menu.CheckItem} this
35310 * @param {Boolean} checked The new checked value that will be set
35312 "beforecheckchange" : true,
35314 * @event checkchange
35315 * Fires after the checked value has been set
35316 * @param {Roo.menu.CheckItem} this
35317 * @param {Boolean} checked The checked value that was set
35319 "checkchange" : true
35321 if(this.checkHandler){
35322 this.on('checkchange', this.checkHandler, this.scope);
35325 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
35327 * @cfg {String} group
35328 * All check items with the same group name will automatically be grouped into a single-select
35329 * radio button group (defaults to '')
35332 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
35334 itemCls : "x-menu-item x-menu-check-item",
35336 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
35338 groupClass : "x-menu-group-item",
35341 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
35342 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
35343 * initialized with checked = true will be rendered as checked.
35348 ctype: "Roo.menu.CheckItem",
35351 onRender : function(c){
35352 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
35354 this.el.addClass(this.groupClass);
35356 Roo.menu.MenuMgr.registerCheckable(this);
35358 this.checked = false;
35359 this.setChecked(true, true);
35364 destroy : function(){
35366 Roo.menu.MenuMgr.unregisterCheckable(this);
35368 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
35372 * Set the checked state of this item
35373 * @param {Boolean} checked The new checked value
35374 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
35376 setChecked : function(state, suppressEvent){
35377 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
35378 if(this.container){
35379 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
35381 this.checked = state;
35382 if(suppressEvent !== true){
35383 this.fireEvent("checkchange", this, state);
35389 handleClick : function(e){
35390 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
35391 this.setChecked(!this.checked);
35393 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
35397 * Ext JS Library 1.1.1
35398 * Copyright(c) 2006-2007, Ext JS, LLC.
35400 * Originally Released Under LGPL - original licence link has changed is not relivant.
35403 * <script type="text/javascript">
35407 * @class Roo.menu.DateItem
35408 * @extends Roo.menu.Adapter
35409 * A menu item that wraps the {@link Roo.DatPicker} component.
35411 * Creates a new DateItem
35412 * @param {Object} config Configuration options
35414 Roo.menu.DateItem = function(config){
35415 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
35416 /** The Roo.DatePicker object @type Roo.DatePicker */
35417 this.picker = this.component;
35418 this.addEvents({select: true});
35420 this.picker.on("render", function(picker){
35421 picker.getEl().swallowEvent("click");
35422 picker.container.addClass("x-menu-date-item");
35425 this.picker.on("select", this.onSelect, this);
35428 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
35430 onSelect : function(picker, date){
35431 this.fireEvent("select", this, date, picker);
35432 Roo.menu.DateItem.superclass.handleClick.call(this);
35436 * Ext JS Library 1.1.1
35437 * Copyright(c) 2006-2007, Ext JS, LLC.
35439 * Originally Released Under LGPL - original licence link has changed is not relivant.
35442 * <script type="text/javascript">
35446 * @class Roo.menu.ColorItem
35447 * @extends Roo.menu.Adapter
35448 * A menu item that wraps the {@link Roo.ColorPalette} component.
35450 * Creates a new ColorItem
35451 * @param {Object} config Configuration options
35453 Roo.menu.ColorItem = function(config){
35454 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
35455 /** The Roo.ColorPalette object @type Roo.ColorPalette */
35456 this.palette = this.component;
35457 this.relayEvents(this.palette, ["select"]);
35458 if(this.selectHandler){
35459 this.on('select', this.selectHandler, this.scope);
35462 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
35464 * Ext JS Library 1.1.1
35465 * Copyright(c) 2006-2007, Ext JS, LLC.
35467 * Originally Released Under LGPL - original licence link has changed is not relivant.
35470 * <script type="text/javascript">
35475 * @class Roo.menu.DateMenu
35476 * @extends Roo.menu.Menu
35477 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
35479 * Creates a new DateMenu
35480 * @param {Object} config Configuration options
35482 Roo.menu.DateMenu = function(config){
35483 Roo.menu.DateMenu.superclass.constructor.call(this, config);
35485 var di = new Roo.menu.DateItem(config);
35488 * The {@link Roo.DatePicker} instance for this DateMenu
35491 this.picker = di.picker;
35494 * @param {DatePicker} picker
35495 * @param {Date} date
35497 this.relayEvents(di, ["select"]);
35499 this.on('beforeshow', function(){
35501 this.picker.hideMonthPicker(true);
35505 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
35509 * Ext JS Library 1.1.1
35510 * Copyright(c) 2006-2007, Ext JS, LLC.
35512 * Originally Released Under LGPL - original licence link has changed is not relivant.
35515 * <script type="text/javascript">
35520 * @class Roo.menu.ColorMenu
35521 * @extends Roo.menu.Menu
35522 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
35524 * Creates a new ColorMenu
35525 * @param {Object} config Configuration options
35527 Roo.menu.ColorMenu = function(config){
35528 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
35530 var ci = new Roo.menu.ColorItem(config);
35533 * The {@link Roo.ColorPalette} instance for this ColorMenu
35534 * @type ColorPalette
35536 this.palette = ci.palette;
35539 * @param {ColorPalette} palette
35540 * @param {String} color
35542 this.relayEvents(ci, ["select"]);
35544 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
35546 * Ext JS Library 1.1.1
35547 * Copyright(c) 2006-2007, Ext JS, LLC.
35549 * Originally Released Under LGPL - original licence link has changed is not relivant.
35552 * <script type="text/javascript">
35556 * @class Roo.form.Field
35557 * @extends Roo.BoxComponent
35558 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
35560 * Creates a new Field
35561 * @param {Object} config Configuration options
35563 Roo.form.Field = function(config){
35564 Roo.form.Field.superclass.constructor.call(this, config);
35567 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
35569 * @cfg {String} fieldLabel Label to use when rendering a form.
35572 * @cfg {String} qtip Mouse over tip
35576 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
35578 invalidClass : "x-form-invalid",
35580 * @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")
35582 invalidText : "The value in this field is invalid",
35584 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
35586 focusClass : "x-form-focus",
35588 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
35589 automatic validation (defaults to "keyup").
35591 validationEvent : "keyup",
35593 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
35595 validateOnBlur : true,
35597 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
35599 validationDelay : 250,
35601 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
35602 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
35604 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
35606 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
35608 fieldClass : "x-form-field",
35610 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
35613 ----------- ----------------------------------------------------------------------
35614 qtip Display a quick tip when the user hovers over the field
35615 title Display a default browser title attribute popup
35616 under Add a block div beneath the field containing the error text
35617 side Add an error icon to the right of the field with a popup on hover
35618 [element id] Add the error text directly to the innerHTML of the specified element
35621 msgTarget : 'qtip',
35623 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
35628 * @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.
35633 * @cfg {Boolean} disabled True to disable the field (defaults to false).
35638 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
35640 inputType : undefined,
35643 * @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).
35645 tabIndex : undefined,
35648 isFormField : true,
35653 * @property {Roo.Element} fieldEl
35654 * Element Containing the rendered Field (with label etc.)
35657 * @cfg {Mixed} value A value to initialize this field with.
35662 * @cfg {String} name The field's HTML name attribute.
35665 * @cfg {String} cls A CSS class to apply to the field's underlying element.
35669 initComponent : function(){
35670 Roo.form.Field.superclass.initComponent.call(this);
35674 * Fires when this field receives input focus.
35675 * @param {Roo.form.Field} this
35680 * Fires when this field loses input focus.
35681 * @param {Roo.form.Field} this
35685 * @event specialkey
35686 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
35687 * {@link Roo.EventObject#getKey} to determine which key was pressed.
35688 * @param {Roo.form.Field} this
35689 * @param {Roo.EventObject} e The event object
35694 * Fires just before the field blurs if the field value has changed.
35695 * @param {Roo.form.Field} this
35696 * @param {Mixed} newValue The new value
35697 * @param {Mixed} oldValue The original value
35702 * Fires after the field has been marked as invalid.
35703 * @param {Roo.form.Field} this
35704 * @param {String} msg The validation message
35709 * Fires after the field has been validated with no errors.
35710 * @param {Roo.form.Field} this
35715 * Fires after the key up
35716 * @param {Roo.form.Field} this
35717 * @param {Roo.EventObject} e The event Object
35724 * Returns the name attribute of the field if available
35725 * @return {String} name The field name
35727 getName: function(){
35728 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
35732 onRender : function(ct, position){
35733 Roo.form.Field.superclass.onRender.call(this, ct, position);
35735 var cfg = this.getAutoCreate();
35737 cfg.name = this.name || this.id;
35739 if(this.inputType){
35740 cfg.type = this.inputType;
35742 this.el = ct.createChild(cfg, position);
35744 var type = this.el.dom.type;
35746 if(type == 'password'){
35749 this.el.addClass('x-form-'+type);
35752 this.el.dom.readOnly = true;
35754 if(this.tabIndex !== undefined){
35755 this.el.dom.setAttribute('tabIndex', this.tabIndex);
35758 this.el.addClass([this.fieldClass, this.cls]);
35763 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
35764 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
35765 * @return {Roo.form.Field} this
35767 applyTo : function(target){
35768 this.allowDomMove = false;
35769 this.el = Roo.get(target);
35770 this.render(this.el.dom.parentNode);
35775 initValue : function(){
35776 if(this.value !== undefined){
35777 this.setValue(this.value);
35778 }else if(this.el.dom.value.length > 0){
35779 this.setValue(this.el.dom.value);
35784 * Returns true if this field has been changed since it was originally loaded and is not disabled.
35786 isDirty : function() {
35787 if(this.disabled) {
35790 return String(this.getValue()) !== String(this.originalValue);
35794 afterRender : function(){
35795 Roo.form.Field.superclass.afterRender.call(this);
35800 fireKey : function(e){
35801 //Roo.log('field ' + e.getKey());
35802 if(e.isNavKeyPress()){
35803 this.fireEvent("specialkey", this, e);
35808 * Resets the current field value to the originally loaded value and clears any validation messages
35810 reset : function(){
35811 this.setValue(this.originalValue);
35812 this.clearInvalid();
35816 initEvents : function(){
35817 // safari killled keypress - so keydown is now used..
35818 this.el.on("keydown" , this.fireKey, this);
35819 this.el.on("focus", this.onFocus, this);
35820 this.el.on("blur", this.onBlur, this);
35821 this.el.relayEvent('keyup', this);
35823 // reference to original value for reset
35824 this.originalValue = this.getValue();
35828 onFocus : function(){
35829 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35830 this.el.addClass(this.focusClass);
35832 if(!this.hasFocus){
35833 this.hasFocus = true;
35834 this.startValue = this.getValue();
35835 this.fireEvent("focus", this);
35839 beforeBlur : Roo.emptyFn,
35842 onBlur : function(){
35844 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
35845 this.el.removeClass(this.focusClass);
35847 this.hasFocus = false;
35848 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
35851 var v = this.getValue();
35852 if(String(v) !== String(this.startValue)){
35853 this.fireEvent('change', this, v, this.startValue);
35855 this.fireEvent("blur", this);
35859 * Returns whether or not the field value is currently valid
35860 * @param {Boolean} preventMark True to disable marking the field invalid
35861 * @return {Boolean} True if the value is valid, else false
35863 isValid : function(preventMark){
35867 var restore = this.preventMark;
35868 this.preventMark = preventMark === true;
35869 var v = this.validateValue(this.processValue(this.getRawValue()));
35870 this.preventMark = restore;
35875 * Validates the field value
35876 * @return {Boolean} True if the value is valid, else false
35878 validate : function(){
35879 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
35880 this.clearInvalid();
35886 processValue : function(value){
35891 // Subclasses should provide the validation implementation by overriding this
35892 validateValue : function(value){
35897 * Mark this field as invalid
35898 * @param {String} msg The validation message
35900 markInvalid : function(msg){
35901 if(!this.rendered || this.preventMark){ // not rendered
35904 this.el.addClass(this.invalidClass);
35905 msg = msg || this.invalidText;
35906 switch(this.msgTarget){
35908 this.el.dom.qtip = msg;
35909 this.el.dom.qclass = 'x-form-invalid-tip';
35910 if(Roo.QuickTips){ // fix for floating editors interacting with DND
35911 Roo.QuickTips.enable();
35915 this.el.dom.title = msg;
35919 var elp = this.el.findParent('.x-form-element', 5, true);
35920 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
35921 this.errorEl.setWidth(elp.getWidth(true)-20);
35923 this.errorEl.update(msg);
35924 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
35927 if(!this.errorIcon){
35928 var elp = this.el.findParent('.x-form-element', 5, true);
35929 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
35931 this.alignErrorIcon();
35932 this.errorIcon.dom.qtip = msg;
35933 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
35934 this.errorIcon.show();
35935 this.on('resize', this.alignErrorIcon, this);
35938 var t = Roo.getDom(this.msgTarget);
35940 t.style.display = this.msgDisplay;
35943 this.fireEvent('invalid', this, msg);
35947 alignErrorIcon : function(){
35948 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
35952 * Clear any invalid styles/messages for this field
35954 clearInvalid : function(){
35955 if(!this.rendered || this.preventMark){ // not rendered
35958 this.el.removeClass(this.invalidClass);
35959 switch(this.msgTarget){
35961 this.el.dom.qtip = '';
35964 this.el.dom.title = '';
35968 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
35972 if(this.errorIcon){
35973 this.errorIcon.dom.qtip = '';
35974 this.errorIcon.hide();
35975 this.un('resize', this.alignErrorIcon, this);
35979 var t = Roo.getDom(this.msgTarget);
35981 t.style.display = 'none';
35984 this.fireEvent('valid', this);
35988 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
35989 * @return {Mixed} value The field value
35991 getRawValue : function(){
35992 var v = this.el.getValue();
35993 if(v === this.emptyText){
36000 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36001 * @return {Mixed} value The field value
36003 getValue : function(){
36004 var v = this.el.getValue();
36005 if(v === this.emptyText || v === undefined){
36012 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36013 * @param {Mixed} value The value to set
36015 setRawValue : function(v){
36016 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36020 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36021 * @param {Mixed} value The value to set
36023 setValue : function(v){
36026 this.el.dom.value = (v === null || v === undefined ? '' : v);
36031 adjustSize : function(w, h){
36032 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36033 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36037 adjustWidth : function(tag, w){
36038 tag = tag.toLowerCase();
36039 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36040 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36041 if(tag == 'input'){
36044 if(tag = 'textarea'){
36047 }else if(Roo.isOpera){
36048 if(tag == 'input'){
36051 if(tag = 'textarea'){
36061 // anything other than normal should be considered experimental
36062 Roo.form.Field.msgFx = {
36064 show: function(msgEl, f){
36065 msgEl.setDisplayed('block');
36068 hide : function(msgEl, f){
36069 msgEl.setDisplayed(false).update('');
36074 show: function(msgEl, f){
36075 msgEl.slideIn('t', {stopFx:true});
36078 hide : function(msgEl, f){
36079 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36084 show: function(msgEl, f){
36085 msgEl.fixDisplay();
36086 msgEl.alignTo(f.el, 'tl-tr');
36087 msgEl.slideIn('l', {stopFx:true});
36090 hide : function(msgEl, f){
36091 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36096 * Ext JS Library 1.1.1
36097 * Copyright(c) 2006-2007, Ext JS, LLC.
36099 * Originally Released Under LGPL - original licence link has changed is not relivant.
36102 * <script type="text/javascript">
36107 * @class Roo.form.TextField
36108 * @extends Roo.form.Field
36109 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36110 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36112 * Creates a new TextField
36113 * @param {Object} config Configuration options
36115 Roo.form.TextField = function(config){
36116 Roo.form.TextField.superclass.constructor.call(this, config);
36120 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36121 * according to the default logic, but this event provides a hook for the developer to apply additional
36122 * logic at runtime to resize the field if needed.
36123 * @param {Roo.form.Field} this This text field
36124 * @param {Number} width The new field width
36130 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36132 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36136 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36140 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36144 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36148 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36152 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36154 disableKeyFilter : false,
36156 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36160 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36164 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36166 maxLength : Number.MAX_VALUE,
36168 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36170 minLengthText : "The minimum length for this field is {0}",
36172 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36174 maxLengthText : "The maximum length for this field is {0}",
36176 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36178 selectOnFocus : false,
36180 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36182 blankText : "This field is required",
36184 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36185 * If available, this function will be called only after the basic validators all return true, and will be passed the
36186 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36190 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36191 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36192 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36196 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36200 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
36204 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
36205 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
36207 emptyClass : 'x-form-empty-field',
36210 initEvents : function(){
36211 Roo.form.TextField.superclass.initEvents.call(this);
36212 if(this.validationEvent == 'keyup'){
36213 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36214 this.el.on('keyup', this.filterValidation, this);
36216 else if(this.validationEvent !== false){
36217 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36219 if(this.selectOnFocus || this.emptyText){
36220 this.on("focus", this.preFocus, this);
36221 if(this.emptyText){
36222 this.on('blur', this.postBlur, this);
36223 this.applyEmptyText();
36226 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36227 this.el.on("keypress", this.filterKeys, this);
36230 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36231 this.el.on("click", this.autoSize, this);
36235 processValue : function(value){
36236 if(this.stripCharsRe){
36237 var newValue = value.replace(this.stripCharsRe, '');
36238 if(newValue !== value){
36239 this.setRawValue(newValue);
36246 filterValidation : function(e){
36247 if(!e.isNavKeyPress()){
36248 this.validationTask.delay(this.validationDelay);
36253 onKeyUp : function(e){
36254 if(!e.isNavKeyPress()){
36260 * Resets the current field value to the originally-loaded value and clears any validation messages.
36261 * Also adds emptyText and emptyClass if the original value was blank.
36263 reset : function(){
36264 Roo.form.TextField.superclass.reset.call(this);
36265 this.applyEmptyText();
36268 applyEmptyText : function(){
36269 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
36270 this.setRawValue(this.emptyText);
36271 this.el.addClass(this.emptyClass);
36276 preFocus : function(){
36277 if(this.emptyText){
36278 if(this.el.dom.value == this.emptyText){
36279 this.setRawValue('');
36281 this.el.removeClass(this.emptyClass);
36283 if(this.selectOnFocus){
36284 this.el.dom.select();
36289 postBlur : function(){
36290 this.applyEmptyText();
36294 filterKeys : function(e){
36295 var k = e.getKey();
36296 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
36299 var c = e.getCharCode(), cc = String.fromCharCode(c);
36300 if(Roo.isIE && (e.isSpecialKey() || !cc)){
36303 if(!this.maskRe.test(cc)){
36308 setValue : function(v){
36309 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
36310 this.el.removeClass(this.emptyClass);
36312 Roo.form.TextField.superclass.setValue.apply(this, arguments);
36313 this.applyEmptyText();
36318 * Validates a value according to the field's validation rules and marks the field as invalid
36319 * if the validation fails
36320 * @param {Mixed} value The value to validate
36321 * @return {Boolean} True if the value is valid, else false
36323 validateValue : function(value){
36324 if(value.length < 1 || value === this.emptyText){ // if it's blank
36325 if(this.allowBlank){
36326 this.clearInvalid();
36329 this.markInvalid(this.blankText);
36333 if(value.length < this.minLength){
36334 this.markInvalid(String.format(this.minLengthText, this.minLength));
36337 if(value.length > this.maxLength){
36338 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
36342 var vt = Roo.form.VTypes;
36343 if(!vt[this.vtype](value, this)){
36344 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
36348 if(typeof this.validator == "function"){
36349 var msg = this.validator(value);
36351 this.markInvalid(msg);
36355 if(this.regex && !this.regex.test(value)){
36356 this.markInvalid(this.regexText);
36363 * Selects text in this field
36364 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
36365 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
36367 selectText : function(start, end){
36368 var v = this.getRawValue();
36370 start = start === undefined ? 0 : start;
36371 end = end === undefined ? v.length : end;
36372 var d = this.el.dom;
36373 if(d.setSelectionRange){
36374 d.setSelectionRange(start, end);
36375 }else if(d.createTextRange){
36376 var range = d.createTextRange();
36377 range.moveStart("character", start);
36378 range.moveEnd("character", v.length-end);
36385 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
36386 * This only takes effect if grow = true, and fires the autosize event.
36388 autoSize : function(){
36389 if(!this.grow || !this.rendered){
36393 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
36396 var v = el.dom.value;
36397 var d = document.createElement('div');
36398 d.appendChild(document.createTextNode(v));
36402 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
36403 this.el.setWidth(w);
36404 this.fireEvent("autosize", this, w);
36408 * Ext JS Library 1.1.1
36409 * Copyright(c) 2006-2007, Ext JS, LLC.
36411 * Originally Released Under LGPL - original licence link has changed is not relivant.
36414 * <script type="text/javascript">
36418 * @class Roo.form.Hidden
36419 * @extends Roo.form.TextField
36420 * Simple Hidden element used on forms
36422 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
36425 * Creates a new Hidden form element.
36426 * @param {Object} config Configuration options
36431 // easy hidden field...
36432 Roo.form.Hidden = function(config){
36433 Roo.form.Hidden.superclass.constructor.call(this, config);
36436 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
36438 inputType: 'hidden',
36441 labelSeparator: '',
36443 itemCls : 'x-form-item-display-none'
36451 * Ext JS Library 1.1.1
36452 * Copyright(c) 2006-2007, Ext JS, LLC.
36454 * Originally Released Under LGPL - original licence link has changed is not relivant.
36457 * <script type="text/javascript">
36461 * @class Roo.form.TriggerField
36462 * @extends Roo.form.TextField
36463 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
36464 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
36465 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
36466 * for which you can provide a custom implementation. For example:
36468 var trigger = new Roo.form.TriggerField();
36469 trigger.onTriggerClick = myTriggerFn;
36470 trigger.applyTo('my-field');
36473 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
36474 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
36475 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
36476 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
36478 * Create a new TriggerField.
36479 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
36480 * to the base TextField)
36482 Roo.form.TriggerField = function(config){
36483 this.mimicing = false;
36484 Roo.form.TriggerField.superclass.constructor.call(this, config);
36487 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
36489 * @cfg {String} triggerClass A CSS class to apply to the trigger
36492 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36493 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
36495 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
36497 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
36501 /** @cfg {Boolean} grow @hide */
36502 /** @cfg {Number} growMin @hide */
36503 /** @cfg {Number} growMax @hide */
36509 autoSize: Roo.emptyFn,
36513 deferHeight : true,
36516 actionMode : 'wrap',
36518 onResize : function(w, h){
36519 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
36520 if(typeof w == 'number'){
36521 var x = w - this.trigger.getWidth();
36522 this.el.setWidth(this.adjustWidth('input', x));
36523 this.trigger.setStyle('left', x+'px');
36528 adjustSize : Roo.BoxComponent.prototype.adjustSize,
36531 getResizeEl : function(){
36536 getPositionEl : function(){
36541 alignErrorIcon : function(){
36542 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
36546 onRender : function(ct, position){
36547 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
36548 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
36549 this.trigger = this.wrap.createChild(this.triggerConfig ||
36550 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
36551 if(this.hideTrigger){
36552 this.trigger.setDisplayed(false);
36554 this.initTrigger();
36556 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
36561 initTrigger : function(){
36562 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
36563 this.trigger.addClassOnOver('x-form-trigger-over');
36564 this.trigger.addClassOnClick('x-form-trigger-click');
36568 onDestroy : function(){
36570 this.trigger.removeAllListeners();
36571 this.trigger.remove();
36574 this.wrap.remove();
36576 Roo.form.TriggerField.superclass.onDestroy.call(this);
36580 onFocus : function(){
36581 Roo.form.TriggerField.superclass.onFocus.call(this);
36582 if(!this.mimicing){
36583 this.wrap.addClass('x-trigger-wrap-focus');
36584 this.mimicing = true;
36585 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
36586 if(this.monitorTab){
36587 this.el.on("keydown", this.checkTab, this);
36593 checkTab : function(e){
36594 if(e.getKey() == e.TAB){
36595 this.triggerBlur();
36600 onBlur : function(){
36605 mimicBlur : function(e, t){
36606 if(!this.wrap.contains(t) && this.validateBlur()){
36607 this.triggerBlur();
36612 triggerBlur : function(){
36613 this.mimicing = false;
36614 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
36615 if(this.monitorTab){
36616 this.el.un("keydown", this.checkTab, this);
36618 this.wrap.removeClass('x-trigger-wrap-focus');
36619 Roo.form.TriggerField.superclass.onBlur.call(this);
36623 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
36624 validateBlur : function(e, t){
36629 onDisable : function(){
36630 Roo.form.TriggerField.superclass.onDisable.call(this);
36632 this.wrap.addClass('x-item-disabled');
36637 onEnable : function(){
36638 Roo.form.TriggerField.superclass.onEnable.call(this);
36640 this.wrap.removeClass('x-item-disabled');
36645 onShow : function(){
36646 var ae = this.getActionEl();
36649 ae.dom.style.display = '';
36650 ae.dom.style.visibility = 'visible';
36656 onHide : function(){
36657 var ae = this.getActionEl();
36658 ae.dom.style.display = 'none';
36662 * The function that should handle the trigger's click event. This method does nothing by default until overridden
36663 * by an implementing function.
36665 * @param {EventObject} e
36667 onTriggerClick : Roo.emptyFn
36670 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
36671 // to be extended by an implementing class. For an example of implementing this class, see the custom
36672 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
36673 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
36674 initComponent : function(){
36675 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
36677 this.triggerConfig = {
36678 tag:'span', cls:'x-form-twin-triggers', cn:[
36679 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
36680 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
36684 getTrigger : function(index){
36685 return this.triggers[index];
36688 initTrigger : function(){
36689 var ts = this.trigger.select('.x-form-trigger', true);
36690 this.wrap.setStyle('overflow', 'hidden');
36691 var triggerField = this;
36692 ts.each(function(t, all, index){
36693 t.hide = function(){
36694 var w = triggerField.wrap.getWidth();
36695 this.dom.style.display = 'none';
36696 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36698 t.show = function(){
36699 var w = triggerField.wrap.getWidth();
36700 this.dom.style.display = '';
36701 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
36703 var triggerIndex = 'Trigger'+(index+1);
36705 if(this['hide'+triggerIndex]){
36706 t.dom.style.display = 'none';
36708 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
36709 t.addClassOnOver('x-form-trigger-over');
36710 t.addClassOnClick('x-form-trigger-click');
36712 this.triggers = ts.elements;
36715 onTrigger1Click : Roo.emptyFn,
36716 onTrigger2Click : Roo.emptyFn
36719 * Ext JS Library 1.1.1
36720 * Copyright(c) 2006-2007, Ext JS, LLC.
36722 * Originally Released Under LGPL - original licence link has changed is not relivant.
36725 * <script type="text/javascript">
36729 * @class Roo.form.TextArea
36730 * @extends Roo.form.TextField
36731 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
36732 * support for auto-sizing.
36734 * Creates a new TextArea
36735 * @param {Object} config Configuration options
36737 Roo.form.TextArea = function(config){
36738 Roo.form.TextArea.superclass.constructor.call(this, config);
36739 // these are provided exchanges for backwards compat
36740 // minHeight/maxHeight were replaced by growMin/growMax to be
36741 // compatible with TextField growing config values
36742 if(this.minHeight !== undefined){
36743 this.growMin = this.minHeight;
36745 if(this.maxHeight !== undefined){
36746 this.growMax = this.maxHeight;
36750 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
36752 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
36756 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
36760 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
36761 * in the field (equivalent to setting overflow: hidden, defaults to false)
36763 preventScrollbars: false,
36765 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36766 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
36770 onRender : function(ct, position){
36772 this.defaultAutoCreate = {
36774 style:"width:300px;height:60px;",
36775 autocomplete: "off"
36778 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
36780 this.textSizeEl = Roo.DomHelper.append(document.body, {
36781 tag: "pre", cls: "x-form-grow-sizer"
36783 if(this.preventScrollbars){
36784 this.el.setStyle("overflow", "hidden");
36786 this.el.setHeight(this.growMin);
36790 onDestroy : function(){
36791 if(this.textSizeEl){
36792 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
36794 Roo.form.TextArea.superclass.onDestroy.call(this);
36798 onKeyUp : function(e){
36799 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
36805 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
36806 * This only takes effect if grow = true, and fires the autosize event if the height changes.
36808 autoSize : function(){
36809 if(!this.grow || !this.textSizeEl){
36813 var v = el.dom.value;
36814 var ts = this.textSizeEl;
36817 ts.appendChild(document.createTextNode(v));
36820 Roo.fly(ts).setWidth(this.el.getWidth());
36822 v = "  ";
36825 v = v.replace(/\n/g, '<p> </p>');
36827 v += " \n ";
36830 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
36831 if(h != this.lastHeight){
36832 this.lastHeight = h;
36833 this.el.setHeight(h);
36834 this.fireEvent("autosize", this, h);
36839 * Ext JS Library 1.1.1
36840 * Copyright(c) 2006-2007, Ext JS, LLC.
36842 * Originally Released Under LGPL - original licence link has changed is not relivant.
36845 * <script type="text/javascript">
36850 * @class Roo.form.NumberField
36851 * @extends Roo.form.TextField
36852 * Numeric text field that provides automatic keystroke filtering and numeric validation.
36854 * Creates a new NumberField
36855 * @param {Object} config Configuration options
36857 Roo.form.NumberField = function(config){
36858 Roo.form.NumberField.superclass.constructor.call(this, config);
36861 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
36863 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
36865 fieldClass: "x-form-field x-form-num-field",
36867 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
36869 allowDecimals : true,
36871 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
36873 decimalSeparator : ".",
36875 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
36877 decimalPrecision : 2,
36879 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
36881 allowNegative : true,
36883 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36885 minValue : Number.NEGATIVE_INFINITY,
36887 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36889 maxValue : Number.MAX_VALUE,
36891 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36893 minText : "The minimum value for this field is {0}",
36895 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36897 maxText : "The maximum value for this field is {0}",
36899 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36900 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36902 nanText : "{0} is not a valid number",
36905 initEvents : function(){
36906 Roo.form.NumberField.superclass.initEvents.call(this);
36907 var allowed = "0123456789";
36908 if(this.allowDecimals){
36909 allowed += this.decimalSeparator;
36911 if(this.allowNegative){
36914 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36915 var keyPress = function(e){
36916 var k = e.getKey();
36917 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36920 var c = e.getCharCode();
36921 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36925 this.el.on("keypress", keyPress, this);
36929 validateValue : function(value){
36930 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
36933 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
36936 var num = this.parseValue(value);
36938 this.markInvalid(String.format(this.nanText, value));
36941 if(num < this.minValue){
36942 this.markInvalid(String.format(this.minText, this.minValue));
36945 if(num > this.maxValue){
36946 this.markInvalid(String.format(this.maxText, this.maxValue));
36952 getValue : function(){
36953 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
36957 parseValue : function(value){
36958 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36959 return isNaN(value) ? '' : value;
36963 fixPrecision : function(value){
36964 var nan = isNaN(value);
36965 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36966 return nan ? '' : value;
36968 return parseFloat(value).toFixed(this.decimalPrecision);
36971 setValue : function(v){
36972 v = this.fixPrecision(v);
36973 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
36977 decimalPrecisionFcn : function(v){
36978 return Math.floor(v);
36981 beforeBlur : function(){
36982 var v = this.parseValue(this.getRawValue());
36989 * Ext JS Library 1.1.1
36990 * Copyright(c) 2006-2007, Ext JS, LLC.
36992 * Originally Released Under LGPL - original licence link has changed is not relivant.
36995 * <script type="text/javascript">
36999 * @class Roo.form.DateField
37000 * @extends Roo.form.TriggerField
37001 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37003 * Create a new DateField
37004 * @param {Object} config
37006 Roo.form.DateField = function(config){
37007 Roo.form.DateField.superclass.constructor.call(this, config);
37013 * Fires when a date is selected
37014 * @param {Roo.form.DateField} combo This combo box
37015 * @param {Date} date The date selected
37022 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37023 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37024 this.ddMatch = null;
37025 if(this.disabledDates){
37026 var dd = this.disabledDates;
37028 for(var i = 0; i < dd.length; i++){
37030 if(i != dd.length-1) re += "|";
37032 this.ddMatch = new RegExp(re + ")");
37036 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37038 * @cfg {String} format
37039 * The default date format string which can be overriden for localization support. The format must be
37040 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37044 * @cfg {String} altFormats
37045 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37046 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37048 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37050 * @cfg {Array} disabledDays
37051 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37053 disabledDays : null,
37055 * @cfg {String} disabledDaysText
37056 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37058 disabledDaysText : "Disabled",
37060 * @cfg {Array} disabledDates
37061 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37062 * expression so they are very powerful. Some examples:
37064 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37065 * <li>["03/08", "09/16"] would disable those days for every year</li>
37066 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37067 * <li>["03/../2006"] would disable every day in March 2006</li>
37068 * <li>["^03"] would disable every day in every March</li>
37070 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37071 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37073 disabledDates : null,
37075 * @cfg {String} disabledDatesText
37076 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37078 disabledDatesText : "Disabled",
37080 * @cfg {Date/String} minValue
37081 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37082 * valid format (defaults to null).
37086 * @cfg {Date/String} maxValue
37087 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37088 * valid format (defaults to null).
37092 * @cfg {String} minText
37093 * The error text to display when the date in the cell is before minValue (defaults to
37094 * 'The date in this field must be after {minValue}').
37096 minText : "The date in this field must be equal to or after {0}",
37098 * @cfg {String} maxText
37099 * The error text to display when the date in the cell is after maxValue (defaults to
37100 * 'The date in this field must be before {maxValue}').
37102 maxText : "The date in this field must be equal to or before {0}",
37104 * @cfg {String} invalidText
37105 * The error text to display when the date in the field is invalid (defaults to
37106 * '{value} is not a valid date - it must be in the format {format}').
37108 invalidText : "{0} is not a valid date - it must be in the format {1}",
37110 * @cfg {String} triggerClass
37111 * An additional CSS class used to style the trigger button. The trigger will always get the
37112 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37113 * which displays a calendar icon).
37115 triggerClass : 'x-form-date-trigger',
37119 * @cfg {bool} useIso
37120 * if enabled, then the date field will use a hidden field to store the
37121 * real value as iso formated date. default (false)
37125 * @cfg {String/Object} autoCreate
37126 * A DomHelper element spec, or true for a default element spec (defaults to
37127 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37130 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37133 hiddenField: false,
37135 onRender : function(ct, position)
37137 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37139 this.el.dom.removeAttribute('name');
37140 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37142 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
37143 // prevent input submission
37144 this.hiddenName = this.name;
37151 validateValue : function(value)
37153 value = this.formatDate(value);
37154 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37157 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37160 var svalue = value;
37161 value = this.parseDate(value);
37163 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37166 var time = value.getTime();
37167 if(this.minValue && time < this.minValue.getTime()){
37168 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37171 if(this.maxValue && time > this.maxValue.getTime()){
37172 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37175 if(this.disabledDays){
37176 var day = value.getDay();
37177 for(var i = 0; i < this.disabledDays.length; i++) {
37178 if(day === this.disabledDays[i]){
37179 this.markInvalid(this.disabledDaysText);
37184 var fvalue = this.formatDate(value);
37185 if(this.ddMatch && this.ddMatch.test(fvalue)){
37186 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37193 // Provides logic to override the default TriggerField.validateBlur which just returns true
37194 validateBlur : function(){
37195 return !this.menu || !this.menu.isVisible();
37199 * Returns the current date value of the date field.
37200 * @return {Date} The date value
37202 getValue : function(){
37204 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37208 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37209 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37210 * (the default format used is "m/d/y").
37213 //All of these calls set the same date value (May 4, 2006)
37215 //Pass a date object:
37216 var dt = new Date('5/4/06');
37217 dateField.setValue(dt);
37219 //Pass a date string (default format):
37220 dateField.setValue('5/4/06');
37222 //Pass a date string (custom format):
37223 dateField.format = 'Y-m-d';
37224 dateField.setValue('2006-5-4');
37226 * @param {String/Date} date The date or valid date string
37228 setValue : function(date){
37229 if (this.hiddenField) {
37230 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37232 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37236 parseDate : function(value){
37237 if(!value || value instanceof Date){
37240 var v = Date.parseDate(value, this.format);
37241 if(!v && this.altFormats){
37242 if(!this.altFormatsArray){
37243 this.altFormatsArray = this.altFormats.split("|");
37245 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
37246 v = Date.parseDate(value, this.altFormatsArray[i]);
37253 formatDate : function(date, fmt){
37254 return (!date || !(date instanceof Date)) ?
37255 date : date.dateFormat(fmt || this.format);
37260 select: function(m, d){
37262 this.fireEvent('select', this, d);
37264 show : function(){ // retain focus styling
37268 this.focus.defer(10, this);
37269 var ml = this.menuListeners;
37270 this.menu.un("select", ml.select, this);
37271 this.menu.un("show", ml.show, this);
37272 this.menu.un("hide", ml.hide, this);
37277 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
37278 onTriggerClick : function(){
37282 if(this.menu == null){
37283 this.menu = new Roo.menu.DateMenu();
37285 Roo.apply(this.menu.picker, {
37286 showClear: this.allowBlank,
37287 minDate : this.minValue,
37288 maxDate : this.maxValue,
37289 disabledDatesRE : this.ddMatch,
37290 disabledDatesText : this.disabledDatesText,
37291 disabledDays : this.disabledDays,
37292 disabledDaysText : this.disabledDaysText,
37293 format : this.format,
37294 minText : String.format(this.minText, this.formatDate(this.minValue)),
37295 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
37297 this.menu.on(Roo.apply({}, this.menuListeners, {
37300 this.menu.picker.setValue(this.getValue() || new Date());
37301 this.menu.show(this.el, "tl-bl?");
37304 beforeBlur : function(){
37305 var v = this.parseDate(this.getRawValue());
37311 /** @cfg {Boolean} grow @hide */
37312 /** @cfg {Number} growMin @hide */
37313 /** @cfg {Number} growMax @hide */
37320 * Ext JS Library 1.1.1
37321 * Copyright(c) 2006-2007, Ext JS, LLC.
37323 * Originally Released Under LGPL - original licence link has changed is not relivant.
37326 * <script type="text/javascript">
37331 * @class Roo.form.ComboBox
37332 * @extends Roo.form.TriggerField
37333 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
37335 * Create a new ComboBox.
37336 * @param {Object} config Configuration options
37338 Roo.form.ComboBox = function(config){
37339 Roo.form.ComboBox.superclass.constructor.call(this, config);
37343 * Fires when the dropdown list is expanded
37344 * @param {Roo.form.ComboBox} combo This combo box
37349 * Fires when the dropdown list is collapsed
37350 * @param {Roo.form.ComboBox} combo This combo box
37354 * @event beforeselect
37355 * Fires before a list item is selected. Return false to cancel the selection.
37356 * @param {Roo.form.ComboBox} combo This combo box
37357 * @param {Roo.data.Record} record The data record returned from the underlying store
37358 * @param {Number} index The index of the selected item in the dropdown list
37360 'beforeselect' : true,
37363 * Fires when a list item is selected
37364 * @param {Roo.form.ComboBox} combo This combo box
37365 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
37366 * @param {Number} index The index of the selected item in the dropdown list
37370 * @event beforequery
37371 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
37372 * The event object passed has these properties:
37373 * @param {Roo.form.ComboBox} combo This combo box
37374 * @param {String} query The query
37375 * @param {Boolean} forceAll true to force "all" query
37376 * @param {Boolean} cancel true to cancel the query
37377 * @param {Object} e The query event object
37379 'beforequery': true,
37382 * Fires when the 'add' icon is pressed (add a listener to enable add button)
37383 * @param {Roo.form.ComboBox} combo This combo box
37388 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
37389 * @param {Roo.form.ComboBox} combo This combo box
37390 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
37396 if(this.transform){
37397 this.allowDomMove = false;
37398 var s = Roo.getDom(this.transform);
37399 if(!this.hiddenName){
37400 this.hiddenName = s.name;
37403 this.mode = 'local';
37404 var d = [], opts = s.options;
37405 for(var i = 0, len = opts.length;i < len; i++){
37407 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
37409 this.value = value;
37411 d.push([value, o.text]);
37413 this.store = new Roo.data.SimpleStore({
37415 fields: ['value', 'text'],
37418 this.valueField = 'value';
37419 this.displayField = 'text';
37421 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
37422 if(!this.lazyRender){
37423 this.target = true;
37424 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
37425 s.parentNode.removeChild(s); // remove it
37426 this.render(this.el.parentNode);
37428 s.parentNode.removeChild(s); // remove it
37433 this.store = Roo.factory(this.store, Roo.data);
37436 this.selectedIndex = -1;
37437 if(this.mode == 'local'){
37438 if(config.queryDelay === undefined){
37439 this.queryDelay = 10;
37441 if(config.minChars === undefined){
37447 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
37449 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
37452 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
37453 * rendering into an Roo.Editor, defaults to false)
37456 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
37457 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
37460 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
37463 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
37464 * the dropdown list (defaults to undefined, with no header element)
37468 * @cfg {String/Roo.Template} tpl The template to use to render the output
37472 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
37474 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
37476 listWidth: undefined,
37478 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
37479 * mode = 'remote' or 'text' if mode = 'local')
37481 displayField: undefined,
37483 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
37484 * mode = 'remote' or 'value' if mode = 'local').
37485 * Note: use of a valueField requires the user make a selection
37486 * in order for a value to be mapped.
37488 valueField: undefined,
37492 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
37493 * field's data value (defaults to the underlying DOM element's name)
37495 hiddenName: undefined,
37497 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
37501 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
37503 selectedClass: 'x-combo-selected',
37505 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37506 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
37507 * which displays a downward arrow icon).
37509 triggerClass : 'x-form-arrow-trigger',
37511 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
37515 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
37516 * anchor positions (defaults to 'tl-bl')
37518 listAlign: 'tl-bl?',
37520 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
37524 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
37525 * query specified by the allQuery config option (defaults to 'query')
37527 triggerAction: 'query',
37529 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
37530 * (defaults to 4, does not apply if editable = false)
37534 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
37535 * delay (typeAheadDelay) if it matches a known value (defaults to false)
37539 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
37540 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
37544 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
37545 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
37549 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
37550 * when editable = true (defaults to false)
37552 selectOnFocus:false,
37554 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
37556 queryParam: 'query',
37558 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
37559 * when mode = 'remote' (defaults to 'Loading...')
37561 loadingText: 'Loading...',
37563 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
37567 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
37571 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
37572 * traditional select (defaults to true)
37576 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
37580 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
37584 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
37585 * listWidth has a higher value)
37589 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
37590 * allow the user to set arbitrary text into the field (defaults to false)
37592 forceSelection:false,
37594 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
37595 * if typeAhead = true (defaults to 250)
37597 typeAheadDelay : 250,
37599 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
37600 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
37602 valueNotFoundText : undefined,
37604 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
37606 blockFocus : false,
37609 * @cfg {Boolean} disableClear Disable showing of clear button.
37611 disableClear : false,
37613 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
37615 alwaysQuery : false,
37621 // element that contains real text value.. (when hidden is used..)
37624 onRender : function(ct, position){
37625 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
37626 if(this.hiddenName){
37627 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
37629 this.hiddenField.value =
37630 this.hiddenValue !== undefined ? this.hiddenValue :
37631 this.value !== undefined ? this.value : '';
37633 // prevent input submission
37634 this.el.dom.removeAttribute('name');
37639 this.el.dom.setAttribute('autocomplete', 'off');
37642 var cls = 'x-combo-list';
37644 this.list = new Roo.Layer({
37645 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
37648 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
37649 this.list.setWidth(lw);
37650 this.list.swallowEvent('mousewheel');
37651 this.assetHeight = 0;
37654 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
37655 this.assetHeight += this.header.getHeight();
37658 this.innerList = this.list.createChild({cls:cls+'-inner'});
37659 this.innerList.on('mouseover', this.onViewOver, this);
37660 this.innerList.on('mousemove', this.onViewMove, this);
37661 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37663 if(this.allowBlank && !this.pageSize && !this.disableClear){
37664 this.footer = this.list.createChild({cls:cls+'-ft'});
37665 this.pageTb = new Roo.Toolbar(this.footer);
37669 this.footer = this.list.createChild({cls:cls+'-ft'});
37670 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
37671 {pageSize: this.pageSize});
37675 if (this.pageTb && this.allowBlank && !this.disableClear) {
37677 this.pageTb.add(new Roo.Toolbar.Fill(), {
37678 cls: 'x-btn-icon x-btn-clear',
37680 handler: function()
37683 _this.clearValue();
37684 _this.onSelect(false, -1);
37689 this.assetHeight += this.footer.getHeight();
37694 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
37697 this.view = new Roo.View(this.innerList, this.tpl, {
37698 singleSelect:true, store: this.store, selectedClass: this.selectedClass
37701 this.view.on('click', this.onViewClick, this);
37703 this.store.on('beforeload', this.onBeforeLoad, this);
37704 this.store.on('load', this.onLoad, this);
37705 this.store.on('loadexception', this.onLoadException, this);
37707 if(this.resizable){
37708 this.resizer = new Roo.Resizable(this.list, {
37709 pinned:true, handles:'se'
37711 this.resizer.on('resize', function(r, w, h){
37712 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
37713 this.listWidth = w;
37714 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
37715 this.restrictHeight();
37717 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
37719 if(!this.editable){
37720 this.editable = true;
37721 this.setEditable(false);
37725 if (typeof(this.events.add.listeners) != 'undefined') {
37727 this.addicon = this.wrap.createChild(
37728 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
37730 this.addicon.on('click', function(e) {
37731 this.fireEvent('add', this);
37734 if (typeof(this.events.edit.listeners) != 'undefined') {
37736 this.editicon = this.wrap.createChild(
37737 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
37738 if (this.addicon) {
37739 this.editicon.setStyle('margin-left', '40px');
37741 this.editicon.on('click', function(e) {
37743 // we fire even if inothing is selected..
37744 this.fireEvent('edit', this, this.lastData );
37754 initEvents : function(){
37755 Roo.form.ComboBox.superclass.initEvents.call(this);
37757 this.keyNav = new Roo.KeyNav(this.el, {
37758 "up" : function(e){
37759 this.inKeyMode = true;
37763 "down" : function(e){
37764 if(!this.isExpanded()){
37765 this.onTriggerClick();
37767 this.inKeyMode = true;
37772 "enter" : function(e){
37773 this.onViewClick();
37777 "esc" : function(e){
37781 "tab" : function(e){
37782 this.onViewClick(false);
37783 this.fireEvent("specialkey", this, e);
37789 doRelay : function(foo, bar, hname){
37790 if(hname == 'down' || this.scope.isExpanded()){
37791 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
37798 this.queryDelay = Math.max(this.queryDelay || 10,
37799 this.mode == 'local' ? 10 : 250);
37800 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
37801 if(this.typeAhead){
37802 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
37804 if(this.editable !== false){
37805 this.el.on("keyup", this.onKeyUp, this);
37807 if(this.forceSelection){
37808 this.on('blur', this.doForce, this);
37812 onDestroy : function(){
37814 this.view.setStore(null);
37815 this.view.el.removeAllListeners();
37816 this.view.el.remove();
37817 this.view.purgeListeners();
37820 this.list.destroy();
37823 this.store.un('beforeload', this.onBeforeLoad, this);
37824 this.store.un('load', this.onLoad, this);
37825 this.store.un('loadexception', this.onLoadException, this);
37827 Roo.form.ComboBox.superclass.onDestroy.call(this);
37831 fireKey : function(e){
37832 if(e.isNavKeyPress() && !this.list.isVisible()){
37833 this.fireEvent("specialkey", this, e);
37838 onResize: function(w, h){
37839 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
37841 if(typeof w != 'number'){
37842 // we do not handle it!?!?
37845 var tw = this.trigger.getWidth();
37846 tw += this.addicon ? this.addicon.getWidth() : 0;
37847 tw += this.editicon ? this.editicon.getWidth() : 0;
37849 this.el.setWidth( this.adjustWidth('input', x));
37851 this.trigger.setStyle('left', x+'px');
37853 if(this.list && this.listWidth === undefined){
37854 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
37855 this.list.setWidth(lw);
37856 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
37864 * Allow or prevent the user from directly editing the field text. If false is passed,
37865 * the user will only be able to select from the items defined in the dropdown list. This method
37866 * is the runtime equivalent of setting the 'editable' config option at config time.
37867 * @param {Boolean} value True to allow the user to directly edit the field text
37869 setEditable : function(value){
37870 if(value == this.editable){
37873 this.editable = value;
37875 this.el.dom.setAttribute('readOnly', true);
37876 this.el.on('mousedown', this.onTriggerClick, this);
37877 this.el.addClass('x-combo-noedit');
37879 this.el.dom.setAttribute('readOnly', false);
37880 this.el.un('mousedown', this.onTriggerClick, this);
37881 this.el.removeClass('x-combo-noedit');
37886 onBeforeLoad : function(){
37887 if(!this.hasFocus){
37890 this.innerList.update(this.loadingText ?
37891 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
37892 this.restrictHeight();
37893 this.selectedIndex = -1;
37897 onLoad : function(){
37898 if(!this.hasFocus){
37901 if(this.store.getCount() > 0){
37903 this.restrictHeight();
37904 if(this.lastQuery == this.allQuery){
37906 this.el.dom.select();
37908 if(!this.selectByValue(this.value, true)){
37909 this.select(0, true);
37913 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
37914 this.taTask.delay(this.typeAheadDelay);
37918 this.onEmptyResults();
37923 onLoadException : function()
37926 Roo.log(this.store.reader.jsonData);
37927 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
37928 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
37934 onTypeAhead : function(){
37935 if(this.store.getCount() > 0){
37936 var r = this.store.getAt(0);
37937 var newValue = r.data[this.displayField];
37938 var len = newValue.length;
37939 var selStart = this.getRawValue().length;
37940 if(selStart != len){
37941 this.setRawValue(newValue);
37942 this.selectText(selStart, newValue.length);
37948 onSelect : function(record, index){
37949 if(this.fireEvent('beforeselect', this, record, index) !== false){
37950 this.setFromData(index > -1 ? record.data : false);
37952 this.fireEvent('select', this, record, index);
37957 * Returns the currently selected field value or empty string if no value is set.
37958 * @return {String} value The selected value
37960 getValue : function(){
37961 if(this.valueField){
37962 return typeof this.value != 'undefined' ? this.value : '';
37964 return Roo.form.ComboBox.superclass.getValue.call(this);
37969 * Clears any text/value currently set in the field
37971 clearValue : function(){
37972 if(this.hiddenField){
37973 this.hiddenField.value = '';
37976 this.setRawValue('');
37977 this.lastSelectionText = '';
37978 this.applyEmptyText();
37982 * Sets the specified value into the field. If the value finds a match, the corresponding record text
37983 * will be displayed in the field. If the value does not match the data value of an existing item,
37984 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
37985 * Otherwise the field will be blank (although the value will still be set).
37986 * @param {String} value The value to match
37988 setValue : function(v){
37990 if(this.valueField){
37991 var r = this.findRecord(this.valueField, v);
37993 text = r.data[this.displayField];
37994 }else if(this.valueNotFoundText !== undefined){
37995 text = this.valueNotFoundText;
37998 this.lastSelectionText = text;
37999 if(this.hiddenField){
38000 this.hiddenField.value = v;
38002 Roo.form.ComboBox.superclass.setValue.call(this, text);
38006 * @property {Object} the last set data for the element
38011 * Sets the value of the field based on a object which is related to the record format for the store.
38012 * @param {Object} value the value to set as. or false on reset?
38014 setFromData : function(o){
38015 var dv = ''; // display value
38016 var vv = ''; // value value..
38018 if (this.displayField) {
38019 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
38021 // this is an error condition!!!
38022 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
38025 if(this.valueField){
38026 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
38028 if(this.hiddenField){
38029 this.hiddenField.value = vv;
38031 this.lastSelectionText = dv;
38032 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38036 // no hidden field.. - we store the value in 'value', but still display
38037 // display field!!!!
38038 this.lastSelectionText = dv;
38039 Roo.form.ComboBox.superclass.setValue.call(this, dv);
38045 reset : function(){
38046 // overridden so that last data is reset..
38047 this.setValue(this.originalValue);
38048 this.clearInvalid();
38049 this.lastData = false;
38052 findRecord : function(prop, value){
38054 if(this.store.getCount() > 0){
38055 this.store.each(function(r){
38056 if(r.data[prop] == value){
38066 getName: function()
38068 // returns hidden if it's set..
38069 if (!this.rendered) {return ''};
38070 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38074 onViewMove : function(e, t){
38075 this.inKeyMode = false;
38079 onViewOver : function(e, t){
38080 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
38083 var item = this.view.findItemFromChild(t);
38085 var index = this.view.indexOf(item);
38086 this.select(index, false);
38091 onViewClick : function(doFocus)
38093 var index = this.view.getSelectedIndexes()[0];
38094 var r = this.store.getAt(index);
38096 this.onSelect(r, index);
38098 if(doFocus !== false && !this.blockFocus){
38104 restrictHeight : function(){
38105 this.innerList.dom.style.height = '';
38106 var inner = this.innerList.dom;
38107 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
38108 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
38109 this.list.beginUpdate();
38110 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
38111 this.list.alignTo(this.el, this.listAlign);
38112 this.list.endUpdate();
38116 onEmptyResults : function(){
38121 * Returns true if the dropdown list is expanded, else false.
38123 isExpanded : function(){
38124 return this.list.isVisible();
38128 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
38129 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38130 * @param {String} value The data value of the item to select
38131 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38132 * selected item if it is not currently in view (defaults to true)
38133 * @return {Boolean} True if the value matched an item in the list, else false
38135 selectByValue : function(v, scrollIntoView){
38136 if(v !== undefined && v !== null){
38137 var r = this.findRecord(this.valueField || this.displayField, v);
38139 this.select(this.store.indexOf(r), scrollIntoView);
38147 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
38148 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
38149 * @param {Number} index The zero-based index of the list item to select
38150 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
38151 * selected item if it is not currently in view (defaults to true)
38153 select : function(index, scrollIntoView){
38154 this.selectedIndex = index;
38155 this.view.select(index);
38156 if(scrollIntoView !== false){
38157 var el = this.view.getNode(index);
38159 this.innerList.scrollChildIntoView(el, false);
38165 selectNext : function(){
38166 var ct = this.store.getCount();
38168 if(this.selectedIndex == -1){
38170 }else if(this.selectedIndex < ct-1){
38171 this.select(this.selectedIndex+1);
38177 selectPrev : function(){
38178 var ct = this.store.getCount();
38180 if(this.selectedIndex == -1){
38182 }else if(this.selectedIndex != 0){
38183 this.select(this.selectedIndex-1);
38189 onKeyUp : function(e){
38190 if(this.editable !== false && !e.isSpecialKey()){
38191 this.lastKey = e.getKey();
38192 this.dqTask.delay(this.queryDelay);
38197 validateBlur : function(){
38198 return !this.list || !this.list.isVisible();
38202 initQuery : function(){
38203 this.doQuery(this.getRawValue());
38207 doForce : function(){
38208 if(this.el.dom.value.length > 0){
38209 this.el.dom.value =
38210 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
38211 this.applyEmptyText();
38216 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
38217 * query allowing the query action to be canceled if needed.
38218 * @param {String} query The SQL query to execute
38219 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
38220 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
38221 * saved in the current store (defaults to false)
38223 doQuery : function(q, forceAll){
38224 if(q === undefined || q === null){
38229 forceAll: forceAll,
38233 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
38237 forceAll = qe.forceAll;
38238 if(forceAll === true || (q.length >= this.minChars)){
38239 if(this.lastQuery != q || this.alwaysQuery){
38240 this.lastQuery = q;
38241 if(this.mode == 'local'){
38242 this.selectedIndex = -1;
38244 this.store.clearFilter();
38246 this.store.filter(this.displayField, q);
38250 this.store.baseParams[this.queryParam] = q;
38252 params: this.getParams(q)
38257 this.selectedIndex = -1;
38264 getParams : function(q){
38266 //p[this.queryParam] = q;
38269 p.limit = this.pageSize;
38275 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
38277 collapse : function(){
38278 if(!this.isExpanded()){
38282 Roo.get(document).un('mousedown', this.collapseIf, this);
38283 Roo.get(document).un('mousewheel', this.collapseIf, this);
38284 if (!this.editable) {
38285 Roo.get(document).un('keydown', this.listKeyPress, this);
38287 this.fireEvent('collapse', this);
38291 collapseIf : function(e){
38292 if(!e.within(this.wrap) && !e.within(this.list)){
38298 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
38300 expand : function(){
38301 if(this.isExpanded() || !this.hasFocus){
38304 this.list.alignTo(this.el, this.listAlign);
38306 Roo.get(document).on('mousedown', this.collapseIf, this);
38307 Roo.get(document).on('mousewheel', this.collapseIf, this);
38308 if (!this.editable) {
38309 Roo.get(document).on('keydown', this.listKeyPress, this);
38312 this.fireEvent('expand', this);
38316 // Implements the default empty TriggerField.onTriggerClick function
38317 onTriggerClick : function(){
38321 if(this.isExpanded()){
38323 if (!this.blockFocus) {
38328 this.hasFocus = true;
38329 if(this.triggerAction == 'all') {
38330 this.doQuery(this.allQuery, true);
38332 this.doQuery(this.getRawValue());
38334 if (!this.blockFocus) {
38339 listKeyPress : function(e)
38341 //Roo.log('listkeypress');
38342 // scroll to first matching element based on key pres..
38343 if (e.isSpecialKey()) {
38346 var k = String.fromCharCode(e.getKey()).toUpperCase();
38349 var csel = this.view.getSelectedNodes();
38350 var cselitem = false;
38352 var ix = this.view.indexOf(csel[0]);
38353 cselitem = this.store.getAt(ix);
38354 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
38360 this.store.each(function(v) {
38362 // start at existing selection.
38363 if (cselitem.id == v.id) {
38369 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
38370 match = this.store.indexOf(v);
38375 if (match === false) {
38376 return true; // no more action?
38379 this.view.select(match);
38380 var sn = Roo.get(this.view.getSelectedNodes()[0])
38381 sn.scrollIntoView(sn.dom.parentNode, false);
38385 * @cfg {Boolean} grow
38389 * @cfg {Number} growMin
38393 * @cfg {Number} growMax
38402 * Ext JS Library 1.1.1
38403 * Copyright(c) 2006-2007, Ext JS, LLC.
38405 * Originally Released Under LGPL - original licence link has changed is not relivant.
38408 * <script type="text/javascript">
38411 * @class Roo.form.Checkbox
38412 * @extends Roo.form.Field
38413 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
38415 * Creates a new Checkbox
38416 * @param {Object} config Configuration options
38418 Roo.form.Checkbox = function(config){
38419 Roo.form.Checkbox.superclass.constructor.call(this, config);
38423 * Fires when the checkbox is checked or unchecked.
38424 * @param {Roo.form.Checkbox} this This checkbox
38425 * @param {Boolean} checked The new checked value
38431 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
38433 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
38435 focusClass : undefined,
38437 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
38439 fieldClass: "x-form-field",
38441 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
38445 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38446 * {tag: "input", type: "checkbox", autocomplete: "off"})
38448 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
38450 * @cfg {String} boxLabel The text that appears beside the checkbox
38454 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
38458 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
38460 valueOff: '0', // value when not checked..
38462 actionMode : 'viewEl',
38465 itemCls : 'x-menu-check-item x-form-item',
38466 groupClass : 'x-menu-group-item',
38467 inputType : 'hidden',
38470 inSetChecked: false, // check that we are not calling self...
38472 inputElement: false, // real input element?
38473 basedOn: false, // ????
38475 isFormField: true, // not sure where this is needed!!!!
38477 onResize : function(){
38478 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
38479 if(!this.boxLabel){
38480 this.el.alignTo(this.wrap, 'c-c');
38484 initEvents : function(){
38485 Roo.form.Checkbox.superclass.initEvents.call(this);
38486 this.el.on("click", this.onClick, this);
38487 this.el.on("change", this.onClick, this);
38491 getResizeEl : function(){
38495 getPositionEl : function(){
38500 onRender : function(ct, position){
38501 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
38503 if(this.inputValue !== undefined){
38504 this.el.dom.value = this.inputValue;
38507 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
38508 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
38509 var viewEl = this.wrap.createChild({
38510 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
38511 this.viewEl = viewEl;
38512 this.wrap.on('click', this.onClick, this);
38514 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
38515 this.el.on('propertychange', this.setFromHidden, this); //ie
38520 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
38521 // viewEl.on('click', this.onClick, this);
38523 //if(this.checked){
38524 this.setChecked(this.checked);
38526 //this.checked = this.el.dom;
38532 initValue : Roo.emptyFn,
38535 * Returns the checked state of the checkbox.
38536 * @return {Boolean} True if checked, else false
38538 getValue : function(){
38540 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
38542 return this.valueOff;
38547 onClick : function(){
38548 this.setChecked(!this.checked);
38550 //if(this.el.dom.checked != this.checked){
38551 // this.setValue(this.el.dom.checked);
38556 * Sets the checked state of the checkbox.
38557 * On is always based on a string comparison between inputValue and the param.
38558 * @param {Boolean/String} value - the value to set
38559 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
38561 setValue : function(v,suppressEvent){
38564 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
38565 //if(this.el && this.el.dom){
38566 // this.el.dom.checked = this.checked;
38567 // this.el.dom.defaultChecked = this.checked;
38569 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
38570 //this.fireEvent("check", this, this.checked);
38573 setChecked : function(state,suppressEvent)
38575 if (this.inSetChecked) {
38576 this.checked = state;
38582 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
38584 this.checked = state;
38585 if(suppressEvent !== true){
38586 this.fireEvent('check', this, state);
38588 this.inSetChecked = true;
38589 this.el.dom.value = state ? this.inputValue : this.valueOff;
38590 this.inSetChecked = false;
38593 // handle setting of hidden value by some other method!!?!?
38594 setFromHidden: function()
38599 //console.log("SET FROM HIDDEN");
38600 //alert('setFrom hidden');
38601 this.setValue(this.el.dom.value);
38604 onDestroy : function()
38607 Roo.get(this.viewEl).remove();
38610 Roo.form.Checkbox.superclass.onDestroy.call(this);
38615 * Ext JS Library 1.1.1
38616 * Copyright(c) 2006-2007, Ext JS, LLC.
38618 * Originally Released Under LGPL - original licence link has changed is not relivant.
38621 * <script type="text/javascript">
38625 * @class Roo.form.Radio
38626 * @extends Roo.form.Checkbox
38627 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
38628 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
38630 * Creates a new Radio
38631 * @param {Object} config Configuration options
38633 Roo.form.Radio = function(){
38634 Roo.form.Radio.superclass.constructor.apply(this, arguments);
38636 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
38637 inputType: 'radio',
38640 * If this radio is part of a group, it will return the selected value
38643 getGroupValue : function(){
38644 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
38646 });//<script type="text/javascript">
38649 * Ext JS Library 1.1.1
38650 * Copyright(c) 2006-2007, Ext JS, LLC.
38651 * licensing@extjs.com
38653 * http://www.extjs.com/license
38659 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
38660 * - IE ? - no idea how much works there.
38668 * @class Ext.form.HtmlEditor
38669 * @extends Ext.form.Field
38670 * Provides a lightweight HTML Editor component.
38672 * This has been tested on Fireforx / Chrome.. IE may not be so great..
38674 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
38675 * supported by this editor.</b><br/><br/>
38676 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
38677 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
38679 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
38681 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
38685 * @cfg {String} createLinkText The default text for the create link prompt
38687 createLinkText : 'Please enter the URL for the link:',
38689 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
38691 defaultLinkValue : 'http:/'+'/',
38694 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
38699 * @cfg {Number} height (in pixels)
38703 * @cfg {Number} width (in pixels)
38708 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
38711 stylesheets: false,
38716 // private properties
38717 validationEvent : false,
38719 initialized : false,
38721 sourceEditMode : false,
38722 onFocus : Roo.emptyFn,
38724 hideMode:'offsets',
38726 defaultAutoCreate : { // modified by initCompnoent..
38728 style:"width:500px;height:300px;",
38729 autocomplete: "off"
38733 initComponent : function(){
38736 * @event initialize
38737 * Fires when the editor is fully initialized (including the iframe)
38738 * @param {HtmlEditor} this
38743 * Fires when the editor is first receives the focus. Any insertion must wait
38744 * until after this event.
38745 * @param {HtmlEditor} this
38749 * @event beforesync
38750 * Fires before the textarea is updated with content from the editor iframe. Return false
38751 * to cancel the sync.
38752 * @param {HtmlEditor} this
38753 * @param {String} html
38757 * @event beforepush
38758 * Fires before the iframe editor is updated with content from the textarea. Return false
38759 * to cancel the push.
38760 * @param {HtmlEditor} this
38761 * @param {String} html
38766 * Fires when the textarea is updated with content from the editor iframe.
38767 * @param {HtmlEditor} this
38768 * @param {String} html
38773 * Fires when the iframe editor is updated with content from the textarea.
38774 * @param {HtmlEditor} this
38775 * @param {String} html
38779 * @event editmodechange
38780 * Fires when the editor switches edit modes
38781 * @param {HtmlEditor} this
38782 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
38784 editmodechange: true,
38786 * @event editorevent
38787 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
38788 * @param {HtmlEditor} this
38792 this.defaultAutoCreate = {
38794 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
38795 autocomplete: "off"
38800 * Protected method that will not generally be called directly. It
38801 * is called when the editor creates its toolbar. Override this method if you need to
38802 * add custom toolbar buttons.
38803 * @param {HtmlEditor} editor
38805 createToolbar : function(editor){
38806 if (!editor.toolbars || !editor.toolbars.length) {
38807 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
38810 for (var i =0 ; i < editor.toolbars.length;i++) {
38811 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
38812 editor.toolbars[i].init(editor);
38819 * Protected method that will not generally be called directly. It
38820 * is called when the editor initializes the iframe with HTML contents. Override this method if you
38821 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
38823 getDocMarkup : function(){
38826 if (this.stylesheets === false) {
38828 Roo.get(document.head).select('style').each(function(node) {
38829 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38832 Roo.get(document.head).select('link').each(function(node) {
38833 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
38836 } else if (!this.stylesheets.length) {
38838 st = '<style type="text/css">' +
38839 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38842 Roo.each(this.stylesheets, function(s) {
38843 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
38848 st += '<style type="text/css">' +
38849 'IMG { cursor: pointer } ' +
38853 return '<html><head>' + st +
38854 //<style type="text/css">' +
38855 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
38857 ' </head><body></body></html>';
38861 onRender : function(ct, position)
38864 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
38865 this.el.dom.style.border = '0 none';
38866 this.el.dom.setAttribute('tabIndex', -1);
38867 this.el.addClass('x-hidden');
38868 if(Roo.isIE){ // fix IE 1px bogus margin
38869 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
38871 this.wrap = this.el.wrap({
38872 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
38875 if (this.resizable) {
38876 this.resizeEl = new Roo.Resizable(this.wrap, {
38880 minHeight : this.height,
38881 height: this.height,
38882 handles : this.resizable,
38885 resize : function(r, w, h) {
38886 _t.onResize(w,h); // -something
38893 this.frameId = Roo.id();
38895 this.createToolbar(this);
38899 var iframe = this.wrap.createChild({
38902 name: this.frameId,
38903 frameBorder : 'no',
38904 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
38908 // console.log(iframe);
38909 //this.wrap.dom.appendChild(iframe);
38911 this.iframe = iframe.dom;
38913 this.assignDocWin();
38915 this.doc.designMode = 'on';
38918 this.doc.write(this.getDocMarkup());
38922 var task = { // must defer to wait for browser to be ready
38924 //console.log("run task?" + this.doc.readyState);
38925 this.assignDocWin();
38926 if(this.doc.body || this.doc.readyState == 'complete'){
38928 this.doc.designMode="on";
38932 Roo.TaskMgr.stop(task);
38933 this.initEditor.defer(10, this);
38940 Roo.TaskMgr.start(task);
38943 this.setSize(this.wrap.getSize());
38945 if (this.resizeEl) {
38946 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
38947 // should trigger onReize..
38952 onResize : function(w, h)
38954 //Roo.log('resize: ' +w + ',' + h );
38955 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
38956 if(this.el && this.iframe){
38957 if(typeof w == 'number'){
38958 var aw = w - this.wrap.getFrameWidth('lr');
38959 this.el.setWidth(this.adjustWidth('textarea', aw));
38960 this.iframe.style.width = aw + 'px';
38962 if(typeof h == 'number'){
38964 for (var i =0; i < this.toolbars.length;i++) {
38965 // fixme - ask toolbars for heights?
38966 tbh += this.toolbars[i].tb.el.getHeight();
38967 if (this.toolbars[i].footer) {
38968 tbh += this.toolbars[i].footer.el.getHeight();
38975 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
38976 ah -= 5; // knock a few pixes off for look..
38977 this.el.setHeight(this.adjustWidth('textarea', ah));
38978 this.iframe.style.height = ah + 'px';
38980 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
38987 * Toggles the editor between standard and source edit mode.
38988 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
38990 toggleSourceEdit : function(sourceEditMode){
38992 this.sourceEditMode = sourceEditMode === true;
38994 if(this.sourceEditMode){
38997 this.iframe.className = 'x-hidden';
38998 this.el.removeClass('x-hidden');
38999 this.el.dom.removeAttribute('tabIndex');
39004 this.iframe.className = '';
39005 this.el.addClass('x-hidden');
39006 this.el.dom.setAttribute('tabIndex', -1);
39009 this.setSize(this.wrap.getSize());
39010 this.fireEvent('editmodechange', this, this.sourceEditMode);
39013 // private used internally
39014 createLink : function(){
39015 var url = prompt(this.createLinkText, this.defaultLinkValue);
39016 if(url && url != 'http:/'+'/'){
39017 this.relayCmd('createlink', url);
39021 // private (for BoxComponent)
39022 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39024 // private (for BoxComponent)
39025 getResizeEl : function(){
39029 // private (for BoxComponent)
39030 getPositionEl : function(){
39035 initEvents : function(){
39036 this.originalValue = this.getValue();
39040 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
39043 markInvalid : Roo.emptyFn,
39045 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
39048 clearInvalid : Roo.emptyFn,
39050 setValue : function(v){
39051 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
39056 * Protected method that will not generally be called directly. If you need/want
39057 * custom HTML cleanup, this is the method you should override.
39058 * @param {String} html The HTML to be cleaned
39059 * return {String} The cleaned HTML
39061 cleanHtml : function(html){
39062 html = String(html);
39063 if(html.length > 5){
39064 if(Roo.isSafari){ // strip safari nonsense
39065 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
39068 if(html == ' '){
39075 * Protected method that will not generally be called directly. Syncs the contents
39076 * of the editor iframe with the textarea.
39078 syncValue : function(){
39079 if(this.initialized){
39080 var bd = (this.doc.body || this.doc.documentElement);
39081 //this.cleanUpPaste(); -- this is done else where and causes havoc..
39082 var html = bd.innerHTML;
39084 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
39085 var m = bs.match(/text-align:(.*?);/i);
39087 html = '<div style="'+m[0]+'">' + html + '</div>';
39090 html = this.cleanHtml(html);
39091 // fix up the special chars..
39092 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
39093 return "&#"+b.charCodeAt()+";"
39095 if(this.fireEvent('beforesync', this, html) !== false){
39096 this.el.dom.value = html;
39097 this.fireEvent('sync', this, html);
39103 * Protected method that will not generally be called directly. Pushes the value of the textarea
39104 * into the iframe editor.
39106 pushValue : function(){
39107 if(this.initialized){
39108 var v = this.el.dom.value;
39113 if(this.fireEvent('beforepush', this, v) !== false){
39114 var d = (this.doc.body || this.doc.documentElement);
39116 this.cleanUpPaste();
39117 this.el.dom.value = d.innerHTML;
39118 this.fireEvent('push', this, v);
39124 deferFocus : function(){
39125 this.focus.defer(10, this);
39129 focus : function(){
39130 if(this.win && !this.sourceEditMode){
39137 assignDocWin: function()
39139 var iframe = this.iframe;
39142 this.doc = iframe.contentWindow.document;
39143 this.win = iframe.contentWindow;
39145 if (!Roo.get(this.frameId)) {
39148 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
39149 this.win = Roo.get(this.frameId).dom.contentWindow;
39154 initEditor : function(){
39155 //console.log("INIT EDITOR");
39156 this.assignDocWin();
39160 this.doc.designMode="on";
39162 this.doc.write(this.getDocMarkup());
39165 var dbody = (this.doc.body || this.doc.documentElement);
39166 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
39167 // this copies styles from the containing element into thsi one..
39168 // not sure why we need all of this..
39169 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
39170 ss['background-attachment'] = 'fixed'; // w3c
39171 dbody.bgProperties = 'fixed'; // ie
39172 Roo.DomHelper.applyStyles(dbody, ss);
39173 Roo.EventManager.on(this.doc, {
39174 //'mousedown': this.onEditorEvent,
39175 'mouseup': this.onEditorEvent,
39176 'dblclick': this.onEditorEvent,
39177 'click': this.onEditorEvent,
39178 'keyup': this.onEditorEvent,
39183 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
39185 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
39186 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
39188 this.initialized = true;
39190 this.fireEvent('initialize', this);
39195 onDestroy : function(){
39201 for (var i =0; i < this.toolbars.length;i++) {
39202 // fixme - ask toolbars for heights?
39203 this.toolbars[i].onDestroy();
39206 this.wrap.dom.innerHTML = '';
39207 this.wrap.remove();
39212 onFirstFocus : function(){
39214 this.assignDocWin();
39217 this.activated = true;
39218 for (var i =0; i < this.toolbars.length;i++) {
39219 this.toolbars[i].onFirstFocus();
39222 if(Roo.isGecko){ // prevent silly gecko errors
39224 var s = this.win.getSelection();
39225 if(!s.focusNode || s.focusNode.nodeType != 3){
39226 var r = s.getRangeAt(0);
39227 r.selectNodeContents((this.doc.body || this.doc.documentElement));
39232 this.execCmd('useCSS', true);
39233 this.execCmd('styleWithCSS', false);
39236 this.fireEvent('activate', this);
39240 adjustFont: function(btn){
39241 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
39242 //if(Roo.isSafari){ // safari
39245 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
39246 if(Roo.isSafari){ // safari
39247 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
39248 v = (v < 10) ? 10 : v;
39249 v = (v > 48) ? 48 : v;
39250 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
39255 v = Math.max(1, v+adjust);
39257 this.execCmd('FontSize', v );
39260 onEditorEvent : function(e){
39261 this.fireEvent('editorevent', this, e);
39262 // this.updateToolbar();
39263 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
39266 insertTag : function(tg)
39268 // could be a bit smarter... -> wrap the current selected tRoo..
39270 this.execCmd("formatblock", tg);
39274 insertText : function(txt)
39278 range = this.createRange();
39279 range.deleteContents();
39280 //alert(Sender.getAttribute('label'));
39282 range.insertNode(this.doc.createTextNode(txt));
39286 relayBtnCmd : function(btn){
39287 this.relayCmd(btn.cmd);
39291 * Executes a Midas editor command on the editor document and performs necessary focus and
39292 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
39293 * @param {String} cmd The Midas command
39294 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39296 relayCmd : function(cmd, value){
39298 this.execCmd(cmd, value);
39299 this.fireEvent('editorevent', this);
39300 //this.updateToolbar();
39305 * Executes a Midas editor command directly on the editor document.
39306 * For visual commands, you should use {@link #relayCmd} instead.
39307 * <b>This should only be called after the editor is initialized.</b>
39308 * @param {String} cmd The Midas command
39309 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
39311 execCmd : function(cmd, value){
39312 this.doc.execCommand(cmd, false, value === undefined ? null : value);
39319 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
39321 * @param {String} text | dom node..
39323 insertAtCursor : function(text)
39328 if(!this.activated){
39334 var r = this.doc.selection.createRange();
39345 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
39349 // from jquery ui (MIT licenced)
39351 var win = this.win;
39353 if (win.getSelection && win.getSelection().getRangeAt) {
39354 range = win.getSelection().getRangeAt(0);
39355 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
39356 range.insertNode(node);
39357 } else if (win.document.selection && win.document.selection.createRange) {
39358 // no firefox support
39359 var txt = typeof(text) == 'string' ? text : text.outerHTML;
39360 win.document.selection.createRange().pasteHTML(txt);
39362 // no firefox support
39363 var txt = typeof(text) == 'string' ? text : text.outerHTML;
39364 this.execCmd('InsertHTML', txt);
39373 mozKeyPress : function(e){
39375 var c = e.getCharCode(), cmd;
39378 c = String.fromCharCode(c).toLowerCase();
39392 this.cleanUpPaste.defer(100, this);
39400 e.preventDefault();
39408 fixKeys : function(){ // load time branching for fastest keydown performance
39410 return function(e){
39411 var k = e.getKey(), r;
39414 r = this.doc.selection.createRange();
39417 r.pasteHTML('    ');
39424 r = this.doc.selection.createRange();
39426 var target = r.parentElement();
39427 if(!target || target.tagName.toLowerCase() != 'li'){
39429 r.pasteHTML('<br />');
39435 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39436 this.cleanUpPaste.defer(100, this);
39442 }else if(Roo.isOpera){
39443 return function(e){
39444 var k = e.getKey();
39448 this.execCmd('InsertHTML','    ');
39451 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39452 this.cleanUpPaste.defer(100, this);
39457 }else if(Roo.isSafari){
39458 return function(e){
39459 var k = e.getKey();
39463 this.execCmd('InsertText','\t');
39467 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
39468 this.cleanUpPaste.defer(100, this);
39476 getAllAncestors: function()
39478 var p = this.getSelectedNode();
39481 a.push(p); // push blank onto stack..
39482 p = this.getParentElement();
39486 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
39490 a.push(this.doc.body);
39494 lastSelNode : false,
39497 getSelection : function()
39499 this.assignDocWin();
39500 return Roo.isIE ? this.doc.selection : this.win.getSelection();
39503 getSelectedNode: function()
39505 // this may only work on Gecko!!!
39507 // should we cache this!!!!
39512 var range = this.createRange(this.getSelection()).cloneRange();
39515 var parent = range.parentElement();
39517 var testRange = range.duplicate();
39518 testRange.moveToElementText(parent);
39519 if (testRange.inRange(range)) {
39522 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
39525 parent = parent.parentElement;
39530 // is ancestor a text element.
39531 var ac = range.commonAncestorContainer;
39532 if (ac.nodeType == 3) {
39533 ac = ac.parentNode;
39536 var ar = ac.childNodes;
39539 var other_nodes = [];
39540 var has_other_nodes = false;
39541 for (var i=0;i<ar.length;i++) {
39542 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
39545 // fullly contained node.
39547 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
39552 // probably selected..
39553 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
39554 other_nodes.push(ar[i]);
39558 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
39563 has_other_nodes = true;
39565 if (!nodes.length && other_nodes.length) {
39566 nodes= other_nodes;
39568 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
39574 createRange: function(sel)
39576 // this has strange effects when using with
39577 // top toolbar - not sure if it's a great idea.
39578 //this.editor.contentWindow.focus();
39579 if (typeof sel != "undefined") {
39581 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
39583 return this.doc.createRange();
39586 return this.doc.createRange();
39589 getParentElement: function()
39592 this.assignDocWin();
39593 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
39595 var range = this.createRange(sel);
39598 var p = range.commonAncestorContainer;
39599 while (p.nodeType == 3) { // text node
39610 * Range intersection.. the hard stuff...
39614 * [ -- selected range --- ]
39618 * if end is before start or hits it. fail.
39619 * if start is after end or hits it fail.
39621 * if either hits (but other is outside. - then it's not
39627 // @see http://www.thismuchiknow.co.uk/?p=64.
39628 rangeIntersectsNode : function(range, node)
39630 var nodeRange = node.ownerDocument.createRange();
39632 nodeRange.selectNode(node);
39634 nodeRange.selectNodeContents(node);
39637 var rangeStartRange = range.cloneRange();
39638 rangeStartRange.collapse(true);
39640 var rangeEndRange = range.cloneRange();
39641 rangeEndRange.collapse(false);
39643 var nodeStartRange = nodeRange.cloneRange();
39644 nodeStartRange.collapse(true);
39646 var nodeEndRange = nodeRange.cloneRange();
39647 nodeEndRange.collapse(false);
39649 return rangeStartRange.compareBoundaryPoints(
39650 Range.START_TO_START, nodeEndRange) == -1 &&
39651 rangeEndRange.compareBoundaryPoints(
39652 Range.START_TO_START, nodeStartRange) == 1;
39656 rangeCompareNode : function(range, node)
39658 var nodeRange = node.ownerDocument.createRange();
39660 nodeRange.selectNode(node);
39662 nodeRange.selectNodeContents(node);
39666 range.collapse(true);
39668 nodeRange.collapse(true);
39670 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
39671 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
39673 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
39675 var nodeIsBefore = ss == 1;
39676 var nodeIsAfter = ee == -1;
39678 if (nodeIsBefore && nodeIsAfter)
39680 if (!nodeIsBefore && nodeIsAfter)
39681 return 1; //right trailed.
39683 if (nodeIsBefore && !nodeIsAfter)
39684 return 2; // left trailed.
39689 // private? - in a new class?
39690 cleanUpPaste : function()
39692 // cleans up the whole document..
39693 Roo.log('cleanuppaste');
39694 this.cleanUpChildren(this.doc.body);
39695 var clean = this.cleanWordChars(this.doc.body.innerHTML);
39696 if (clean != this.doc.body.innerHTML) {
39697 this.doc.body.innerHTML = clean;
39702 cleanWordChars : function(input) {
39703 var he = Roo.form.HtmlEditor;
39705 var output = input;
39706 Roo.each(he.swapCodes, function(sw) {
39708 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
39709 output = output.replace(swapper, sw[1]);
39715 cleanUpChildren : function (n)
39717 if (!n.childNodes.length) {
39720 for (var i = n.childNodes.length-1; i > -1 ; i--) {
39721 this.cleanUpChild(n.childNodes[i]);
39728 cleanUpChild : function (node)
39730 //console.log(node);
39731 if (node.nodeName == "#text") {
39732 // clean up silly Windows -- stuff?
39735 if (node.nodeName == "#comment") {
39736 node.parentNode.removeChild(node);
39737 // clean up silly Windows -- stuff?
39741 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
39743 node.parentNode.removeChild(node);
39748 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
39750 // remove <a name=....> as rendering on yahoo mailer is bored with this.
39752 if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
39753 remove_keep_children = true;
39756 if (remove_keep_children) {
39757 this.cleanUpChildren(node);
39758 // inserts everything just before this node...
39759 while (node.childNodes.length) {
39760 var cn = node.childNodes[0];
39761 node.removeChild(cn);
39762 node.parentNode.insertBefore(cn, node);
39764 node.parentNode.removeChild(node);
39768 if (!node.attributes || !node.attributes.length) {
39769 this.cleanUpChildren(node);
39773 function cleanAttr(n,v)
39776 if (v.match(/^\./) || v.match(/^\//)) {
39779 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
39782 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
39783 node.removeAttribute(n);
39787 function cleanStyle(n,v)
39789 if (v.match(/expression/)) { //XSS?? should we even bother..
39790 node.removeAttribute(n);
39795 var parts = v.split(/;/);
39796 Roo.each(parts, function(p) {
39797 p = p.replace(/\s+/g,'');
39801 var l = p.split(':').shift().replace(/\s+/g,'');
39803 // only allow 'c whitelisted system attributes'
39804 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
39805 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
39806 node.removeAttribute(n);
39816 for (var i = node.attributes.length-1; i > -1 ; i--) {
39817 var a = node.attributes[i];
39819 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
39820 node.removeAttribute(a.name);
39823 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
39824 cleanAttr(a.name,a.value); // fixme..
39827 if (a.name == 'style') {
39828 cleanStyle(a.name,a.value);
39830 /// clean up MS crap..
39831 // tecnically this should be a list of valid class'es..
39834 if (a.name == 'class') {
39835 if (a.value.match(/^Mso/)) {
39836 node.className = '';
39839 if (a.value.match(/body/)) {
39840 node.className = '';
39850 this.cleanUpChildren(node);
39856 // hide stuff that is not compatible
39870 * @event specialkey
39874 * @cfg {String} fieldClass @hide
39877 * @cfg {String} focusClass @hide
39880 * @cfg {String} autoCreate @hide
39883 * @cfg {String} inputType @hide
39886 * @cfg {String} invalidClass @hide
39889 * @cfg {String} invalidText @hide
39892 * @cfg {String} msgFx @hide
39895 * @cfg {String} validateOnBlur @hide
39899 Roo.form.HtmlEditor.white = [
39900 'area', 'br', 'img', 'input', 'hr', 'wbr',
39902 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
39903 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
39904 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
39905 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
39906 'table', 'ul', 'xmp',
39908 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
39911 'dir', 'menu', 'ol', 'ul', 'dl',
39917 Roo.form.HtmlEditor.black = [
39918 // 'embed', 'object', // enable - backend responsiblity to clean thiese
39920 'base', 'basefont', 'bgsound', 'blink', 'body',
39921 'frame', 'frameset', 'head', 'html', 'ilayer',
39922 'iframe', 'layer', 'link', 'meta', 'object',
39923 'script', 'style' ,'title', 'xml' // clean later..
39925 Roo.form.HtmlEditor.clean = [
39926 'script', 'style', 'title', 'xml'
39928 Roo.form.HtmlEditor.remove = [
39933 Roo.form.HtmlEditor.ablack = [
39937 Roo.form.HtmlEditor.aclean = [
39938 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
39942 Roo.form.HtmlEditor.pwhite= [
39943 'http', 'https', 'mailto'
39946 // white listed style attributes.
39947 Roo.form.HtmlEditor.cwhite= [
39953 Roo.form.HtmlEditor.swapCodes =[
39964 // <script type="text/javascript">
39967 * Ext JS Library 1.1.1
39968 * Copyright(c) 2006-2007, Ext JS, LLC.
39974 * @class Roo.form.HtmlEditorToolbar1
39979 new Roo.form.HtmlEditor({
39982 new Roo.form.HtmlEditorToolbar1({
39983 disable : { fonts: 1 , format: 1, ..., ... , ...],
39989 * @cfg {Object} disable List of elements to disable..
39990 * @cfg {Array} btns List of additional buttons.
39994 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
39997 Roo.form.HtmlEditor.ToolbarStandard = function(config)
40000 Roo.apply(this, config);
40002 // default disabled, based on 'good practice'..
40003 this.disable = this.disable || {};
40004 Roo.applyIf(this.disable, {
40007 specialElements : true
40011 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40012 // dont call parent... till later.
40015 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
40023 * @cfg {Object} disable List of toolbar elements to disable
40028 * @cfg {Array} fontFamilies An array of available font families
40046 // "á" , ?? a acute?
40051 "°" // , // degrees
40053 // "é" , // e ecute
40054 // "ú" , // u ecute?
40057 specialElements : [
40059 text: "Insert Table",
40062 ihtml : '<table><tr><td>Cell</td></tr></table>'
40066 text: "Insert Image",
40069 ihtml : '<img src="about:blank"/>'
40078 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
40079 "input:submit", "input:button", "select", "textarea", "label" ],
40082 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
40084 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
40087 * @cfg {String} defaultFont default font to use.
40089 defaultFont: 'tahoma',
40091 fontSelect : false,
40094 formatCombo : false,
40096 init : function(editor)
40098 this.editor = editor;
40101 var fid = editor.frameId;
40103 function btn(id, toggle, handler){
40104 var xid = fid + '-'+ id ;
40108 cls : 'x-btn-icon x-edit-'+id,
40109 enableToggle:toggle !== false,
40110 scope: editor, // was editor...
40111 handler:handler||editor.relayBtnCmd,
40112 clickEvent:'mousedown',
40113 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40120 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
40122 // stop form submits
40123 tb.el.on('click', function(e){
40124 e.preventDefault(); // what does this do?
40127 if(!this.disable.font && !Roo.isSafari){
40128 /* why no safari for fonts
40129 editor.fontSelect = tb.el.createChild({
40132 cls:'x-font-select',
40133 html: editor.createFontOptions()
40135 editor.fontSelect.on('change', function(){
40136 var font = editor.fontSelect.dom.value;
40137 editor.relayCmd('fontname', font);
40138 editor.deferFocus();
40141 editor.fontSelect.dom,
40146 if(!this.disable.formats){
40147 this.formatCombo = new Roo.form.ComboBox({
40148 store: new Roo.data.SimpleStore({
40151 data : this.formats // from states.js
40154 //autoCreate : {tag: "div", size: "20"},
40155 displayField:'tag',
40159 triggerAction: 'all',
40160 emptyText:'Add tag',
40161 selectOnFocus:true,
40164 'select': function(c, r, i) {
40165 editor.insertTag(r.get('tag'));
40171 tb.addField(this.formatCombo);
40175 if(!this.disable.format){
40182 if(!this.disable.fontSize){
40187 btn('increasefontsize', false, editor.adjustFont),
40188 btn('decreasefontsize', false, editor.adjustFont)
40193 if(!this.disable.colors){
40196 id:editor.frameId +'-forecolor',
40197 cls:'x-btn-icon x-edit-forecolor',
40198 clickEvent:'mousedown',
40199 tooltip: this.buttonTips['forecolor'] || undefined,
40201 menu : new Roo.menu.ColorMenu({
40202 allowReselect: true,
40203 focus: Roo.emptyFn,
40206 selectHandler: function(cp, color){
40207 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
40208 editor.deferFocus();
40211 clickEvent:'mousedown'
40214 id:editor.frameId +'backcolor',
40215 cls:'x-btn-icon x-edit-backcolor',
40216 clickEvent:'mousedown',
40217 tooltip: this.buttonTips['backcolor'] || undefined,
40219 menu : new Roo.menu.ColorMenu({
40220 focus: Roo.emptyFn,
40223 allowReselect: true,
40224 selectHandler: function(cp, color){
40226 editor.execCmd('useCSS', false);
40227 editor.execCmd('hilitecolor', color);
40228 editor.execCmd('useCSS', true);
40229 editor.deferFocus();
40231 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
40232 Roo.isSafari || Roo.isIE ? '#'+color : color);
40233 editor.deferFocus();
40237 clickEvent:'mousedown'
40242 // now add all the items...
40245 if(!this.disable.alignments){
40248 btn('justifyleft'),
40249 btn('justifycenter'),
40250 btn('justifyright')
40254 //if(!Roo.isSafari){
40255 if(!this.disable.links){
40258 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
40262 if(!this.disable.lists){
40265 btn('insertorderedlist'),
40266 btn('insertunorderedlist')
40269 if(!this.disable.sourceEdit){
40272 btn('sourceedit', true, function(btn){
40273 this.toggleSourceEdit(btn.pressed);
40280 // special menu.. - needs to be tidied up..
40281 if (!this.disable.special) {
40284 cls: 'x-edit-none',
40290 for (var i =0; i < this.specialChars.length; i++) {
40291 smenu.menu.items.push({
40293 html: this.specialChars[i],
40294 handler: function(a,b) {
40295 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
40296 //editor.insertAtCursor(a.html);
40309 if (!this.disable.specialElements) {
40312 cls: 'x-edit-none',
40317 for (var i =0; i < this.specialElements.length; i++) {
40318 semenu.menu.items.push(
40320 handler: function(a,b) {
40321 editor.insertAtCursor(this.ihtml);
40323 }, this.specialElements[i])
40335 for(var i =0; i< this.btns.length;i++) {
40336 var b = this.btns[i];
40337 b.cls = 'x-edit-none';
40346 // disable everything...
40348 this.tb.items.each(function(item){
40349 if(item.id != editor.frameId+ '-sourceedit'){
40353 this.rendered = true;
40355 // the all the btns;
40356 editor.on('editorevent', this.updateToolbar, this);
40357 // other toolbars need to implement this..
40358 //editor.on('editmodechange', this.updateToolbar, this);
40364 * Protected method that will not generally be called directly. It triggers
40365 * a toolbar update by reading the markup state of the current selection in the editor.
40367 updateToolbar: function(){
40369 if(!this.editor.activated){
40370 this.editor.onFirstFocus();
40374 var btns = this.tb.items.map,
40375 doc = this.editor.doc,
40376 frameId = this.editor.frameId;
40378 if(!this.disable.font && !Roo.isSafari){
40380 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
40381 if(name != this.fontSelect.dom.value){
40382 this.fontSelect.dom.value = name;
40386 if(!this.disable.format){
40387 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
40388 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
40389 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
40391 if(!this.disable.alignments){
40392 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
40393 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
40394 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
40396 if(!Roo.isSafari && !this.disable.lists){
40397 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
40398 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
40401 var ans = this.editor.getAllAncestors();
40402 if (this.formatCombo) {
40405 var store = this.formatCombo.store;
40406 this.formatCombo.setValue("");
40407 for (var i =0; i < ans.length;i++) {
40408 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
40410 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
40418 // hides menus... - so this cant be on a menu...
40419 Roo.menu.MenuMgr.hideAll();
40421 //this.editorsyncValue();
40425 createFontOptions : function(){
40426 var buf = [], fs = this.fontFamilies, ff, lc;
40427 for(var i = 0, len = fs.length; i< len; i++){
40429 lc = ff.toLowerCase();
40431 '<option value="',lc,'" style="font-family:',ff,';"',
40432 (this.defaultFont == lc ? ' selected="true">' : '>'),
40437 return buf.join('');
40440 toggleSourceEdit : function(sourceEditMode){
40441 if(sourceEditMode === undefined){
40442 sourceEditMode = !this.sourceEditMode;
40444 this.sourceEditMode = sourceEditMode === true;
40445 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
40446 // just toggle the button?
40447 if(btn.pressed !== this.editor.sourceEditMode){
40448 btn.toggle(this.editor.sourceEditMode);
40452 if(this.sourceEditMode){
40453 this.tb.items.each(function(item){
40454 if(item.cmd != 'sourceedit'){
40460 if(this.initialized){
40461 this.tb.items.each(function(item){
40467 // tell the editor that it's been pressed..
40468 this.editor.toggleSourceEdit(sourceEditMode);
40472 * Object collection of toolbar tooltips for the buttons in the editor. The key
40473 * is the command id associated with that button and the value is a valid QuickTips object.
40478 title: 'Bold (Ctrl+B)',
40479 text: 'Make the selected text bold.',
40480 cls: 'x-html-editor-tip'
40483 title: 'Italic (Ctrl+I)',
40484 text: 'Make the selected text italic.',
40485 cls: 'x-html-editor-tip'
40493 title: 'Bold (Ctrl+B)',
40494 text: 'Make the selected text bold.',
40495 cls: 'x-html-editor-tip'
40498 title: 'Italic (Ctrl+I)',
40499 text: 'Make the selected text italic.',
40500 cls: 'x-html-editor-tip'
40503 title: 'Underline (Ctrl+U)',
40504 text: 'Underline the selected text.',
40505 cls: 'x-html-editor-tip'
40507 increasefontsize : {
40508 title: 'Grow Text',
40509 text: 'Increase the font size.',
40510 cls: 'x-html-editor-tip'
40512 decreasefontsize : {
40513 title: 'Shrink Text',
40514 text: 'Decrease the font size.',
40515 cls: 'x-html-editor-tip'
40518 title: 'Text Highlight Color',
40519 text: 'Change the background color of the selected text.',
40520 cls: 'x-html-editor-tip'
40523 title: 'Font Color',
40524 text: 'Change the color of the selected text.',
40525 cls: 'x-html-editor-tip'
40528 title: 'Align Text Left',
40529 text: 'Align text to the left.',
40530 cls: 'x-html-editor-tip'
40533 title: 'Center Text',
40534 text: 'Center text in the editor.',
40535 cls: 'x-html-editor-tip'
40538 title: 'Align Text Right',
40539 text: 'Align text to the right.',
40540 cls: 'x-html-editor-tip'
40542 insertunorderedlist : {
40543 title: 'Bullet List',
40544 text: 'Start a bulleted list.',
40545 cls: 'x-html-editor-tip'
40547 insertorderedlist : {
40548 title: 'Numbered List',
40549 text: 'Start a numbered list.',
40550 cls: 'x-html-editor-tip'
40553 title: 'Hyperlink',
40554 text: 'Make the selected text a hyperlink.',
40555 cls: 'x-html-editor-tip'
40558 title: 'Source Edit',
40559 text: 'Switch to source editing mode.',
40560 cls: 'x-html-editor-tip'
40564 onDestroy : function(){
40567 this.tb.items.each(function(item){
40569 item.menu.removeAll();
40571 item.menu.el.destroy();
40579 onFirstFocus: function() {
40580 this.tb.items.each(function(item){
40589 // <script type="text/javascript">
40592 * Ext JS Library 1.1.1
40593 * Copyright(c) 2006-2007, Ext JS, LLC.
40600 * @class Roo.form.HtmlEditor.ToolbarContext
40605 new Roo.form.HtmlEditor({
40608 { xtype: 'ToolbarStandard', styles : {} }
40609 { xtype: 'ToolbarContext', disable : {} }
40615 * @config : {Object} disable List of elements to disable.. (not done yet.)
40616 * @config : {Object} styles Map of styles available.
40620 Roo.form.HtmlEditor.ToolbarContext = function(config)
40623 Roo.apply(this, config);
40624 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
40625 // dont call parent... till later.
40626 this.styles = this.styles || {};
40628 Roo.form.HtmlEditor.ToolbarContext.types = {
40640 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
40702 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
40707 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
40761 // should we really allow this??
40762 // should this just be
40777 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
40785 * @cfg {Object} disable List of toolbar elements to disable
40790 * @cfg {Object} styles List of styles
40791 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
40793 * These must be defined in the page, so they get rendered correctly..
40804 init : function(editor)
40806 this.editor = editor;
40809 var fid = editor.frameId;
40811 function btn(id, toggle, handler){
40812 var xid = fid + '-'+ id ;
40816 cls : 'x-btn-icon x-edit-'+id,
40817 enableToggle:toggle !== false,
40818 scope: editor, // was editor...
40819 handler:handler||editor.relayBtnCmd,
40820 clickEvent:'mousedown',
40821 tooltip: etb.buttonTips[id] || undefined, ///tips ???
40825 // create a new element.
40826 var wdiv = editor.wrap.createChild({
40828 }, editor.wrap.dom.firstChild.nextSibling, true);
40830 // can we do this more than once??
40832 // stop form submits
40835 // disable everything...
40836 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40837 this.toolbars = {};
40839 for (var i in ty) {
40841 this.toolbars[i] = this.buildToolbar(ty[i],i);
40843 this.tb = this.toolbars.BODY;
40845 this.buildFooter();
40846 this.footer.show();
40848 this.rendered = true;
40850 // the all the btns;
40851 editor.on('editorevent', this.updateToolbar, this);
40852 // other toolbars need to implement this..
40853 //editor.on('editmodechange', this.updateToolbar, this);
40859 * Protected method that will not generally be called directly. It triggers
40860 * a toolbar update by reading the markup state of the current selection in the editor.
40862 updateToolbar: function(editor,ev,sel){
40865 // capture mouse up - this is handy for selecting images..
40866 // perhaps should go somewhere else...
40867 if(!this.editor.activated){
40868 this.editor.onFirstFocus();
40872 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
40873 // selectNode - might want to handle IE?
40875 (ev.type == 'mouseup' || ev.type == 'click' ) &&
40876 ev.target && ev.target.tagName == 'IMG') {
40877 // they have click on an image...
40878 // let's see if we can change the selection...
40881 var nodeRange = sel.ownerDocument.createRange();
40883 nodeRange.selectNode(sel);
40885 nodeRange.selectNodeContents(sel);
40887 //nodeRange.collapse(true);
40888 var s = editor.win.getSelection();
40889 s.removeAllRanges();
40890 s.addRange(nodeRange);
40894 var updateFooter = sel ? false : true;
40897 var ans = this.editor.getAllAncestors();
40900 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
40903 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
40904 sel = sel ? sel : this.editor.doc.body;
40905 sel = sel.tagName.length ? sel : this.editor.doc.body;
40908 // pick a menu that exists..
40909 var tn = sel.tagName.toUpperCase();
40910 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
40912 tn = sel.tagName.toUpperCase();
40914 var lastSel = this.tb.selectedNode
40916 this.tb.selectedNode = sel;
40918 // if current menu does not match..
40919 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
40922 ///console.log("show: " + tn);
40923 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
40926 this.tb.items.first().el.innerHTML = tn + ': ';
40929 // update attributes
40930 if (this.tb.fields) {
40931 this.tb.fields.each(function(e) {
40932 e.setValue(sel.getAttribute(e.name));
40937 var st = this.tb.fields.item(0);
40938 st.store.removeAll();
40939 var cn = sel.className.split(/\s+/);
40942 if (this.styles['*']) {
40944 Roo.each(this.styles['*'], function(v) {
40945 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40948 if (this.styles[tn]) {
40949 Roo.each(this.styles[tn], function(v) {
40950 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
40954 st.store.loadData(avs);
40958 // flag our selected Node.
40959 this.tb.selectedNode = sel;
40962 Roo.menu.MenuMgr.hideAll();
40966 if (!updateFooter) {
40969 // update the footer
40973 this.footerEls = ans.reverse();
40974 Roo.each(this.footerEls, function(a,i) {
40975 if (!a) { return; }
40976 html += html.length ? ' > ' : '';
40978 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
40983 var sz = this.footDisp.up('td').getSize();
40984 this.footDisp.dom.style.width = (sz.width -10) + 'px';
40985 this.footDisp.dom.style.marginLeft = '5px';
40987 this.footDisp.dom.style.overflow = 'hidden';
40989 this.footDisp.dom.innerHTML = html;
40991 //this.editorsyncValue();
40996 onDestroy : function(){
40999 this.tb.items.each(function(item){
41001 item.menu.removeAll();
41003 item.menu.el.destroy();
41011 onFirstFocus: function() {
41012 // need to do this for all the toolbars..
41013 this.tb.items.each(function(item){
41017 buildToolbar: function(tlist, nm)
41019 var editor = this.editor;
41020 // create a new element.
41021 var wdiv = editor.wrap.createChild({
41023 }, editor.wrap.dom.firstChild.nextSibling, true);
41026 var tb = new Roo.Toolbar(wdiv);
41029 tb.add(nm+ ": ");
41032 for(var i in this.styles) {
41037 if (styles && styles.length) {
41039 // this needs a multi-select checkbox...
41040 tb.addField( new Roo.form.ComboBox({
41041 store: new Roo.data.SimpleStore({
41043 fields: ['val', 'selected'],
41046 name : 'className',
41047 displayField:'val',
41051 triggerAction: 'all',
41052 emptyText:'Select Style',
41053 selectOnFocus:true,
41056 'select': function(c, r, i) {
41057 // initial support only for on class per el..
41058 tb.selectedNode.className = r ? r.get('val') : '';
41059 editor.syncValue();
41068 for (var i in tlist) {
41070 var item = tlist[i];
41071 tb.add(item.title + ": ");
41077 // opts == pulldown..
41078 tb.addField( new Roo.form.ComboBox({
41079 store: new Roo.data.SimpleStore({
41085 displayField:'val',
41089 triggerAction: 'all',
41090 emptyText:'Select',
41091 selectOnFocus:true,
41092 width: item.width ? item.width : 130,
41094 'select': function(c, r, i) {
41095 tb.selectedNode.setAttribute(c.name, r.get('val'));
41104 tb.addField( new Roo.form.TextField({
41107 //allowBlank:false,
41112 tb.addField( new Roo.form.TextField({
41118 'change' : function(f, nv, ov) {
41119 tb.selectedNode.setAttribute(f.name, nv);
41125 tb.el.on('click', function(e){
41126 e.preventDefault(); // what does this do?
41128 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
41131 // dont need to disable them... as they will get hidden
41136 buildFooter : function()
41139 var fel = this.editor.wrap.createChild();
41140 this.footer = new Roo.Toolbar(fel);
41141 // toolbar has scrolly on left / right?
41142 var footDisp= new Roo.Toolbar.Fill();
41148 handler : function() {
41149 _t.footDisp.scrollTo('left',0,true)
41153 this.footer.add( footDisp );
41158 handler : function() {
41160 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
41164 var fel = Roo.get(footDisp.el);
41165 fel.addClass('x-editor-context');
41166 this.footDispWrap = fel;
41167 this.footDispWrap.overflow = 'hidden';
41169 this.footDisp = fel.createChild();
41170 this.footDispWrap.on('click', this.onContextClick, this)
41174 onContextClick : function (ev,dom)
41176 ev.preventDefault();
41177 var cn = dom.className;
41179 if (!cn.match(/x-ed-loc-/)) {
41182 var n = cn.split('-').pop();
41183 var ans = this.footerEls;
41187 var range = this.editor.createRange();
41189 range.selectNodeContents(sel);
41190 //range.selectNode(sel);
41193 var selection = this.editor.getSelection();
41194 selection.removeAllRanges();
41195 selection.addRange(range);
41199 this.updateToolbar(null, null, sel);
41216 * Ext JS Library 1.1.1
41217 * Copyright(c) 2006-2007, Ext JS, LLC.
41219 * Originally Released Under LGPL - original licence link has changed is not relivant.
41222 * <script type="text/javascript">
41226 * @class Roo.form.BasicForm
41227 * @extends Roo.util.Observable
41228 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
41230 * @param {String/HTMLElement/Roo.Element} el The form element or its id
41231 * @param {Object} config Configuration options
41233 Roo.form.BasicForm = function(el, config){
41234 this.allItems = [];
41235 this.childForms = [];
41236 Roo.apply(this, config);
41238 * The Roo.form.Field items in this form.
41239 * @type MixedCollection
41243 this.items = new Roo.util.MixedCollection(false, function(o){
41244 return o.id || (o.id = Roo.id());
41248 * @event beforeaction
41249 * Fires before any action is performed. Return false to cancel the action.
41250 * @param {Form} this
41251 * @param {Action} action The action to be performed
41253 beforeaction: true,
41255 * @event actionfailed
41256 * Fires when an action fails.
41257 * @param {Form} this
41258 * @param {Action} action The action that failed
41260 actionfailed : true,
41262 * @event actioncomplete
41263 * Fires when an action is completed.
41264 * @param {Form} this
41265 * @param {Action} action The action that completed
41267 actioncomplete : true
41272 Roo.form.BasicForm.superclass.constructor.call(this);
41275 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
41277 * @cfg {String} method
41278 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
41281 * @cfg {DataReader} reader
41282 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
41283 * This is optional as there is built-in support for processing JSON.
41286 * @cfg {DataReader} errorReader
41287 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
41288 * This is completely optional as there is built-in support for processing JSON.
41291 * @cfg {String} url
41292 * The URL to use for form actions if one isn't supplied in the action options.
41295 * @cfg {Boolean} fileUpload
41296 * Set to true if this form is a file upload.
41300 * @cfg {Object} baseParams
41301 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
41306 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
41311 activeAction : null,
41314 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
41315 * or setValues() data instead of when the form was first created.
41317 trackResetOnLoad : false,
41321 * childForms - used for multi-tab forms
41324 childForms : false,
41327 * allItems - full list of fields.
41333 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
41334 * element by passing it or its id or mask the form itself by passing in true.
41337 waitMsgTarget : false,
41340 initEl : function(el){
41341 this.el = Roo.get(el);
41342 this.id = this.el.id || Roo.id();
41343 this.el.on('submit', this.onSubmit, this);
41344 this.el.addClass('x-form');
41348 onSubmit : function(e){
41353 * Returns true if client-side validation on the form is successful.
41356 isValid : function(){
41358 this.items.each(function(f){
41367 * Returns true if any fields in this form have changed since their original load.
41370 isDirty : function(){
41372 this.items.each(function(f){
41382 * Performs a predefined action (submit or load) or custom actions you define on this form.
41383 * @param {String} actionName The name of the action type
41384 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
41385 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
41386 * accept other config options):
41388 Property Type Description
41389 ---------------- --------------- ----------------------------------------------------------------------------------
41390 url String The url for the action (defaults to the form's url)
41391 method String The form method to use (defaults to the form's method, or POST if not defined)
41392 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
41393 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
41394 validate the form on the client (defaults to false)
41396 * @return {BasicForm} this
41398 doAction : function(action, options){
41399 if(typeof action == 'string'){
41400 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
41402 if(this.fireEvent('beforeaction', this, action) !== false){
41403 this.beforeAction(action);
41404 action.run.defer(100, action);
41410 * Shortcut to do a submit action.
41411 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41412 * @return {BasicForm} this
41414 submit : function(options){
41415 this.doAction('submit', options);
41420 * Shortcut to do a load action.
41421 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
41422 * @return {BasicForm} this
41424 load : function(options){
41425 this.doAction('load', options);
41430 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
41431 * @param {Record} record The record to edit
41432 * @return {BasicForm} this
41434 updateRecord : function(record){
41435 record.beginEdit();
41436 var fs = record.fields;
41437 fs.each(function(f){
41438 var field = this.findField(f.name);
41440 record.set(f.name, field.getValue());
41448 * Loads an Roo.data.Record into this form.
41449 * @param {Record} record The record to load
41450 * @return {BasicForm} this
41452 loadRecord : function(record){
41453 this.setValues(record.data);
41458 beforeAction : function(action){
41459 var o = action.options;
41462 if(this.waitMsgTarget === true){
41463 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
41464 }else if(this.waitMsgTarget){
41465 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
41466 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
41468 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
41474 afterAction : function(action, success){
41475 this.activeAction = null;
41476 var o = action.options;
41478 if(this.waitMsgTarget === true){
41480 }else if(this.waitMsgTarget){
41481 this.waitMsgTarget.unmask();
41483 Roo.MessageBox.updateProgress(1);
41484 Roo.MessageBox.hide();
41491 Roo.callback(o.success, o.scope, [this, action]);
41492 this.fireEvent('actioncomplete', this, action);
41496 // failure condition..
41497 // we have a scenario where updates need confirming.
41498 // eg. if a locking scenario exists..
41499 // we look for { errors : { needs_confirm : true }} in the response.
41500 if (typeof(action.result.errors.needs_confirm) != 'undefined') {
41502 Roo.MessageBox.confirm(
41503 "Change requires confirmation",
41504 action.result.errorMsg,
41509 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
41519 Roo.callback(o.failure, o.scope, [this, action]);
41520 // show an error message if no failed handler is set..
41521 if (!this.hasListener('actionfailed')) {
41522 Roo.MessageBox.alert("Error",
41523 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
41524 action.result.errorMsg :
41525 "Saving Failed, please check your entries"
41529 this.fireEvent('actionfailed', this, action);
41535 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
41536 * @param {String} id The value to search for
41539 findField : function(id){
41540 var field = this.items.get(id);
41542 this.items.each(function(f){
41543 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
41549 return field || null;
41553 * Add a secondary form to this one,
41554 * Used to provide tabbed forms. One form is primary, with hidden values
41555 * which mirror the elements from the other forms.
41557 * @param {Roo.form.Form} form to add.
41560 addForm : function(form)
41563 if (this.childForms.indexOf(form) > -1) {
41567 this.childForms.push(form);
41569 Roo.each(form.allItems, function (fe) {
41571 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
41572 if (this.findField(n)) { // already added..
41575 var add = new Roo.form.Hidden({
41578 add.render(this.el);
41585 * Mark fields in this form invalid in bulk.
41586 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
41587 * @return {BasicForm} this
41589 markInvalid : function(errors){
41590 if(errors instanceof Array){
41591 for(var i = 0, len = errors.length; i < len; i++){
41592 var fieldError = errors[i];
41593 var f = this.findField(fieldError.id);
41595 f.markInvalid(fieldError.msg);
41601 if(typeof errors[id] != 'function' && (field = this.findField(id))){
41602 field.markInvalid(errors[id]);
41606 Roo.each(this.childForms || [], function (f) {
41607 f.markInvalid(errors);
41614 * Set values for fields in this form in bulk.
41615 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
41616 * @return {BasicForm} this
41618 setValues : function(values){
41619 if(values instanceof Array){ // array of objects
41620 for(var i = 0, len = values.length; i < len; i++){
41622 var f = this.findField(v.id);
41624 f.setValue(v.value);
41625 if(this.trackResetOnLoad){
41626 f.originalValue = f.getValue();
41630 }else{ // object hash
41633 if(typeof values[id] != 'function' && (field = this.findField(id))){
41635 if (field.setFromData &&
41636 field.valueField &&
41637 field.displayField &&
41638 // combos' with local stores can
41639 // be queried via setValue()
41640 // to set their value..
41641 (field.store && !field.store.isLocal)
41645 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
41646 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
41647 field.setFromData(sd);
41650 field.setValue(values[id]);
41654 if(this.trackResetOnLoad){
41655 field.originalValue = field.getValue();
41661 Roo.each(this.childForms || [], function (f) {
41662 f.setValues(values);
41669 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
41670 * they are returned as an array.
41671 * @param {Boolean} asString
41674 getValues : function(asString){
41675 if (this.childForms) {
41676 // copy values from the child forms
41677 Roo.each(this.childForms, function (f) {
41678 this.setValues(f.getValues());
41684 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
41685 if(asString === true){
41688 return Roo.urlDecode(fs);
41692 * Returns the fields in this form as an object with key/value pairs.
41693 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
41696 getFieldValues : function(with_hidden)
41698 if (this.childForms) {
41699 // copy values from the child forms
41700 // should this call getFieldValues - probably not as we do not currently copy
41701 // hidden fields when we generate..
41702 Roo.each(this.childForms, function (f) {
41703 this.setValues(f.getValues());
41708 this.items.each(function(f){
41709 if (!f.getName()) {
41712 var v = f.getValue();
41713 // not sure if this supported any more..
41714 if ((typeof(v) == 'object') && f.getRawValue) {
41715 v = f.getRawValue() ; // dates..
41717 // combo boxes where name != hiddenName...
41718 if (f.name != f.getName()) {
41719 ret[f.name] = f.getRawValue();
41721 ret[f.getName()] = v;
41728 * Clears all invalid messages in this form.
41729 * @return {BasicForm} this
41731 clearInvalid : function(){
41732 this.items.each(function(f){
41736 Roo.each(this.childForms || [], function (f) {
41745 * Resets this form.
41746 * @return {BasicForm} this
41748 reset : function(){
41749 this.items.each(function(f){
41753 Roo.each(this.childForms || [], function (f) {
41762 * Add Roo.form components to this form.
41763 * @param {Field} field1
41764 * @param {Field} field2 (optional)
41765 * @param {Field} etc (optional)
41766 * @return {BasicForm} this
41769 this.items.addAll(Array.prototype.slice.call(arguments, 0));
41775 * Removes a field from the items collection (does NOT remove its markup).
41776 * @param {Field} field
41777 * @return {BasicForm} this
41779 remove : function(field){
41780 this.items.remove(field);
41785 * Looks at the fields in this form, checks them for an id attribute,
41786 * and calls applyTo on the existing dom element with that id.
41787 * @return {BasicForm} this
41789 render : function(){
41790 this.items.each(function(f){
41791 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
41799 * Calls {@link Ext#apply} for all fields in this form with the passed object.
41800 * @param {Object} values
41801 * @return {BasicForm} this
41803 applyToFields : function(o){
41804 this.items.each(function(f){
41811 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
41812 * @param {Object} values
41813 * @return {BasicForm} this
41815 applyIfToFields : function(o){
41816 this.items.each(function(f){
41824 Roo.BasicForm = Roo.form.BasicForm;/*
41826 * Ext JS Library 1.1.1
41827 * Copyright(c) 2006-2007, Ext JS, LLC.
41829 * Originally Released Under LGPL - original licence link has changed is not relivant.
41832 * <script type="text/javascript">
41836 * @class Roo.form.Form
41837 * @extends Roo.form.BasicForm
41838 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
41840 * @param {Object} config Configuration options
41842 Roo.form.Form = function(config){
41844 if (config.items) {
41845 xitems = config.items;
41846 delete config.items;
41850 Roo.form.Form.superclass.constructor.call(this, null, config);
41851 this.url = this.url || this.action;
41853 this.root = new Roo.form.Layout(Roo.applyIf({
41857 this.active = this.root;
41859 * Array of all the buttons that have been added to this form via {@link addButton}
41863 this.allItems = [];
41866 * @event clientvalidation
41867 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
41868 * @param {Form} this
41869 * @param {Boolean} valid true if the form has passed client-side validation
41871 clientvalidation: true,
41874 * Fires when the form is rendered
41875 * @param {Roo.form.Form} form
41880 if (this.progressUrl) {
41881 // push a hidden field onto the list of fields..
41885 name : 'UPLOAD_IDENTIFIER'
41890 Roo.each(xitems, this.addxtype, this);
41896 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
41898 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
41901 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
41904 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
41906 buttonAlign:'center',
41909 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
41914 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
41915 * This property cascades to child containers if not set.
41920 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
41921 * fires a looping event with that state. This is required to bind buttons to the valid
41922 * state using the config value formBind:true on the button.
41924 monitorValid : false,
41927 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
41932 * @cfg {String} progressUrl - Url to return progress data
41935 progressUrl : false,
41938 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
41939 * fields are added and the column is closed. If no fields are passed the column remains open
41940 * until end() is called.
41941 * @param {Object} config The config to pass to the column
41942 * @param {Field} field1 (optional)
41943 * @param {Field} field2 (optional)
41944 * @param {Field} etc (optional)
41945 * @return Column The column container object
41947 column : function(c){
41948 var col = new Roo.form.Column(c);
41950 if(arguments.length > 1){ // duplicate code required because of Opera
41951 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41958 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
41959 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
41960 * until end() is called.
41961 * @param {Object} config The config to pass to the fieldset
41962 * @param {Field} field1 (optional)
41963 * @param {Field} field2 (optional)
41964 * @param {Field} etc (optional)
41965 * @return FieldSet The fieldset container object
41967 fieldset : function(c){
41968 var fs = new Roo.form.FieldSet(c);
41970 if(arguments.length > 1){ // duplicate code required because of Opera
41971 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41978 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
41979 * fields are added and the container is closed. If no fields are passed the container remains open
41980 * until end() is called.
41981 * @param {Object} config The config to pass to the Layout
41982 * @param {Field} field1 (optional)
41983 * @param {Field} field2 (optional)
41984 * @param {Field} etc (optional)
41985 * @return Layout The container object
41987 container : function(c){
41988 var l = new Roo.form.Layout(c);
41990 if(arguments.length > 1){ // duplicate code required because of Opera
41991 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
41998 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
41999 * @param {Object} container A Roo.form.Layout or subclass of Layout
42000 * @return {Form} this
42002 start : function(c){
42003 // cascade label info
42004 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
42005 this.active.stack.push(c);
42006 c.ownerCt = this.active;
42012 * Closes the current open container
42013 * @return {Form} this
42016 if(this.active == this.root){
42019 this.active = this.active.ownerCt;
42024 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
42025 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
42026 * as the label of the field.
42027 * @param {Field} field1
42028 * @param {Field} field2 (optional)
42029 * @param {Field} etc. (optional)
42030 * @return {Form} this
42033 this.active.stack.push.apply(this.active.stack, arguments);
42034 this.allItems.push.apply(this.allItems,arguments);
42036 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
42037 if(a[i].isFormField){
42042 Roo.form.Form.superclass.add.apply(this, r);
42052 * Find any element that has been added to a form, using it's ID or name
42053 * This can include framesets, columns etc. along with regular fields..
42054 * @param {String} id - id or name to find.
42056 * @return {Element} e - or false if nothing found.
42058 findbyId : function(id)
42064 Roo.each(this.allItems, function(f){
42065 if (f.id == id || f.name == id ){
42076 * Render this form into the passed container. This should only be called once!
42077 * @param {String/HTMLElement/Element} container The element this component should be rendered into
42078 * @return {Form} this
42080 render : function(ct)
42086 var o = this.autoCreate || {
42088 method : this.method || 'POST',
42089 id : this.id || Roo.id()
42091 this.initEl(ct.createChild(o));
42093 this.root.render(this.el);
42097 this.items.each(function(f){
42098 f.render('x-form-el-'+f.id);
42101 if(this.buttons.length > 0){
42102 // tables are required to maintain order and for correct IE layout
42103 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
42104 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
42105 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
42107 var tr = tb.getElementsByTagName('tr')[0];
42108 for(var i = 0, len = this.buttons.length; i < len; i++) {
42109 var b = this.buttons[i];
42110 var td = document.createElement('td');
42111 td.className = 'x-form-btn-td';
42112 b.render(tr.appendChild(td));
42115 if(this.monitorValid){ // initialize after render
42116 this.startMonitoring();
42118 this.fireEvent('rendered', this);
42123 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
42124 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
42125 * object or a valid Roo.DomHelper element config
42126 * @param {Function} handler The function called when the button is clicked
42127 * @param {Object} scope (optional) The scope of the handler function
42128 * @return {Roo.Button}
42130 addButton : function(config, handler, scope){
42134 minWidth: this.minButtonWidth,
42137 if(typeof config == "string"){
42140 Roo.apply(bc, config);
42142 var btn = new Roo.Button(null, bc);
42143 this.buttons.push(btn);
42148 * Adds a series of form elements (using the xtype property as the factory method.
42149 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
42150 * @param {Object} config
42153 addxtype : function()
42155 var ar = Array.prototype.slice.call(arguments, 0);
42157 for(var i = 0; i < ar.length; i++) {
42159 continue; // skip -- if this happends something invalid got sent, we
42160 // should ignore it, as basically that interface element will not show up
42161 // and that should be pretty obvious!!
42164 if (Roo.form[ar[i].xtype]) {
42166 var fe = Roo.factory(ar[i], Roo.form);
42172 fe.store.form = this;
42177 this.allItems.push(fe);
42178 if (fe.items && fe.addxtype) {
42179 fe.addxtype.apply(fe, fe.items);
42189 // console.log('adding ' + ar[i].xtype);
42191 if (ar[i].xtype == 'Button') {
42192 //console.log('adding button');
42193 //console.log(ar[i]);
42194 this.addButton(ar[i]);
42195 this.allItems.push(fe);
42199 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
42200 alert('end is not supported on xtype any more, use items');
42202 // //console.log('adding end');
42210 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
42211 * option "monitorValid"
42213 startMonitoring : function(){
42216 Roo.TaskMgr.start({
42217 run : this.bindHandler,
42218 interval : this.monitorPoll || 200,
42225 * Stops monitoring of the valid state of this form
42227 stopMonitoring : function(){
42228 this.bound = false;
42232 bindHandler : function(){
42234 return false; // stops binding
42237 this.items.each(function(f){
42238 if(!f.isValid(true)){
42243 for(var i = 0, len = this.buttons.length; i < len; i++){
42244 var btn = this.buttons[i];
42245 if(btn.formBind === true && btn.disabled === valid){
42246 btn.setDisabled(!valid);
42249 this.fireEvent('clientvalidation', this, valid);
42263 Roo.Form = Roo.form.Form;
42266 * Ext JS Library 1.1.1
42267 * Copyright(c) 2006-2007, Ext JS, LLC.
42269 * Originally Released Under LGPL - original licence link has changed is not relivant.
42272 * <script type="text/javascript">
42276 * @class Roo.form.Action
42277 * Internal Class used to handle form actions
42279 * @param {Roo.form.BasicForm} el The form element or its id
42280 * @param {Object} config Configuration options
42284 // define the action interface
42285 Roo.form.Action = function(form, options){
42287 this.options = options || {};
42290 * Client Validation Failed
42293 Roo.form.Action.CLIENT_INVALID = 'client';
42295 * Server Validation Failed
42298 Roo.form.Action.SERVER_INVALID = 'server';
42300 * Connect to Server Failed
42303 Roo.form.Action.CONNECT_FAILURE = 'connect';
42305 * Reading Data from Server Failed
42308 Roo.form.Action.LOAD_FAILURE = 'load';
42310 Roo.form.Action.prototype = {
42312 failureType : undefined,
42313 response : undefined,
42314 result : undefined,
42316 // interface method
42317 run : function(options){
42321 // interface method
42322 success : function(response){
42326 // interface method
42327 handleResponse : function(response){
42331 // default connection failure
42332 failure : function(response){
42334 this.response = response;
42335 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42336 this.form.afterAction(this, false);
42339 processResponse : function(response){
42340 this.response = response;
42341 if(!response.responseText){
42344 this.result = this.handleResponse(response);
42345 return this.result;
42348 // utility functions used internally
42349 getUrl : function(appendParams){
42350 var url = this.options.url || this.form.url || this.form.el.dom.action;
42352 var p = this.getParams();
42354 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
42360 getMethod : function(){
42361 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
42364 getParams : function(){
42365 var bp = this.form.baseParams;
42366 var p = this.options.params;
42368 if(typeof p == "object"){
42369 p = Roo.urlEncode(Roo.applyIf(p, bp));
42370 }else if(typeof p == 'string' && bp){
42371 p += '&' + Roo.urlEncode(bp);
42374 p = Roo.urlEncode(bp);
42379 createCallback : function(){
42381 success: this.success,
42382 failure: this.failure,
42384 timeout: (this.form.timeout*1000),
42385 upload: this.form.fileUpload ? this.success : undefined
42390 Roo.form.Action.Submit = function(form, options){
42391 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
42394 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
42397 haveProgress : false,
42398 uploadComplete : false,
42400 // uploadProgress indicator.
42401 uploadProgress : function()
42403 if (!this.form.progressUrl) {
42407 if (!this.haveProgress) {
42408 Roo.MessageBox.progress("Uploading", "Uploading");
42410 if (this.uploadComplete) {
42411 Roo.MessageBox.hide();
42415 this.haveProgress = true;
42417 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
42419 var c = new Roo.data.Connection();
42421 url : this.form.progressUrl,
42426 success : function(req){
42427 //console.log(data);
42431 rdata = Roo.decode(req.responseText)
42433 Roo.log("Invalid data from server..");
42437 if (!rdata || !rdata.success) {
42441 var data = rdata.data;
42443 if (this.uploadComplete) {
42444 Roo.MessageBox.hide();
42449 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
42450 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
42453 this.uploadProgress.defer(2000,this);
42456 failure: function(data) {
42457 Roo.log('progress url failed ');
42468 // run get Values on the form, so it syncs any secondary forms.
42469 this.form.getValues();
42471 var o = this.options;
42472 var method = this.getMethod();
42473 var isPost = method == 'POST';
42474 if(o.clientValidation === false || this.form.isValid()){
42476 if (this.form.progressUrl) {
42477 this.form.findField('UPLOAD_IDENTIFIER').setValue(
42478 (new Date() * 1) + '' + Math.random());
42483 Roo.Ajax.request(Roo.apply(this.createCallback(), {
42484 form:this.form.el.dom,
42485 url:this.getUrl(!isPost),
42487 params:isPost ? this.getParams() : null,
42488 isUpload: this.form.fileUpload
42491 this.uploadProgress();
42493 }else if (o.clientValidation !== false){ // client validation failed
42494 this.failureType = Roo.form.Action.CLIENT_INVALID;
42495 this.form.afterAction(this, false);
42499 success : function(response)
42501 this.uploadComplete= true;
42502 if (this.haveProgress) {
42503 Roo.MessageBox.hide();
42507 var result = this.processResponse(response);
42508 if(result === true || result.success){
42509 this.form.afterAction(this, true);
42513 this.form.markInvalid(result.errors);
42514 this.failureType = Roo.form.Action.SERVER_INVALID;
42516 this.form.afterAction(this, false);
42518 failure : function(response)
42520 this.uploadComplete= true;
42521 if (this.haveProgress) {
42522 Roo.MessageBox.hide();
42525 this.response = response;
42526 this.failureType = Roo.form.Action.CONNECT_FAILURE;
42527 this.form.afterAction(this, false);
42530 handleResponse : function(response){
42531 if(this.form.errorReader){
42532 var rs = this.form.errorReader.read(response);
42535 for(var i = 0, len = rs.records.length; i < len; i++) {
42536 var r = rs.records[i];
42537 errors[i] = r.data;
42540 if(errors.length < 1){
42544 success : rs.success,
42550 ret = Roo.decode(response.responseText);
42554 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
42564 Roo.form.Action.Load = function(form, options){
42565 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
42566 this.reader = this.form.reader;
42569 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
42574 Roo.Ajax.request(Roo.apply(
42575 this.createCallback(), {
42576 method:this.getMethod(),
42577 url:this.getUrl(false),
42578 params:this.getParams()
42582 success : function(response){
42584 var result = this.processResponse(response);
42585 if(result === true || !result.success || !result.data){
42586 this.failureType = Roo.form.Action.LOAD_FAILURE;
42587 this.form.afterAction(this, false);
42590 this.form.clearInvalid();
42591 this.form.setValues(result.data);
42592 this.form.afterAction(this, true);
42595 handleResponse : function(response){
42596 if(this.form.reader){
42597 var rs = this.form.reader.read(response);
42598 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
42600 success : rs.success,
42604 return Roo.decode(response.responseText);
42608 Roo.form.Action.ACTION_TYPES = {
42609 'load' : Roo.form.Action.Load,
42610 'submit' : Roo.form.Action.Submit
42613 * Ext JS Library 1.1.1
42614 * Copyright(c) 2006-2007, Ext JS, LLC.
42616 * Originally Released Under LGPL - original licence link has changed is not relivant.
42619 * <script type="text/javascript">
42623 * @class Roo.form.Layout
42624 * @extends Roo.Component
42625 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
42627 * @param {Object} config Configuration options
42629 Roo.form.Layout = function(config){
42631 if (config.items) {
42632 xitems = config.items;
42633 delete config.items;
42635 Roo.form.Layout.superclass.constructor.call(this, config);
42637 Roo.each(xitems, this.addxtype, this);
42641 Roo.extend(Roo.form.Layout, Roo.Component, {
42643 * @cfg {String/Object} autoCreate
42644 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
42647 * @cfg {String/Object/Function} style
42648 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
42649 * a function which returns such a specification.
42652 * @cfg {String} labelAlign
42653 * Valid values are "left," "top" and "right" (defaults to "left")
42656 * @cfg {Number} labelWidth
42657 * Fixed width in pixels of all field labels (defaults to undefined)
42660 * @cfg {Boolean} clear
42661 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
42665 * @cfg {String} labelSeparator
42666 * The separator to use after field labels (defaults to ':')
42668 labelSeparator : ':',
42670 * @cfg {Boolean} hideLabels
42671 * True to suppress the display of field labels in this layout (defaults to false)
42673 hideLabels : false,
42676 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
42681 onRender : function(ct, position){
42682 if(this.el){ // from markup
42683 this.el = Roo.get(this.el);
42684 }else { // generate
42685 var cfg = this.getAutoCreate();
42686 this.el = ct.createChild(cfg, position);
42689 this.el.applyStyles(this.style);
42691 if(this.labelAlign){
42692 this.el.addClass('x-form-label-'+this.labelAlign);
42694 if(this.hideLabels){
42695 this.labelStyle = "display:none";
42696 this.elementStyle = "padding-left:0;";
42698 if(typeof this.labelWidth == 'number'){
42699 this.labelStyle = "width:"+this.labelWidth+"px;";
42700 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
42702 if(this.labelAlign == 'top'){
42703 this.labelStyle = "width:auto;";
42704 this.elementStyle = "padding-left:0;";
42707 var stack = this.stack;
42708 var slen = stack.length;
42710 if(!this.fieldTpl){
42711 var t = new Roo.Template(
42712 '<div class="x-form-item {5}">',
42713 '<label for="{0}" style="{2}">{1}{4}</label>',
42714 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42716 '</div><div class="x-form-clear-left"></div>'
42718 t.disableFormats = true;
42720 Roo.form.Layout.prototype.fieldTpl = t;
42722 for(var i = 0; i < slen; i++) {
42723 if(stack[i].isFormField){
42724 this.renderField(stack[i]);
42726 this.renderComponent(stack[i]);
42731 this.el.createChild({cls:'x-form-clear'});
42736 renderField : function(f){
42737 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
42740 f.labelStyle||this.labelStyle||'', //2
42741 this.elementStyle||'', //3
42742 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
42743 f.itemCls||this.itemCls||'' //5
42744 ], true).getPrevSibling());
42748 renderComponent : function(c){
42749 c.render(c.isLayout ? this.el : this.el.createChild());
42752 * Adds a object form elements (using the xtype property as the factory method.)
42753 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
42754 * @param {Object} config
42756 addxtype : function(o)
42758 // create the lement.
42759 o.form = this.form;
42760 var fe = Roo.factory(o, Roo.form);
42761 this.form.allItems.push(fe);
42762 this.stack.push(fe);
42764 if (fe.isFormField) {
42765 this.form.items.add(fe);
42773 * @class Roo.form.Column
42774 * @extends Roo.form.Layout
42775 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
42777 * @param {Object} config Configuration options
42779 Roo.form.Column = function(config){
42780 Roo.form.Column.superclass.constructor.call(this, config);
42783 Roo.extend(Roo.form.Column, Roo.form.Layout, {
42785 * @cfg {Number/String} width
42786 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42789 * @cfg {String/Object} autoCreate
42790 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
42794 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
42797 onRender : function(ct, position){
42798 Roo.form.Column.superclass.onRender.call(this, ct, position);
42800 this.el.setWidth(this.width);
42807 * @class Roo.form.Row
42808 * @extends Roo.form.Layout
42809 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
42811 * @param {Object} config Configuration options
42815 Roo.form.Row = function(config){
42816 Roo.form.Row.superclass.constructor.call(this, config);
42819 Roo.extend(Roo.form.Row, Roo.form.Layout, {
42821 * @cfg {Number/String} width
42822 * The fixed width of the column in pixels or CSS value (defaults to "auto")
42825 * @cfg {Number/String} height
42826 * The fixed height of the column in pixels or CSS value (defaults to "auto")
42828 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
42832 onRender : function(ct, position){
42833 //console.log('row render');
42835 var t = new Roo.Template(
42836 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
42837 '<label for="{0}" style="{2}">{1}{4}</label>',
42838 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
42842 t.disableFormats = true;
42844 Roo.form.Layout.prototype.rowTpl = t;
42846 this.fieldTpl = this.rowTpl;
42848 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
42849 var labelWidth = 100;
42851 if ((this.labelAlign != 'top')) {
42852 if (typeof this.labelWidth == 'number') {
42853 labelWidth = this.labelWidth
42855 this.padWidth = 20 + labelWidth;
42859 Roo.form.Column.superclass.onRender.call(this, ct, position);
42861 this.el.setWidth(this.width);
42864 this.el.setHeight(this.height);
42869 renderField : function(f){
42870 f.fieldEl = this.fieldTpl.append(this.el, [
42871 f.id, f.fieldLabel,
42872 f.labelStyle||this.labelStyle||'',
42873 this.elementStyle||'',
42874 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
42875 f.itemCls||this.itemCls||'',
42876 f.width ? f.width + this.padWidth : 160 + this.padWidth
42883 * @class Roo.form.FieldSet
42884 * @extends Roo.form.Layout
42885 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
42887 * @param {Object} config Configuration options
42889 Roo.form.FieldSet = function(config){
42890 Roo.form.FieldSet.superclass.constructor.call(this, config);
42893 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
42895 * @cfg {String} legend
42896 * The text to display as the legend for the FieldSet (defaults to '')
42899 * @cfg {String/Object} autoCreate
42900 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
42904 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
42907 onRender : function(ct, position){
42908 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
42910 this.setLegend(this.legend);
42915 setLegend : function(text){
42917 this.el.child('legend').update(text);
42922 * Ext JS Library 1.1.1
42923 * Copyright(c) 2006-2007, Ext JS, LLC.
42925 * Originally Released Under LGPL - original licence link has changed is not relivant.
42928 * <script type="text/javascript">
42931 * @class Roo.form.VTypes
42932 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
42935 Roo.form.VTypes = function(){
42936 // closure these in so they are only created once.
42937 var alpha = /^[a-zA-Z_]+$/;
42938 var alphanum = /^[a-zA-Z0-9_]+$/;
42939 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
42940 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
42942 // All these messages and functions are configurable
42945 * The function used to validate email addresses
42946 * @param {String} value The email address
42948 'email' : function(v){
42949 return email.test(v);
42952 * The error text to display when the email validation function returns false
42955 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
42957 * The keystroke filter mask to be applied on email input
42960 'emailMask' : /[a-z0-9_\.\-@]/i,
42963 * The function used to validate URLs
42964 * @param {String} value The URL
42966 'url' : function(v){
42967 return url.test(v);
42970 * The error text to display when the url validation function returns false
42973 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
42976 * The function used to validate alpha values
42977 * @param {String} value The value
42979 'alpha' : function(v){
42980 return alpha.test(v);
42983 * The error text to display when the alpha validation function returns false
42986 'alphaText' : 'This field should only contain letters and _',
42988 * The keystroke filter mask to be applied on alpha input
42991 'alphaMask' : /[a-z_]/i,
42994 * The function used to validate alphanumeric values
42995 * @param {String} value The value
42997 'alphanum' : function(v){
42998 return alphanum.test(v);
43001 * The error text to display when the alphanumeric validation function returns false
43004 'alphanumText' : 'This field should only contain letters, numbers and _',
43006 * The keystroke filter mask to be applied on alphanumeric input
43009 'alphanumMask' : /[a-z0-9_]/i
43011 }();//<script type="text/javascript">
43014 * @class Roo.form.FCKeditor
43015 * @extends Roo.form.TextArea
43016 * Wrapper around the FCKEditor http://www.fckeditor.net
43018 * Creates a new FCKeditor
43019 * @param {Object} config Configuration options
43021 Roo.form.FCKeditor = function(config){
43022 Roo.form.FCKeditor.superclass.constructor.call(this, config);
43025 * @event editorinit
43026 * Fired when the editor is initialized - you can add extra handlers here..
43027 * @param {FCKeditor} this
43028 * @param {Object} the FCK object.
43035 Roo.form.FCKeditor.editors = { };
43036 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
43038 //defaultAutoCreate : {
43039 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
43043 * @cfg {Object} fck options - see fck manual for details.
43048 * @cfg {Object} fck toolbar set (Basic or Default)
43050 toolbarSet : 'Basic',
43052 * @cfg {Object} fck BasePath
43054 basePath : '/fckeditor/',
43062 onRender : function(ct, position)
43065 this.defaultAutoCreate = {
43067 style:"width:300px;height:60px;",
43068 autocomplete: "off"
43071 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
43074 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
43075 if(this.preventScrollbars){
43076 this.el.setStyle("overflow", "hidden");
43078 this.el.setHeight(this.growMin);
43081 //console.log('onrender' + this.getId() );
43082 Roo.form.FCKeditor.editors[this.getId()] = this;
43085 this.replaceTextarea() ;
43089 getEditor : function() {
43090 return this.fckEditor;
43093 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
43094 * @param {Mixed} value The value to set
43098 setValue : function(value)
43100 //console.log('setValue: ' + value);
43102 if(typeof(value) == 'undefined') { // not sure why this is happending...
43105 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
43107 //if(!this.el || !this.getEditor()) {
43108 // this.value = value;
43109 //this.setValue.defer(100,this,[value]);
43113 if(!this.getEditor()) {
43117 this.getEditor().SetData(value);
43124 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
43125 * @return {Mixed} value The field value
43127 getValue : function()
43130 if (this.frame && this.frame.dom.style.display == 'none') {
43131 return Roo.form.FCKeditor.superclass.getValue.call(this);
43134 if(!this.el || !this.getEditor()) {
43136 // this.getValue.defer(100,this);
43141 var value=this.getEditor().GetData();
43142 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
43143 return Roo.form.FCKeditor.superclass.getValue.call(this);
43149 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
43150 * @return {Mixed} value The field value
43152 getRawValue : function()
43154 if (this.frame && this.frame.dom.style.display == 'none') {
43155 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
43158 if(!this.el || !this.getEditor()) {
43159 //this.getRawValue.defer(100,this);
43166 var value=this.getEditor().GetData();
43167 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
43168 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
43172 setSize : function(w,h) {
43176 //if (this.frame && this.frame.dom.style.display == 'none') {
43177 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43180 //if(!this.el || !this.getEditor()) {
43181 // this.setSize.defer(100,this, [w,h]);
43187 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
43189 this.frame.dom.setAttribute('width', w);
43190 this.frame.dom.setAttribute('height', h);
43191 this.frame.setSize(w,h);
43195 toggleSourceEdit : function(value) {
43199 this.el.dom.style.display = value ? '' : 'none';
43200 this.frame.dom.style.display = value ? 'none' : '';
43205 focus: function(tag)
43207 if (this.frame.dom.style.display == 'none') {
43208 return Roo.form.FCKeditor.superclass.focus.call(this);
43210 if(!this.el || !this.getEditor()) {
43211 this.focus.defer(100,this, [tag]);
43218 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
43219 this.getEditor().Focus();
43221 if (!this.getEditor().Selection.GetSelection()) {
43222 this.focus.defer(100,this, [tag]);
43227 var r = this.getEditor().EditorDocument.createRange();
43228 r.setStart(tgs[0],0);
43229 r.setEnd(tgs[0],0);
43230 this.getEditor().Selection.GetSelection().removeAllRanges();
43231 this.getEditor().Selection.GetSelection().addRange(r);
43232 this.getEditor().Focus();
43239 replaceTextarea : function()
43241 if ( document.getElementById( this.getId() + '___Frame' ) )
43243 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
43245 // We must check the elements firstly using the Id and then the name.
43246 var oTextarea = document.getElementById( this.getId() );
43248 var colElementsByName = document.getElementsByName( this.getId() ) ;
43250 oTextarea.style.display = 'none' ;
43252 if ( oTextarea.tabIndex ) {
43253 this.TabIndex = oTextarea.tabIndex ;
43256 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
43257 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
43258 this.frame = Roo.get(this.getId() + '___Frame')
43261 _getConfigHtml : function()
43265 for ( var o in this.fckconfig ) {
43266 sConfig += sConfig.length > 0 ? '&' : '';
43267 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
43270 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
43274 _getIFrameHtml : function()
43276 var sFile = 'fckeditor.html' ;
43277 /* no idea what this is about..
43280 if ( (/fcksource=true/i).test( window.top.location.search ) )
43281 sFile = 'fckeditor.original.html' ;
43286 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
43287 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
43290 var html = '<iframe id="' + this.getId() +
43291 '___Frame" src="' + sLink +
43292 '" width="' + this.width +
43293 '" height="' + this.height + '"' +
43294 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
43295 ' frameborder="0" scrolling="no"></iframe>' ;
43300 _insertHtmlBefore : function( html, element )
43302 if ( element.insertAdjacentHTML ) {
43304 element.insertAdjacentHTML( 'beforeBegin', html ) ;
43306 var oRange = document.createRange() ;
43307 oRange.setStartBefore( element ) ;
43308 var oFragment = oRange.createContextualFragment( html );
43309 element.parentNode.insertBefore( oFragment, element ) ;
43322 //Roo.reg('fckeditor', Roo.form.FCKeditor);
43324 function FCKeditor_OnComplete(editorInstance){
43325 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
43326 f.fckEditor = editorInstance;
43327 //console.log("loaded");
43328 f.fireEvent('editorinit', f, editorInstance);
43348 //<script type="text/javascript">
43350 * @class Roo.form.GridField
43351 * @extends Roo.form.Field
43352 * Embed a grid (or editable grid into a form)
43355 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
43357 * xgrid.store = Roo.data.Store
43358 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
43359 * xgrid.store.reader = Roo.data.JsonReader
43363 * Creates a new GridField
43364 * @param {Object} config Configuration options
43366 Roo.form.GridField = function(config){
43367 Roo.form.GridField.superclass.constructor.call(this, config);
43371 Roo.extend(Roo.form.GridField, Roo.form.Field, {
43373 * @cfg {Number} width - used to restrict width of grid..
43377 * @cfg {Number} height - used to restrict height of grid..
43381 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
43387 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43388 * {tag: "input", type: "checkbox", autocomplete: "off"})
43390 // defaultAutoCreate : { tag: 'div' },
43391 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43393 * @cfg {String} addTitle Text to include for adding a title.
43397 onResize : function(){
43398 Roo.form.Field.superclass.onResize.apply(this, arguments);
43401 initEvents : function(){
43402 // Roo.form.Checkbox.superclass.initEvents.call(this);
43403 // has no events...
43408 getResizeEl : function(){
43412 getPositionEl : function(){
43417 onRender : function(ct, position){
43419 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
43420 var style = this.style;
43423 Roo.form.GridField.superclass.onRender.call(this, ct, position);
43424 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
43425 this.viewEl = this.wrap.createChild({ tag: 'div' });
43427 this.viewEl.applyStyles(style);
43430 this.viewEl.setWidth(this.width);
43433 this.viewEl.setHeight(this.height);
43435 //if(this.inputValue !== undefined){
43436 //this.setValue(this.value);
43439 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
43442 this.grid.render();
43443 this.grid.getDataSource().on('remove', this.refreshValue, this);
43444 this.grid.getDataSource().on('update', this.refreshValue, this);
43445 this.grid.on('afteredit', this.refreshValue, this);
43451 * Sets the value of the item.
43452 * @param {String} either an object or a string..
43454 setValue : function(v){
43456 v = v || []; // empty set..
43457 // this does not seem smart - it really only affects memoryproxy grids..
43458 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
43459 var ds = this.grid.getDataSource();
43460 // assumes a json reader..
43462 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
43463 ds.loadData( data);
43465 // clear selection so it does not get stale.
43466 if (this.grid.sm) {
43467 this.grid.sm.clearSelections();
43470 Roo.form.GridField.superclass.setValue.call(this, v);
43471 this.refreshValue();
43472 // should load data in the grid really....
43476 refreshValue: function() {
43478 this.grid.getDataSource().each(function(r) {
43481 this.el.dom.value = Roo.encode(val);
43489 * Ext JS Library 1.1.1
43490 * Copyright(c) 2006-2007, Ext JS, LLC.
43492 * Originally Released Under LGPL - original licence link has changed is not relivant.
43495 * <script type="text/javascript">
43498 * @class Roo.form.DisplayField
43499 * @extends Roo.form.Field
43500 * A generic Field to display non-editable data.
43502 * Creates a new Display Field item.
43503 * @param {Object} config Configuration options
43505 Roo.form.DisplayField = function(config){
43506 Roo.form.DisplayField.superclass.constructor.call(this, config);
43510 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
43511 inputType: 'hidden',
43517 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43519 focusClass : undefined,
43521 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43523 fieldClass: 'x-form-field',
43526 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
43528 valueRenderer: undefined,
43532 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43533 * {tag: "input", type: "checkbox", autocomplete: "off"})
43536 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
43538 onResize : function(){
43539 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
43543 initEvents : function(){
43544 // Roo.form.Checkbox.superclass.initEvents.call(this);
43545 // has no events...
43550 getResizeEl : function(){
43554 getPositionEl : function(){
43559 onRender : function(ct, position){
43561 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
43562 //if(this.inputValue !== undefined){
43563 this.wrap = this.el.wrap();
43565 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
43567 if (this.bodyStyle) {
43568 this.viewEl.applyStyles(this.bodyStyle);
43570 //this.viewEl.setStyle('padding', '2px');
43572 this.setValue(this.value);
43577 initValue : Roo.emptyFn,
43582 onClick : function(){
43587 * Sets the checked state of the checkbox.
43588 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
43590 setValue : function(v){
43592 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
43593 // this might be called before we have a dom element..
43594 if (!this.viewEl) {
43597 this.viewEl.dom.innerHTML = html;
43598 Roo.form.DisplayField.superclass.setValue.call(this, v);
43608 * @class Roo.form.DayPicker
43609 * @extends Roo.form.Field
43610 * A Day picker show [M] [T] [W] ....
43612 * Creates a new Day Picker
43613 * @param {Object} config Configuration options
43615 Roo.form.DayPicker= function(config){
43616 Roo.form.DayPicker.superclass.constructor.call(this, config);
43620 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
43622 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43624 focusClass : undefined,
43626 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43628 fieldClass: "x-form-field",
43631 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43632 * {tag: "input", type: "checkbox", autocomplete: "off"})
43634 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43637 actionMode : 'viewEl',
43641 inputType : 'hidden',
43644 inputElement: false, // real input element?
43645 basedOn: false, // ????
43647 isFormField: true, // not sure where this is needed!!!!
43649 onResize : function(){
43650 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43651 if(!this.boxLabel){
43652 this.el.alignTo(this.wrap, 'c-c');
43656 initEvents : function(){
43657 Roo.form.Checkbox.superclass.initEvents.call(this);
43658 this.el.on("click", this.onClick, this);
43659 this.el.on("change", this.onClick, this);
43663 getResizeEl : function(){
43667 getPositionEl : function(){
43673 onRender : function(ct, position){
43674 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43676 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
43678 var r1 = '<table><tr>';
43679 var r2 = '<tr class="x-form-daypick-icons">';
43680 for (var i=0; i < 7; i++) {
43681 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
43682 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
43685 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
43686 viewEl.select('img').on('click', this.onClick, this);
43687 this.viewEl = viewEl;
43690 // this will not work on Chrome!!!
43691 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43692 this.el.on('propertychange', this.setFromHidden, this); //ie
43700 initValue : Roo.emptyFn,
43703 * Returns the checked state of the checkbox.
43704 * @return {Boolean} True if checked, else false
43706 getValue : function(){
43707 return this.el.dom.value;
43712 onClick : function(e){
43713 //this.setChecked(!this.checked);
43714 Roo.get(e.target).toggleClass('x-menu-item-checked');
43715 this.refreshValue();
43716 //if(this.el.dom.checked != this.checked){
43717 // this.setValue(this.el.dom.checked);
43722 refreshValue : function()
43725 this.viewEl.select('img',true).each(function(e,i,n) {
43726 val += e.is(".x-menu-item-checked") ? String(n) : '';
43728 this.setValue(val, true);
43732 * Sets the checked state of the checkbox.
43733 * On is always based on a string comparison between inputValue and the param.
43734 * @param {Boolean/String} value - the value to set
43735 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43737 setValue : function(v,suppressEvent){
43738 if (!this.el.dom) {
43741 var old = this.el.dom.value ;
43742 this.el.dom.value = v;
43743 if (suppressEvent) {
43747 // update display..
43748 this.viewEl.select('img',true).each(function(e,i,n) {
43750 var on = e.is(".x-menu-item-checked");
43751 var newv = v.indexOf(String(n)) > -1;
43753 e.toggleClass('x-menu-item-checked');
43759 this.fireEvent('change', this, v, old);
43764 // handle setting of hidden value by some other method!!?!?
43765 setFromHidden: function()
43770 //console.log("SET FROM HIDDEN");
43771 //alert('setFrom hidden');
43772 this.setValue(this.el.dom.value);
43775 onDestroy : function()
43778 Roo.get(this.viewEl).remove();
43781 Roo.form.DayPicker.superclass.onDestroy.call(this);
43785 * RooJS Library 1.1.1
43786 * Copyright(c) 2008-2011 Alan Knowles
43793 * @class Roo.form.ComboCheck
43794 * @extends Roo.form.ComboBox
43795 * A combobox for multiple select items.
43797 * FIXME - could do with a reset button..
43800 * Create a new ComboCheck
43801 * @param {Object} config Configuration options
43803 Roo.form.ComboCheck = function(config){
43804 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43805 // should verify some data...
43807 // hiddenName = required..
43808 // displayField = required
43809 // valudField == required
43810 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43812 Roo.each(req, function(e) {
43813 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43814 throw "Roo.form.ComboCheck : missing value for: " + e;
43821 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
43826 selectedClass: 'x-menu-item-checked',
43829 onRender : function(ct, position){
43835 var cls = 'x-combo-list';
43838 this.tpl = new Roo.Template({
43839 html : '<div class="'+cls+'-item x-menu-check-item">' +
43840 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
43841 '<span>{' + this.displayField + '}</span>' +
43848 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
43849 this.view.singleSelect = false;
43850 this.view.multiSelect = true;
43851 this.view.toggleSelect = true;
43852 this.pageTb.add(new Roo.Toolbar.Fill(), {
43855 handler: function()
43862 onViewOver : function(e, t){
43868 onViewClick : function(doFocus,index){
43872 select: function () {
43873 //Roo.log("SELECT CALLED");
43876 selectByValue : function(xv, scrollIntoView){
43877 var ar = this.getValueArray();
43880 Roo.each(ar, function(v) {
43881 if(v === undefined || v === null){
43884 var r = this.findRecord(this.valueField, v);
43886 sels.push(this.store.indexOf(r))
43890 this.view.select(sels);
43896 onSelect : function(record, index){
43897 // Roo.log("onselect Called");
43898 // this is only called by the clear button now..
43899 this.view.clearSelections();
43900 this.setValue('[]');
43901 if (this.value != this.valueBefore) {
43902 this.fireEvent('change', this, this.value, this.valueBefore);
43905 getValueArray : function()
43910 //Roo.log(this.value);
43911 if (typeof(this.value) == 'undefined') {
43914 var ar = Roo.decode(this.value);
43915 return ar instanceof Array ? ar : []; //?? valid?
43918 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
43923 expand : function ()
43925 Roo.form.ComboCheck.superclass.expand.call(this);
43926 this.valueBefore = this.value;
43931 collapse : function(){
43932 Roo.form.ComboCheck.superclass.collapse.call(this);
43933 var sl = this.view.getSelectedIndexes();
43934 var st = this.store;
43938 Roo.each(sl, function(i) {
43940 nv.push(r.get(this.valueField));
43942 this.setValue(Roo.encode(nv));
43943 if (this.value != this.valueBefore) {
43945 this.fireEvent('change', this, this.value, this.valueBefore);
43950 setValue : function(v){
43954 var vals = this.getValueArray();
43956 Roo.each(vals, function(k) {
43957 var r = this.findRecord(this.valueField, k);
43959 tv.push(r.data[this.displayField]);
43960 }else if(this.valueNotFoundText !== undefined){
43961 tv.push( this.valueNotFoundText );
43966 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
43967 this.hiddenField.value = v;
43971 });//<script type="text/javasscript">
43975 * @class Roo.DDView
43976 * A DnD enabled version of Roo.View.
43977 * @param {Element/String} container The Element in which to create the View.
43978 * @param {String} tpl The template string used to create the markup for each element of the View
43979 * @param {Object} config The configuration properties. These include all the config options of
43980 * {@link Roo.View} plus some specific to this class.<br>
43982 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
43983 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
43985 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
43986 .x-view-drag-insert-above {
43987 border-top:1px dotted #3366cc;
43989 .x-view-drag-insert-below {
43990 border-bottom:1px dotted #3366cc;
43996 Roo.DDView = function(container, tpl, config) {
43997 Roo.DDView.superclass.constructor.apply(this, arguments);
43998 this.getEl().setStyle("outline", "0px none");
43999 this.getEl().unselectable();
44000 if (this.dragGroup) {
44001 this.setDraggable(this.dragGroup.split(","));
44003 if (this.dropGroup) {
44004 this.setDroppable(this.dropGroup.split(","));
44006 if (this.deletable) {
44007 this.setDeletable();
44009 this.isDirtyFlag = false;
44015 Roo.extend(Roo.DDView, Roo.View, {
44016 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
44017 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
44018 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
44019 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
44023 reset: Roo.emptyFn,
44025 clearInvalid: Roo.form.Field.prototype.clearInvalid,
44027 validate: function() {
44031 destroy: function() {
44032 this.purgeListeners();
44033 this.getEl.removeAllListeners();
44034 this.getEl().remove();
44035 if (this.dragZone) {
44036 if (this.dragZone.destroy) {
44037 this.dragZone.destroy();
44040 if (this.dropZone) {
44041 if (this.dropZone.destroy) {
44042 this.dropZone.destroy();
44047 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
44048 getName: function() {
44052 /** Loads the View from a JSON string representing the Records to put into the Store. */
44053 setValue: function(v) {
44055 throw "DDView.setValue(). DDView must be constructed with a valid Store";
44058 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
44059 this.store.proxy = new Roo.data.MemoryProxy(data);
44063 /** @return {String} a parenthesised list of the ids of the Records in the View. */
44064 getValue: function() {
44066 this.store.each(function(rec) {
44067 result += rec.id + ',';
44069 return result.substr(0, result.length - 1) + ')';
44072 getIds: function() {
44073 var i = 0, result = new Array(this.store.getCount());
44074 this.store.each(function(rec) {
44075 result[i++] = rec.id;
44080 isDirty: function() {
44081 return this.isDirtyFlag;
44085 * Part of the Roo.dd.DropZone interface. If no target node is found, the
44086 * whole Element becomes the target, and this causes the drop gesture to append.
44088 getTargetFromEvent : function(e) {
44089 var target = e.getTarget();
44090 while ((target !== null) && (target.parentNode != this.el.dom)) {
44091 target = target.parentNode;
44094 target = this.el.dom.lastChild || this.el.dom;
44100 * Create the drag data which consists of an object which has the property "ddel" as
44101 * the drag proxy element.
44103 getDragData : function(e) {
44104 var target = this.findItemFromChild(e.getTarget());
44106 this.handleSelection(e);
44107 var selNodes = this.getSelectedNodes();
44110 copy: this.copy || (this.allowCopy && e.ctrlKey),
44114 var selectedIndices = this.getSelectedIndexes();
44115 for (var i = 0; i < selectedIndices.length; i++) {
44116 dragData.records.push(this.store.getAt(selectedIndices[i]));
44118 if (selNodes.length == 1) {
44119 dragData.ddel = target.cloneNode(true); // the div element
44121 var div = document.createElement('div'); // create the multi element drag "ghost"
44122 div.className = 'multi-proxy';
44123 for (var i = 0, len = selNodes.length; i < len; i++) {
44124 div.appendChild(selNodes[i].cloneNode(true));
44126 dragData.ddel = div;
44128 //console.log(dragData)
44129 //console.log(dragData.ddel.innerHTML)
44132 //console.log('nodragData')
44136 /** Specify to which ddGroup items in this DDView may be dragged. */
44137 setDraggable: function(ddGroup) {
44138 if (ddGroup instanceof Array) {
44139 Roo.each(ddGroup, this.setDraggable, this);
44142 if (this.dragZone) {
44143 this.dragZone.addToGroup(ddGroup);
44145 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
44146 containerScroll: true,
44150 // Draggability implies selection. DragZone's mousedown selects the element.
44151 if (!this.multiSelect) { this.singleSelect = true; }
44153 // Wire the DragZone's handlers up to methods in *this*
44154 this.dragZone.getDragData = this.getDragData.createDelegate(this);
44158 /** Specify from which ddGroup this DDView accepts drops. */
44159 setDroppable: function(ddGroup) {
44160 if (ddGroup instanceof Array) {
44161 Roo.each(ddGroup, this.setDroppable, this);
44164 if (this.dropZone) {
44165 this.dropZone.addToGroup(ddGroup);
44167 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
44168 containerScroll: true,
44172 // Wire the DropZone's handlers up to methods in *this*
44173 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
44174 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
44175 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
44176 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
44177 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
44181 /** Decide whether to drop above or below a View node. */
44182 getDropPoint : function(e, n, dd){
44183 if (n == this.el.dom) { return "above"; }
44184 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
44185 var c = t + (b - t) / 2;
44186 var y = Roo.lib.Event.getPageY(e);
44194 onNodeEnter : function(n, dd, e, data){
44198 onNodeOver : function(n, dd, e, data){
44199 var pt = this.getDropPoint(e, n, dd);
44200 // set the insert point style on the target node
44201 var dragElClass = this.dropNotAllowed;
44204 if (pt == "above"){
44205 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
44206 targetElClass = "x-view-drag-insert-above";
44208 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
44209 targetElClass = "x-view-drag-insert-below";
44211 if (this.lastInsertClass != targetElClass){
44212 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
44213 this.lastInsertClass = targetElClass;
44216 return dragElClass;
44219 onNodeOut : function(n, dd, e, data){
44220 this.removeDropIndicators(n);
44223 onNodeDrop : function(n, dd, e, data){
44224 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
44227 var pt = this.getDropPoint(e, n, dd);
44228 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
44229 if (pt == "below") { insertAt++; }
44230 for (var i = 0; i < data.records.length; i++) {
44231 var r = data.records[i];
44232 var dup = this.store.getById(r.id);
44233 if (dup && (dd != this.dragZone)) {
44234 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
44237 this.store.insert(insertAt++, r.copy());
44239 data.source.isDirtyFlag = true;
44241 this.store.insert(insertAt++, r);
44243 this.isDirtyFlag = true;
44246 this.dragZone.cachedTarget = null;
44250 removeDropIndicators : function(n){
44252 Roo.fly(n).removeClass([
44253 "x-view-drag-insert-above",
44254 "x-view-drag-insert-below"]);
44255 this.lastInsertClass = "_noclass";
44260 * Utility method. Add a delete option to the DDView's context menu.
44261 * @param {String} imageUrl The URL of the "delete" icon image.
44263 setDeletable: function(imageUrl) {
44264 if (!this.singleSelect && !this.multiSelect) {
44265 this.singleSelect = true;
44267 var c = this.getContextMenu();
44268 this.contextMenu.on("itemclick", function(item) {
44271 this.remove(this.getSelectedIndexes());
44275 this.contextMenu.add({
44282 /** Return the context menu for this DDView. */
44283 getContextMenu: function() {
44284 if (!this.contextMenu) {
44285 // Create the View's context menu
44286 this.contextMenu = new Roo.menu.Menu({
44287 id: this.id + "-contextmenu"
44289 this.el.on("contextmenu", this.showContextMenu, this);
44291 return this.contextMenu;
44294 disableContextMenu: function() {
44295 if (this.contextMenu) {
44296 this.el.un("contextmenu", this.showContextMenu, this);
44300 showContextMenu: function(e, item) {
44301 item = this.findItemFromChild(e.getTarget());
44304 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
44305 this.contextMenu.showAt(e.getXY());
44310 * Remove {@link Roo.data.Record}s at the specified indices.
44311 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
44313 remove: function(selectedIndices) {
44314 selectedIndices = [].concat(selectedIndices);
44315 for (var i = 0; i < selectedIndices.length; i++) {
44316 var rec = this.store.getAt(selectedIndices[i]);
44317 this.store.remove(rec);
44322 * Double click fires the event, but also, if this is draggable, and there is only one other
44323 * related DropZone, it transfers the selected node.
44325 onDblClick : function(e){
44326 var item = this.findItemFromChild(e.getTarget());
44328 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
44331 if (this.dragGroup) {
44332 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
44333 while (targets.indexOf(this.dropZone) > -1) {
44334 targets.remove(this.dropZone);
44336 if (targets.length == 1) {
44337 this.dragZone.cachedTarget = null;
44338 var el = Roo.get(targets[0].getEl());
44339 var box = el.getBox(true);
44340 targets[0].onNodeDrop(el.dom, {
44342 xy: [box.x, box.y + box.height - 1]
44343 }, null, this.getDragData(e));
44349 handleSelection: function(e) {
44350 this.dragZone.cachedTarget = null;
44351 var item = this.findItemFromChild(e.getTarget());
44353 this.clearSelections(true);
44356 if (item && (this.multiSelect || this.singleSelect)){
44357 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
44358 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
44359 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
44360 this.unselect(item);
44362 this.select(item, this.multiSelect && e.ctrlKey);
44363 this.lastSelection = item;
44368 onItemClick : function(item, index, e){
44369 if(this.fireEvent("beforeclick", this, index, item, e) === false){
44375 unselect : function(nodeInfo, suppressEvent){
44376 var node = this.getNode(nodeInfo);
44377 if(node && this.isSelected(node)){
44378 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
44379 Roo.fly(node).removeClass(this.selectedClass);
44380 this.selections.remove(node);
44381 if(!suppressEvent){
44382 this.fireEvent("selectionchange", this, this.selections);
44390 * Ext JS Library 1.1.1
44391 * Copyright(c) 2006-2007, Ext JS, LLC.
44393 * Originally Released Under LGPL - original licence link has changed is not relivant.
44396 * <script type="text/javascript">
44400 * @class Roo.LayoutManager
44401 * @extends Roo.util.Observable
44402 * Base class for layout managers.
44404 Roo.LayoutManager = function(container, config){
44405 Roo.LayoutManager.superclass.constructor.call(this);
44406 this.el = Roo.get(container);
44407 // ie scrollbar fix
44408 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
44409 document.body.scroll = "no";
44410 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
44411 this.el.position('relative');
44413 this.id = this.el.id;
44414 this.el.addClass("x-layout-container");
44415 /** false to disable window resize monitoring @type Boolean */
44416 this.monitorWindowResize = true;
44421 * Fires when a layout is performed.
44422 * @param {Roo.LayoutManager} this
44426 * @event regionresized
44427 * Fires when the user resizes a region.
44428 * @param {Roo.LayoutRegion} region The resized region
44429 * @param {Number} newSize The new size (width for east/west, height for north/south)
44431 "regionresized" : true,
44433 * @event regioncollapsed
44434 * Fires when a region is collapsed.
44435 * @param {Roo.LayoutRegion} region The collapsed region
44437 "regioncollapsed" : true,
44439 * @event regionexpanded
44440 * Fires when a region is expanded.
44441 * @param {Roo.LayoutRegion} region The expanded region
44443 "regionexpanded" : true
44445 this.updating = false;
44446 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
44449 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
44451 * Returns true if this layout is currently being updated
44452 * @return {Boolean}
44454 isUpdating : function(){
44455 return this.updating;
44459 * Suspend the LayoutManager from doing auto-layouts while
44460 * making multiple add or remove calls
44462 beginUpdate : function(){
44463 this.updating = true;
44467 * Restore auto-layouts and optionally disable the manager from performing a layout
44468 * @param {Boolean} noLayout true to disable a layout update
44470 endUpdate : function(noLayout){
44471 this.updating = false;
44477 layout: function(){
44481 onRegionResized : function(region, newSize){
44482 this.fireEvent("regionresized", region, newSize);
44486 onRegionCollapsed : function(region){
44487 this.fireEvent("regioncollapsed", region);
44490 onRegionExpanded : function(region){
44491 this.fireEvent("regionexpanded", region);
44495 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
44496 * performs box-model adjustments.
44497 * @return {Object} The size as an object {width: (the width), height: (the height)}
44499 getViewSize : function(){
44501 if(this.el.dom != document.body){
44502 size = this.el.getSize();
44504 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
44506 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
44507 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
44512 * Returns the Element this layout is bound to.
44513 * @return {Roo.Element}
44515 getEl : function(){
44520 * Returns the specified region.
44521 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
44522 * @return {Roo.LayoutRegion}
44524 getRegion : function(target){
44525 return this.regions[target.toLowerCase()];
44528 onWindowResize : function(){
44529 if(this.monitorWindowResize){
44535 * Ext JS Library 1.1.1
44536 * Copyright(c) 2006-2007, Ext JS, LLC.
44538 * Originally Released Under LGPL - original licence link has changed is not relivant.
44541 * <script type="text/javascript">
44544 * @class Roo.BorderLayout
44545 * @extends Roo.LayoutManager
44546 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
44547 * please see: <br><br>
44548 * <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>
44549 * <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>
44552 var layout = new Roo.BorderLayout(document.body, {
44586 preferredTabWidth: 150
44591 var CP = Roo.ContentPanel;
44593 layout.beginUpdate();
44594 layout.add("north", new CP("north", "North"));
44595 layout.add("south", new CP("south", {title: "South", closable: true}));
44596 layout.add("west", new CP("west", {title: "West"}));
44597 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
44598 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
44599 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
44600 layout.getRegion("center").showPanel("center1");
44601 layout.endUpdate();
44604 <b>The container the layout is rendered into can be either the body element or any other element.
44605 If it is not the body element, the container needs to either be an absolute positioned element,
44606 or you will need to add "position:relative" to the css of the container. You will also need to specify
44607 the container size if it is not the body element.</b>
44610 * Create a new BorderLayout
44611 * @param {String/HTMLElement/Element} container The container this layout is bound to
44612 * @param {Object} config Configuration options
44614 Roo.BorderLayout = function(container, config){
44615 config = config || {};
44616 Roo.BorderLayout.superclass.constructor.call(this, container, config);
44617 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
44618 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
44619 var target = this.factory.validRegions[i];
44620 if(config[target]){
44621 this.addRegion(target, config[target]);
44626 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
44628 * Creates and adds a new region if it doesn't already exist.
44629 * @param {String} target The target region key (north, south, east, west or center).
44630 * @param {Object} config The regions config object
44631 * @return {BorderLayoutRegion} The new region
44633 addRegion : function(target, config){
44634 if(!this.regions[target]){
44635 var r = this.factory.create(target, this, config);
44636 this.bindRegion(target, r);
44638 return this.regions[target];
44642 bindRegion : function(name, r){
44643 this.regions[name] = r;
44644 r.on("visibilitychange", this.layout, this);
44645 r.on("paneladded", this.layout, this);
44646 r.on("panelremoved", this.layout, this);
44647 r.on("invalidated", this.layout, this);
44648 r.on("resized", this.onRegionResized, this);
44649 r.on("collapsed", this.onRegionCollapsed, this);
44650 r.on("expanded", this.onRegionExpanded, this);
44654 * Performs a layout update.
44656 layout : function(){
44657 if(this.updating) return;
44658 var size = this.getViewSize();
44659 var w = size.width;
44660 var h = size.height;
44665 //var x = 0, y = 0;
44667 var rs = this.regions;
44668 var north = rs["north"];
44669 var south = rs["south"];
44670 var west = rs["west"];
44671 var east = rs["east"];
44672 var center = rs["center"];
44673 //if(this.hideOnLayout){ // not supported anymore
44674 //c.el.setStyle("display", "none");
44676 if(north && north.isVisible()){
44677 var b = north.getBox();
44678 var m = north.getMargins();
44679 b.width = w - (m.left+m.right);
44682 centerY = b.height + b.y + m.bottom;
44683 centerH -= centerY;
44684 north.updateBox(this.safeBox(b));
44686 if(south && south.isVisible()){
44687 var b = south.getBox();
44688 var m = south.getMargins();
44689 b.width = w - (m.left+m.right);
44691 var totalHeight = (b.height + m.top + m.bottom);
44692 b.y = h - totalHeight + m.top;
44693 centerH -= totalHeight;
44694 south.updateBox(this.safeBox(b));
44696 if(west && west.isVisible()){
44697 var b = west.getBox();
44698 var m = west.getMargins();
44699 b.height = centerH - (m.top+m.bottom);
44701 b.y = centerY + m.top;
44702 var totalWidth = (b.width + m.left + m.right);
44703 centerX += totalWidth;
44704 centerW -= totalWidth;
44705 west.updateBox(this.safeBox(b));
44707 if(east && east.isVisible()){
44708 var b = east.getBox();
44709 var m = east.getMargins();
44710 b.height = centerH - (m.top+m.bottom);
44711 var totalWidth = (b.width + m.left + m.right);
44712 b.x = w - totalWidth + m.left;
44713 b.y = centerY + m.top;
44714 centerW -= totalWidth;
44715 east.updateBox(this.safeBox(b));
44718 var m = center.getMargins();
44720 x: centerX + m.left,
44721 y: centerY + m.top,
44722 width: centerW - (m.left+m.right),
44723 height: centerH - (m.top+m.bottom)
44725 //if(this.hideOnLayout){
44726 //center.el.setStyle("display", "block");
44728 center.updateBox(this.safeBox(centerBox));
44731 this.fireEvent("layout", this);
44735 safeBox : function(box){
44736 box.width = Math.max(0, box.width);
44737 box.height = Math.max(0, box.height);
44742 * Adds a ContentPanel (or subclass) to this layout.
44743 * @param {String} target The target region key (north, south, east, west or center).
44744 * @param {Roo.ContentPanel} panel The panel to add
44745 * @return {Roo.ContentPanel} The added panel
44747 add : function(target, panel){
44749 target = target.toLowerCase();
44750 return this.regions[target].add(panel);
44754 * Remove a ContentPanel (or subclass) to this layout.
44755 * @param {String} target The target region key (north, south, east, west or center).
44756 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
44757 * @return {Roo.ContentPanel} The removed panel
44759 remove : function(target, panel){
44760 target = target.toLowerCase();
44761 return this.regions[target].remove(panel);
44765 * Searches all regions for a panel with the specified id
44766 * @param {String} panelId
44767 * @return {Roo.ContentPanel} The panel or null if it wasn't found
44769 findPanel : function(panelId){
44770 var rs = this.regions;
44771 for(var target in rs){
44772 if(typeof rs[target] != "function"){
44773 var p = rs[target].getPanel(panelId);
44783 * Searches all regions for a panel with the specified id and activates (shows) it.
44784 * @param {String/ContentPanel} panelId The panels id or the panel itself
44785 * @return {Roo.ContentPanel} The shown panel or null
44787 showPanel : function(panelId) {
44788 var rs = this.regions;
44789 for(var target in rs){
44790 var r = rs[target];
44791 if(typeof r != "function"){
44792 if(r.hasPanel(panelId)){
44793 return r.showPanel(panelId);
44801 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
44802 * @param {Roo.state.Provider} provider (optional) An alternate state provider
44804 restoreState : function(provider){
44806 provider = Roo.state.Manager;
44808 var sm = new Roo.LayoutStateManager();
44809 sm.init(this, provider);
44813 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
44814 * object should contain properties for each region to add ContentPanels to, and each property's value should be
44815 * a valid ContentPanel config object. Example:
44817 // Create the main layout
44818 var layout = new Roo.BorderLayout('main-ct', {
44829 // Create and add multiple ContentPanels at once via configs
44832 id: 'source-files',
44834 title:'Ext Source Files',
44847 * @param {Object} regions An object containing ContentPanel configs by region name
44849 batchAdd : function(regions){
44850 this.beginUpdate();
44851 for(var rname in regions){
44852 var lr = this.regions[rname];
44854 this.addTypedPanels(lr, regions[rname]);
44861 addTypedPanels : function(lr, ps){
44862 if(typeof ps == 'string'){
44863 lr.add(new Roo.ContentPanel(ps));
44865 else if(ps instanceof Array){
44866 for(var i =0, len = ps.length; i < len; i++){
44867 this.addTypedPanels(lr, ps[i]);
44870 else if(!ps.events){ // raw config?
44872 delete ps.el; // prevent conflict
44873 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
44875 else { // panel object assumed!
44880 * Adds a xtype elements to the layout.
44884 xtype : 'ContentPanel',
44891 xtype : 'NestedLayoutPanel',
44897 items : [ ... list of content panels or nested layout panels.. ]
44901 * @param {Object} cfg Xtype definition of item to add.
44903 addxtype : function(cfg)
44905 // basically accepts a pannel...
44906 // can accept a layout region..!?!?
44907 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
44909 if (!cfg.xtype.match(/Panel$/)) {
44914 if (typeof(cfg.region) == 'undefined') {
44915 Roo.log("Failed to add Panel, region was not set");
44919 var region = cfg.region;
44925 xitems = cfg.items;
44932 case 'ContentPanel': // ContentPanel (el, cfg)
44933 case 'ScrollPanel': // ContentPanel (el, cfg)
44934 if(cfg.autoCreate) {
44935 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44937 var el = this.el.createChild();
44938 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
44941 this.add(region, ret);
44945 case 'TreePanel': // our new panel!
44946 cfg.el = this.el.createChild();
44947 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
44948 this.add(region, ret);
44951 case 'NestedLayoutPanel':
44952 // create a new Layout (which is a Border Layout...
44953 var el = this.el.createChild();
44954 var clayout = cfg.layout;
44956 clayout.items = clayout.items || [];
44957 // replace this exitems with the clayout ones..
44958 xitems = clayout.items;
44961 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
44962 cfg.background = false;
44964 var layout = new Roo.BorderLayout(el, clayout);
44966 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
44967 //console.log('adding nested layout panel ' + cfg.toSource());
44968 this.add(region, ret);
44969 nb = {}; /// find first...
44974 // needs grid and region
44976 //var el = this.getRegion(region).el.createChild();
44977 var el = this.el.createChild();
44978 // create the grid first...
44980 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
44982 if (region == 'center' && this.active ) {
44983 cfg.background = false;
44985 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
44987 this.add(region, ret);
44988 if (cfg.background) {
44989 ret.on('activate', function(gp) {
44990 if (!gp.grid.rendered) {
45003 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
45005 // GridPanel (grid, cfg)
45008 this.beginUpdate();
45012 Roo.each(xitems, function(i) {
45013 region = nb && i.region ? i.region : false;
45015 var add = ret.addxtype(i);
45018 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
45019 if (!i.background) {
45020 abn[region] = nb[region] ;
45027 // make the last non-background panel active..
45028 //if (nb) { Roo.log(abn); }
45031 for(var r in abn) {
45032 region = this.getRegion(r);
45034 // tried using nb[r], but it does not work..
45036 region.showPanel(abn[r]);
45047 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
45048 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
45049 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
45050 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
45053 var CP = Roo.ContentPanel;
45055 var layout = Roo.BorderLayout.create({
45059 panels: [new CP("north", "North")]
45068 panels: [new CP("west", {title: "West"})]
45077 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
45086 panels: [new CP("south", {title: "South", closable: true})]
45093 preferredTabWidth: 150,
45095 new CP("center1", {title: "Close Me", closable: true}),
45096 new CP("center2", {title: "Center Panel", closable: false})
45101 layout.getRegion("center").showPanel("center1");
45106 Roo.BorderLayout.create = function(config, targetEl){
45107 var layout = new Roo.BorderLayout(targetEl || document.body, config);
45108 layout.beginUpdate();
45109 var regions = Roo.BorderLayout.RegionFactory.validRegions;
45110 for(var j = 0, jlen = regions.length; j < jlen; j++){
45111 var lr = regions[j];
45112 if(layout.regions[lr] && config[lr].panels){
45113 var r = layout.regions[lr];
45114 var ps = config[lr].panels;
45115 layout.addTypedPanels(r, ps);
45118 layout.endUpdate();
45123 Roo.BorderLayout.RegionFactory = {
45125 validRegions : ["north","south","east","west","center"],
45128 create : function(target, mgr, config){
45129 target = target.toLowerCase();
45130 if(config.lightweight || config.basic){
45131 return new Roo.BasicLayoutRegion(mgr, config, target);
45135 return new Roo.NorthLayoutRegion(mgr, config);
45137 return new Roo.SouthLayoutRegion(mgr, config);
45139 return new Roo.EastLayoutRegion(mgr, config);
45141 return new Roo.WestLayoutRegion(mgr, config);
45143 return new Roo.CenterLayoutRegion(mgr, config);
45145 throw 'Layout region "'+target+'" not supported.';
45149 * Ext JS Library 1.1.1
45150 * Copyright(c) 2006-2007, Ext JS, LLC.
45152 * Originally Released Under LGPL - original licence link has changed is not relivant.
45155 * <script type="text/javascript">
45159 * @class Roo.BasicLayoutRegion
45160 * @extends Roo.util.Observable
45161 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
45162 * and does not have a titlebar, tabs or any other features. All it does is size and position
45163 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
45165 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
45167 this.position = pos;
45170 * @scope Roo.BasicLayoutRegion
45174 * @event beforeremove
45175 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
45176 * @param {Roo.LayoutRegion} this
45177 * @param {Roo.ContentPanel} panel The panel
45178 * @param {Object} e The cancel event object
45180 "beforeremove" : true,
45182 * @event invalidated
45183 * Fires when the layout for this region is changed.
45184 * @param {Roo.LayoutRegion} this
45186 "invalidated" : true,
45188 * @event visibilitychange
45189 * Fires when this region is shown or hidden
45190 * @param {Roo.LayoutRegion} this
45191 * @param {Boolean} visibility true or false
45193 "visibilitychange" : true,
45195 * @event paneladded
45196 * Fires when a panel is added.
45197 * @param {Roo.LayoutRegion} this
45198 * @param {Roo.ContentPanel} panel The panel
45200 "paneladded" : true,
45202 * @event panelremoved
45203 * Fires when a panel is removed.
45204 * @param {Roo.LayoutRegion} this
45205 * @param {Roo.ContentPanel} panel The panel
45207 "panelremoved" : true,
45210 * Fires when this region is collapsed.
45211 * @param {Roo.LayoutRegion} this
45213 "collapsed" : true,
45216 * Fires when this region is expanded.
45217 * @param {Roo.LayoutRegion} this
45222 * Fires when this region is slid into view.
45223 * @param {Roo.LayoutRegion} this
45225 "slideshow" : true,
45228 * Fires when this region slides out of view.
45229 * @param {Roo.LayoutRegion} this
45231 "slidehide" : true,
45233 * @event panelactivated
45234 * Fires when a panel is activated.
45235 * @param {Roo.LayoutRegion} this
45236 * @param {Roo.ContentPanel} panel The activated panel
45238 "panelactivated" : true,
45241 * Fires when the user resizes this region.
45242 * @param {Roo.LayoutRegion} this
45243 * @param {Number} newSize The new size (width for east/west, height for north/south)
45247 /** A collection of panels in this region. @type Roo.util.MixedCollection */
45248 this.panels = new Roo.util.MixedCollection();
45249 this.panels.getKey = this.getPanelId.createDelegate(this);
45251 this.activePanel = null;
45252 // ensure listeners are added...
45254 if (config.listeners || config.events) {
45255 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
45256 listeners : config.listeners || {},
45257 events : config.events || {}
45261 if(skipConfig !== true){
45262 this.applyConfig(config);
45266 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
45267 getPanelId : function(p){
45271 applyConfig : function(config){
45272 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45273 this.config = config;
45278 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
45279 * the width, for horizontal (north, south) the height.
45280 * @param {Number} newSize The new width or height
45282 resizeTo : function(newSize){
45283 var el = this.el ? this.el :
45284 (this.activePanel ? this.activePanel.getEl() : null);
45286 switch(this.position){
45289 el.setWidth(newSize);
45290 this.fireEvent("resized", this, newSize);
45294 el.setHeight(newSize);
45295 this.fireEvent("resized", this, newSize);
45301 getBox : function(){
45302 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
45305 getMargins : function(){
45306 return this.margins;
45309 updateBox : function(box){
45311 var el = this.activePanel.getEl();
45312 el.dom.style.left = box.x + "px";
45313 el.dom.style.top = box.y + "px";
45314 this.activePanel.setSize(box.width, box.height);
45318 * Returns the container element for this region.
45319 * @return {Roo.Element}
45321 getEl : function(){
45322 return this.activePanel;
45326 * Returns true if this region is currently visible.
45327 * @return {Boolean}
45329 isVisible : function(){
45330 return this.activePanel ? true : false;
45333 setActivePanel : function(panel){
45334 panel = this.getPanel(panel);
45335 if(this.activePanel && this.activePanel != panel){
45336 this.activePanel.setActiveState(false);
45337 this.activePanel.getEl().setLeftTop(-10000,-10000);
45339 this.activePanel = panel;
45340 panel.setActiveState(true);
45342 panel.setSize(this.box.width, this.box.height);
45344 this.fireEvent("panelactivated", this, panel);
45345 this.fireEvent("invalidated");
45349 * Show the specified panel.
45350 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
45351 * @return {Roo.ContentPanel} The shown panel or null
45353 showPanel : function(panel){
45354 if(panel = this.getPanel(panel)){
45355 this.setActivePanel(panel);
45361 * Get the active panel for this region.
45362 * @return {Roo.ContentPanel} The active panel or null
45364 getActivePanel : function(){
45365 return this.activePanel;
45369 * Add the passed ContentPanel(s)
45370 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45371 * @return {Roo.ContentPanel} The panel added (if only one was added)
45373 add : function(panel){
45374 if(arguments.length > 1){
45375 for(var i = 0, len = arguments.length; i < len; i++) {
45376 this.add(arguments[i]);
45380 if(this.hasPanel(panel)){
45381 this.showPanel(panel);
45384 var el = panel.getEl();
45385 if(el.dom.parentNode != this.mgr.el.dom){
45386 this.mgr.el.dom.appendChild(el.dom);
45388 if(panel.setRegion){
45389 panel.setRegion(this);
45391 this.panels.add(panel);
45392 el.setStyle("position", "absolute");
45393 if(!panel.background){
45394 this.setActivePanel(panel);
45395 if(this.config.initialSize && this.panels.getCount()==1){
45396 this.resizeTo(this.config.initialSize);
45399 this.fireEvent("paneladded", this, panel);
45404 * Returns true if the panel is in this region.
45405 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45406 * @return {Boolean}
45408 hasPanel : function(panel){
45409 if(typeof panel == "object"){ // must be panel obj
45410 panel = panel.getId();
45412 return this.getPanel(panel) ? true : false;
45416 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
45417 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45418 * @param {Boolean} preservePanel Overrides the config preservePanel option
45419 * @return {Roo.ContentPanel} The panel that was removed
45421 remove : function(panel, preservePanel){
45422 panel = this.getPanel(panel);
45427 this.fireEvent("beforeremove", this, panel, e);
45428 if(e.cancel === true){
45431 var panelId = panel.getId();
45432 this.panels.removeKey(panelId);
45437 * Returns the panel specified or null if it's not in this region.
45438 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
45439 * @return {Roo.ContentPanel}
45441 getPanel : function(id){
45442 if(typeof id == "object"){ // must be panel obj
45445 return this.panels.get(id);
45449 * Returns this regions position (north/south/east/west/center).
45452 getPosition: function(){
45453 return this.position;
45457 * Ext JS Library 1.1.1
45458 * Copyright(c) 2006-2007, Ext JS, LLC.
45460 * Originally Released Under LGPL - original licence link has changed is not relivant.
45463 * <script type="text/javascript">
45467 * @class Roo.LayoutRegion
45468 * @extends Roo.BasicLayoutRegion
45469 * This class represents a region in a layout manager.
45470 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
45471 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
45472 * @cfg {Boolean} floatable False to disable floating (defaults to true)
45473 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
45474 * @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})
45475 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
45476 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
45477 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
45478 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
45479 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
45480 * @cfg {String} title The title for the region (overrides panel titles)
45481 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
45482 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
45483 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
45484 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
45485 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
45486 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
45487 * the space available, similar to FireFox 1.5 tabs (defaults to false)
45488 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
45489 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
45490 * @cfg {Boolean} showPin True to show a pin button
45491 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
45492 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
45493 * @cfg {Boolean} disableTabTips True to disable tab tooltips
45494 * @cfg {Number} width For East/West panels
45495 * @cfg {Number} height For North/South panels
45496 * @cfg {Boolean} split To show the splitter
45497 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
45499 Roo.LayoutRegion = function(mgr, config, pos){
45500 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
45501 var dh = Roo.DomHelper;
45502 /** This region's container element
45503 * @type Roo.Element */
45504 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
45505 /** This region's title element
45506 * @type Roo.Element */
45508 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
45509 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
45510 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
45512 this.titleEl.enableDisplayMode();
45513 /** This region's title text element
45514 * @type HTMLElement */
45515 this.titleTextEl = this.titleEl.dom.firstChild;
45516 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
45517 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
45518 this.closeBtn.enableDisplayMode();
45519 this.closeBtn.on("click", this.closeClicked, this);
45520 this.closeBtn.hide();
45522 this.createBody(config);
45523 this.visible = true;
45524 this.collapsed = false;
45526 if(config.hideWhenEmpty){
45528 this.on("paneladded", this.validateVisibility, this);
45529 this.on("panelremoved", this.validateVisibility, this);
45531 this.applyConfig(config);
45534 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
45536 createBody : function(){
45537 /** This region's body element
45538 * @type Roo.Element */
45539 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
45542 applyConfig : function(c){
45543 if(c.collapsible && this.position != "center" && !this.collapsedEl){
45544 var dh = Roo.DomHelper;
45545 if(c.titlebar !== false){
45546 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
45547 this.collapseBtn.on("click", this.collapse, this);
45548 this.collapseBtn.enableDisplayMode();
45550 if(c.showPin === true || this.showPin){
45551 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
45552 this.stickBtn.enableDisplayMode();
45553 this.stickBtn.on("click", this.expand, this);
45554 this.stickBtn.hide();
45557 /** This region's collapsed element
45558 * @type Roo.Element */
45559 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
45560 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
45562 if(c.floatable !== false){
45563 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
45564 this.collapsedEl.on("click", this.collapseClick, this);
45567 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
45568 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
45569 id: "message", unselectable: "on", style:{"float":"left"}});
45570 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
45572 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
45573 this.expandBtn.on("click", this.expand, this);
45575 if(this.collapseBtn){
45576 this.collapseBtn.setVisible(c.collapsible == true);
45578 this.cmargins = c.cmargins || this.cmargins ||
45579 (this.position == "west" || this.position == "east" ?
45580 {top: 0, left: 2, right:2, bottom: 0} :
45581 {top: 2, left: 0, right:0, bottom: 2});
45582 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
45583 this.bottomTabs = c.tabPosition != "top";
45584 this.autoScroll = c.autoScroll || false;
45585 if(this.autoScroll){
45586 this.bodyEl.setStyle("overflow", "auto");
45588 this.bodyEl.setStyle("overflow", "hidden");
45590 //if(c.titlebar !== false){
45591 if((!c.titlebar && !c.title) || c.titlebar === false){
45592 this.titleEl.hide();
45594 this.titleEl.show();
45596 this.titleTextEl.innerHTML = c.title;
45600 this.duration = c.duration || .30;
45601 this.slideDuration = c.slideDuration || .45;
45604 this.collapse(true);
45611 * Returns true if this region is currently visible.
45612 * @return {Boolean}
45614 isVisible : function(){
45615 return this.visible;
45619 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
45620 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
45622 setCollapsedTitle : function(title){
45623 title = title || " ";
45624 if(this.collapsedTitleTextEl){
45625 this.collapsedTitleTextEl.innerHTML = title;
45629 getBox : function(){
45631 if(!this.collapsed){
45632 b = this.el.getBox(false, true);
45634 b = this.collapsedEl.getBox(false, true);
45639 getMargins : function(){
45640 return this.collapsed ? this.cmargins : this.margins;
45643 highlight : function(){
45644 this.el.addClass("x-layout-panel-dragover");
45647 unhighlight : function(){
45648 this.el.removeClass("x-layout-panel-dragover");
45651 updateBox : function(box){
45653 if(!this.collapsed){
45654 this.el.dom.style.left = box.x + "px";
45655 this.el.dom.style.top = box.y + "px";
45656 this.updateBody(box.width, box.height);
45658 this.collapsedEl.dom.style.left = box.x + "px";
45659 this.collapsedEl.dom.style.top = box.y + "px";
45660 this.collapsedEl.setSize(box.width, box.height);
45663 this.tabs.autoSizeTabs();
45667 updateBody : function(w, h){
45669 this.el.setWidth(w);
45670 w -= this.el.getBorderWidth("rl");
45671 if(this.config.adjustments){
45672 w += this.config.adjustments[0];
45676 this.el.setHeight(h);
45677 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
45678 h -= this.el.getBorderWidth("tb");
45679 if(this.config.adjustments){
45680 h += this.config.adjustments[1];
45682 this.bodyEl.setHeight(h);
45684 h = this.tabs.syncHeight(h);
45687 if(this.panelSize){
45688 w = w !== null ? w : this.panelSize.width;
45689 h = h !== null ? h : this.panelSize.height;
45691 if(this.activePanel){
45692 var el = this.activePanel.getEl();
45693 w = w !== null ? w : el.getWidth();
45694 h = h !== null ? h : el.getHeight();
45695 this.panelSize = {width: w, height: h};
45696 this.activePanel.setSize(w, h);
45698 if(Roo.isIE && this.tabs){
45699 this.tabs.el.repaint();
45704 * Returns the container element for this region.
45705 * @return {Roo.Element}
45707 getEl : function(){
45712 * Hides this region.
45715 if(!this.collapsed){
45716 this.el.dom.style.left = "-2000px";
45719 this.collapsedEl.dom.style.left = "-2000px";
45720 this.collapsedEl.hide();
45722 this.visible = false;
45723 this.fireEvent("visibilitychange", this, false);
45727 * Shows this region if it was previously hidden.
45730 if(!this.collapsed){
45733 this.collapsedEl.show();
45735 this.visible = true;
45736 this.fireEvent("visibilitychange", this, true);
45739 closeClicked : function(){
45740 if(this.activePanel){
45741 this.remove(this.activePanel);
45745 collapseClick : function(e){
45747 e.stopPropagation();
45750 e.stopPropagation();
45756 * Collapses this region.
45757 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
45759 collapse : function(skipAnim){
45760 if(this.collapsed) return;
45761 this.collapsed = true;
45763 this.split.el.hide();
45765 if(this.config.animate && skipAnim !== true){
45766 this.fireEvent("invalidated", this);
45767 this.animateCollapse();
45769 this.el.setLocation(-20000,-20000);
45771 this.collapsedEl.show();
45772 this.fireEvent("collapsed", this);
45773 this.fireEvent("invalidated", this);
45777 animateCollapse : function(){
45782 * Expands this region if it was previously collapsed.
45783 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
45784 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
45786 expand : function(e, skipAnim){
45787 if(e) e.stopPropagation();
45788 if(!this.collapsed || this.el.hasActiveFx()) return;
45790 this.afterSlideIn();
45793 this.collapsed = false;
45794 if(this.config.animate && skipAnim !== true){
45795 this.animateExpand();
45799 this.split.el.show();
45801 this.collapsedEl.setLocation(-2000,-2000);
45802 this.collapsedEl.hide();
45803 this.fireEvent("invalidated", this);
45804 this.fireEvent("expanded", this);
45808 animateExpand : function(){
45812 initTabs : function()
45814 this.bodyEl.setStyle("overflow", "hidden");
45815 var ts = new Roo.TabPanel(
45818 tabPosition: this.bottomTabs ? 'bottom' : 'top',
45819 disableTooltips: this.config.disableTabTips,
45820 toolbar : this.config.toolbar
45823 if(this.config.hideTabs){
45824 ts.stripWrap.setDisplayed(false);
45827 ts.resizeTabs = this.config.resizeTabs === true;
45828 ts.minTabWidth = this.config.minTabWidth || 40;
45829 ts.maxTabWidth = this.config.maxTabWidth || 250;
45830 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
45831 ts.monitorResize = false;
45832 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
45833 ts.bodyEl.addClass('x-layout-tabs-body');
45834 this.panels.each(this.initPanelAsTab, this);
45837 initPanelAsTab : function(panel){
45838 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
45839 this.config.closeOnTab && panel.isClosable());
45840 if(panel.tabTip !== undefined){
45841 ti.setTooltip(panel.tabTip);
45843 ti.on("activate", function(){
45844 this.setActivePanel(panel);
45846 if(this.config.closeOnTab){
45847 ti.on("beforeclose", function(t, e){
45849 this.remove(panel);
45855 updatePanelTitle : function(panel, title){
45856 if(this.activePanel == panel){
45857 this.updateTitle(title);
45860 var ti = this.tabs.getTab(panel.getEl().id);
45862 if(panel.tabTip !== undefined){
45863 ti.setTooltip(panel.tabTip);
45868 updateTitle : function(title){
45869 if(this.titleTextEl && !this.config.title){
45870 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
45874 setActivePanel : function(panel){
45875 panel = this.getPanel(panel);
45876 if(this.activePanel && this.activePanel != panel){
45877 this.activePanel.setActiveState(false);
45879 this.activePanel = panel;
45880 panel.setActiveState(true);
45881 if(this.panelSize){
45882 panel.setSize(this.panelSize.width, this.panelSize.height);
45885 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
45887 this.updateTitle(panel.getTitle());
45889 this.fireEvent("invalidated", this);
45891 this.fireEvent("panelactivated", this, panel);
45895 * Shows the specified panel.
45896 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
45897 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
45899 showPanel : function(panel){
45900 if(panel = this.getPanel(panel)){
45902 var tab = this.tabs.getTab(panel.getEl().id);
45903 if(tab.isHidden()){
45904 this.tabs.unhideTab(tab.id);
45908 this.setActivePanel(panel);
45915 * Get the active panel for this region.
45916 * @return {Roo.ContentPanel} The active panel or null
45918 getActivePanel : function(){
45919 return this.activePanel;
45922 validateVisibility : function(){
45923 if(this.panels.getCount() < 1){
45924 this.updateTitle(" ");
45925 this.closeBtn.hide();
45928 if(!this.isVisible()){
45935 * Adds the passed ContentPanel(s) to this region.
45936 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
45937 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
45939 add : function(panel){
45940 if(arguments.length > 1){
45941 for(var i = 0, len = arguments.length; i < len; i++) {
45942 this.add(arguments[i]);
45946 if(this.hasPanel(panel)){
45947 this.showPanel(panel);
45950 panel.setRegion(this);
45951 this.panels.add(panel);
45952 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
45953 this.bodyEl.dom.appendChild(panel.getEl().dom);
45954 if(panel.background !== true){
45955 this.setActivePanel(panel);
45957 this.fireEvent("paneladded", this, panel);
45963 this.initPanelAsTab(panel);
45965 if(panel.background !== true){
45966 this.tabs.activate(panel.getEl().id);
45968 this.fireEvent("paneladded", this, panel);
45973 * Hides the tab for the specified panel.
45974 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45976 hidePanel : function(panel){
45977 if(this.tabs && (panel = this.getPanel(panel))){
45978 this.tabs.hideTab(panel.getEl().id);
45983 * Unhides the tab for a previously hidden panel.
45984 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
45986 unhidePanel : function(panel){
45987 if(this.tabs && (panel = this.getPanel(panel))){
45988 this.tabs.unhideTab(panel.getEl().id);
45992 clearPanels : function(){
45993 while(this.panels.getCount() > 0){
45994 this.remove(this.panels.first());
45999 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
46000 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
46001 * @param {Boolean} preservePanel Overrides the config preservePanel option
46002 * @return {Roo.ContentPanel} The panel that was removed
46004 remove : function(panel, preservePanel){
46005 panel = this.getPanel(panel);
46010 this.fireEvent("beforeremove", this, panel, e);
46011 if(e.cancel === true){
46014 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
46015 var panelId = panel.getId();
46016 this.panels.removeKey(panelId);
46018 document.body.appendChild(panel.getEl().dom);
46021 this.tabs.removeTab(panel.getEl().id);
46022 }else if (!preservePanel){
46023 this.bodyEl.dom.removeChild(panel.getEl().dom);
46025 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
46026 var p = this.panels.first();
46027 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
46028 tempEl.appendChild(p.getEl().dom);
46029 this.bodyEl.update("");
46030 this.bodyEl.dom.appendChild(p.getEl().dom);
46032 this.updateTitle(p.getTitle());
46034 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
46035 this.setActivePanel(p);
46037 panel.setRegion(null);
46038 if(this.activePanel == panel){
46039 this.activePanel = null;
46041 if(this.config.autoDestroy !== false && preservePanel !== true){
46042 try{panel.destroy();}catch(e){}
46044 this.fireEvent("panelremoved", this, panel);
46049 * Returns the TabPanel component used by this region
46050 * @return {Roo.TabPanel}
46052 getTabs : function(){
46056 createTool : function(parentEl, className){
46057 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
46058 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
46059 btn.addClassOnOver("x-layout-tools-button-over");
46064 * Ext JS Library 1.1.1
46065 * Copyright(c) 2006-2007, Ext JS, LLC.
46067 * Originally Released Under LGPL - original licence link has changed is not relivant.
46070 * <script type="text/javascript">
46076 * @class Roo.SplitLayoutRegion
46077 * @extends Roo.LayoutRegion
46078 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
46080 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
46081 this.cursor = cursor;
46082 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
46085 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
46086 splitTip : "Drag to resize.",
46087 collapsibleSplitTip : "Drag to resize. Double click to hide.",
46088 useSplitTips : false,
46090 applyConfig : function(config){
46091 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
46094 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
46095 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
46096 /** The SplitBar for this region
46097 * @type Roo.SplitBar */
46098 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
46099 this.split.on("moved", this.onSplitMove, this);
46100 this.split.useShim = config.useShim === true;
46101 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
46102 if(this.useSplitTips){
46103 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
46105 if(config.collapsible){
46106 this.split.el.on("dblclick", this.collapse, this);
46109 if(typeof config.minSize != "undefined"){
46110 this.split.minSize = config.minSize;
46112 if(typeof config.maxSize != "undefined"){
46113 this.split.maxSize = config.maxSize;
46115 if(config.hideWhenEmpty || config.hidden || config.collapsed){
46116 this.hideSplitter();
46121 getHMaxSize : function(){
46122 var cmax = this.config.maxSize || 10000;
46123 var center = this.mgr.getRegion("center");
46124 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
46127 getVMaxSize : function(){
46128 var cmax = this.config.maxSize || 10000;
46129 var center = this.mgr.getRegion("center");
46130 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
46133 onSplitMove : function(split, newSize){
46134 this.fireEvent("resized", this, newSize);
46138 * Returns the {@link Roo.SplitBar} for this region.
46139 * @return {Roo.SplitBar}
46141 getSplitBar : function(){
46146 this.hideSplitter();
46147 Roo.SplitLayoutRegion.superclass.hide.call(this);
46150 hideSplitter : function(){
46152 this.split.el.setLocation(-2000,-2000);
46153 this.split.el.hide();
46159 this.split.el.show();
46161 Roo.SplitLayoutRegion.superclass.show.call(this);
46164 beforeSlide: function(){
46165 if(Roo.isGecko){// firefox overflow auto bug workaround
46166 this.bodyEl.clip();
46167 if(this.tabs) this.tabs.bodyEl.clip();
46168 if(this.activePanel){
46169 this.activePanel.getEl().clip();
46171 if(this.activePanel.beforeSlide){
46172 this.activePanel.beforeSlide();
46178 afterSlide : function(){
46179 if(Roo.isGecko){// firefox overflow auto bug workaround
46180 this.bodyEl.unclip();
46181 if(this.tabs) this.tabs.bodyEl.unclip();
46182 if(this.activePanel){
46183 this.activePanel.getEl().unclip();
46184 if(this.activePanel.afterSlide){
46185 this.activePanel.afterSlide();
46191 initAutoHide : function(){
46192 if(this.autoHide !== false){
46193 if(!this.autoHideHd){
46194 var st = new Roo.util.DelayedTask(this.slideIn, this);
46195 this.autoHideHd = {
46196 "mouseout": function(e){
46197 if(!e.within(this.el, true)){
46201 "mouseover" : function(e){
46207 this.el.on(this.autoHideHd);
46211 clearAutoHide : function(){
46212 if(this.autoHide !== false){
46213 this.el.un("mouseout", this.autoHideHd.mouseout);
46214 this.el.un("mouseover", this.autoHideHd.mouseover);
46218 clearMonitor : function(){
46219 Roo.get(document).un("click", this.slideInIf, this);
46222 // these names are backwards but not changed for compat
46223 slideOut : function(){
46224 if(this.isSlid || this.el.hasActiveFx()){
46227 this.isSlid = true;
46228 if(this.collapseBtn){
46229 this.collapseBtn.hide();
46231 this.closeBtnState = this.closeBtn.getStyle('display');
46232 this.closeBtn.hide();
46234 this.stickBtn.show();
46237 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
46238 this.beforeSlide();
46239 this.el.setStyle("z-index", 10001);
46240 this.el.slideIn(this.getSlideAnchor(), {
46241 callback: function(){
46243 this.initAutoHide();
46244 Roo.get(document).on("click", this.slideInIf, this);
46245 this.fireEvent("slideshow", this);
46252 afterSlideIn : function(){
46253 this.clearAutoHide();
46254 this.isSlid = false;
46255 this.clearMonitor();
46256 this.el.setStyle("z-index", "");
46257 if(this.collapseBtn){
46258 this.collapseBtn.show();
46260 this.closeBtn.setStyle('display', this.closeBtnState);
46262 this.stickBtn.hide();
46264 this.fireEvent("slidehide", this);
46267 slideIn : function(cb){
46268 if(!this.isSlid || this.el.hasActiveFx()){
46272 this.isSlid = false;
46273 this.beforeSlide();
46274 this.el.slideOut(this.getSlideAnchor(), {
46275 callback: function(){
46276 this.el.setLeftTop(-10000, -10000);
46278 this.afterSlideIn();
46286 slideInIf : function(e){
46287 if(!e.within(this.el)){
46292 animateCollapse : function(){
46293 this.beforeSlide();
46294 this.el.setStyle("z-index", 20000);
46295 var anchor = this.getSlideAnchor();
46296 this.el.slideOut(anchor, {
46297 callback : function(){
46298 this.el.setStyle("z-index", "");
46299 this.collapsedEl.slideIn(anchor, {duration:.3});
46301 this.el.setLocation(-10000,-10000);
46303 this.fireEvent("collapsed", this);
46310 animateExpand : function(){
46311 this.beforeSlide();
46312 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
46313 this.el.setStyle("z-index", 20000);
46314 this.collapsedEl.hide({
46317 this.el.slideIn(this.getSlideAnchor(), {
46318 callback : function(){
46319 this.el.setStyle("z-index", "");
46322 this.split.el.show();
46324 this.fireEvent("invalidated", this);
46325 this.fireEvent("expanded", this);
46353 getAnchor : function(){
46354 return this.anchors[this.position];
46357 getCollapseAnchor : function(){
46358 return this.canchors[this.position];
46361 getSlideAnchor : function(){
46362 return this.sanchors[this.position];
46365 getAlignAdj : function(){
46366 var cm = this.cmargins;
46367 switch(this.position){
46383 getExpandAdj : function(){
46384 var c = this.collapsedEl, cm = this.cmargins;
46385 switch(this.position){
46387 return [-(cm.right+c.getWidth()+cm.left), 0];
46390 return [cm.right+c.getWidth()+cm.left, 0];
46393 return [0, -(cm.top+cm.bottom+c.getHeight())];
46396 return [0, cm.top+cm.bottom+c.getHeight()];
46402 * Ext JS Library 1.1.1
46403 * Copyright(c) 2006-2007, Ext JS, LLC.
46405 * Originally Released Under LGPL - original licence link has changed is not relivant.
46408 * <script type="text/javascript">
46411 * These classes are private internal classes
46413 Roo.CenterLayoutRegion = function(mgr, config){
46414 Roo.LayoutRegion.call(this, mgr, config, "center");
46415 this.visible = true;
46416 this.minWidth = config.minWidth || 20;
46417 this.minHeight = config.minHeight || 20;
46420 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
46422 // center panel can't be hidden
46426 // center panel can't be hidden
46429 getMinWidth: function(){
46430 return this.minWidth;
46433 getMinHeight: function(){
46434 return this.minHeight;
46439 Roo.NorthLayoutRegion = function(mgr, config){
46440 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
46442 this.split.placement = Roo.SplitBar.TOP;
46443 this.split.orientation = Roo.SplitBar.VERTICAL;
46444 this.split.el.addClass("x-layout-split-v");
46446 var size = config.initialSize || config.height;
46447 if(typeof size != "undefined"){
46448 this.el.setHeight(size);
46451 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
46452 orientation: Roo.SplitBar.VERTICAL,
46453 getBox : function(){
46454 if(this.collapsed){
46455 return this.collapsedEl.getBox();
46457 var box = this.el.getBox();
46459 box.height += this.split.el.getHeight();
46464 updateBox : function(box){
46465 if(this.split && !this.collapsed){
46466 box.height -= this.split.el.getHeight();
46467 this.split.el.setLeft(box.x);
46468 this.split.el.setTop(box.y+box.height);
46469 this.split.el.setWidth(box.width);
46471 if(this.collapsed){
46472 this.updateBody(box.width, null);
46474 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46478 Roo.SouthLayoutRegion = function(mgr, config){
46479 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
46481 this.split.placement = Roo.SplitBar.BOTTOM;
46482 this.split.orientation = Roo.SplitBar.VERTICAL;
46483 this.split.el.addClass("x-layout-split-v");
46485 var size = config.initialSize || config.height;
46486 if(typeof size != "undefined"){
46487 this.el.setHeight(size);
46490 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
46491 orientation: Roo.SplitBar.VERTICAL,
46492 getBox : function(){
46493 if(this.collapsed){
46494 return this.collapsedEl.getBox();
46496 var box = this.el.getBox();
46498 var sh = this.split.el.getHeight();
46505 updateBox : function(box){
46506 if(this.split && !this.collapsed){
46507 var sh = this.split.el.getHeight();
46510 this.split.el.setLeft(box.x);
46511 this.split.el.setTop(box.y-sh);
46512 this.split.el.setWidth(box.width);
46514 if(this.collapsed){
46515 this.updateBody(box.width, null);
46517 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46521 Roo.EastLayoutRegion = function(mgr, config){
46522 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
46524 this.split.placement = Roo.SplitBar.RIGHT;
46525 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46526 this.split.el.addClass("x-layout-split-h");
46528 var size = config.initialSize || config.width;
46529 if(typeof size != "undefined"){
46530 this.el.setWidth(size);
46533 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
46534 orientation: Roo.SplitBar.HORIZONTAL,
46535 getBox : function(){
46536 if(this.collapsed){
46537 return this.collapsedEl.getBox();
46539 var box = this.el.getBox();
46541 var sw = this.split.el.getWidth();
46548 updateBox : function(box){
46549 if(this.split && !this.collapsed){
46550 var sw = this.split.el.getWidth();
46552 this.split.el.setLeft(box.x);
46553 this.split.el.setTop(box.y);
46554 this.split.el.setHeight(box.height);
46557 if(this.collapsed){
46558 this.updateBody(null, box.height);
46560 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46564 Roo.WestLayoutRegion = function(mgr, config){
46565 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
46567 this.split.placement = Roo.SplitBar.LEFT;
46568 this.split.orientation = Roo.SplitBar.HORIZONTAL;
46569 this.split.el.addClass("x-layout-split-h");
46571 var size = config.initialSize || config.width;
46572 if(typeof size != "undefined"){
46573 this.el.setWidth(size);
46576 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
46577 orientation: Roo.SplitBar.HORIZONTAL,
46578 getBox : function(){
46579 if(this.collapsed){
46580 return this.collapsedEl.getBox();
46582 var box = this.el.getBox();
46584 box.width += this.split.el.getWidth();
46589 updateBox : function(box){
46590 if(this.split && !this.collapsed){
46591 var sw = this.split.el.getWidth();
46593 this.split.el.setLeft(box.x+box.width);
46594 this.split.el.setTop(box.y);
46595 this.split.el.setHeight(box.height);
46597 if(this.collapsed){
46598 this.updateBody(null, box.height);
46600 Roo.LayoutRegion.prototype.updateBox.call(this, box);
46605 * Ext JS Library 1.1.1
46606 * Copyright(c) 2006-2007, Ext JS, LLC.
46608 * Originally Released Under LGPL - original licence link has changed is not relivant.
46611 * <script type="text/javascript">
46616 * Private internal class for reading and applying state
46618 Roo.LayoutStateManager = function(layout){
46619 // default empty state
46628 Roo.LayoutStateManager.prototype = {
46629 init : function(layout, provider){
46630 this.provider = provider;
46631 var state = provider.get(layout.id+"-layout-state");
46633 var wasUpdating = layout.isUpdating();
46635 layout.beginUpdate();
46637 for(var key in state){
46638 if(typeof state[key] != "function"){
46639 var rstate = state[key];
46640 var r = layout.getRegion(key);
46643 r.resizeTo(rstate.size);
46645 if(rstate.collapsed == true){
46648 r.expand(null, true);
46654 layout.endUpdate();
46656 this.state = state;
46658 this.layout = layout;
46659 layout.on("regionresized", this.onRegionResized, this);
46660 layout.on("regioncollapsed", this.onRegionCollapsed, this);
46661 layout.on("regionexpanded", this.onRegionExpanded, this);
46664 storeState : function(){
46665 this.provider.set(this.layout.id+"-layout-state", this.state);
46668 onRegionResized : function(region, newSize){
46669 this.state[region.getPosition()].size = newSize;
46673 onRegionCollapsed : function(region){
46674 this.state[region.getPosition()].collapsed = true;
46678 onRegionExpanded : function(region){
46679 this.state[region.getPosition()].collapsed = false;
46684 * Ext JS Library 1.1.1
46685 * Copyright(c) 2006-2007, Ext JS, LLC.
46687 * Originally Released Under LGPL - original licence link has changed is not relivant.
46690 * <script type="text/javascript">
46693 * @class Roo.ContentPanel
46694 * @extends Roo.util.Observable
46695 * A basic ContentPanel element.
46696 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
46697 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
46698 * @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
46699 * @cfg {Boolean} closable True if the panel can be closed/removed
46700 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
46701 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
46702 * @cfg {Toolbar} toolbar A toolbar for this panel
46703 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
46704 * @cfg {String} title The title for this panel
46705 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
46706 * @cfg {String} url Calls {@link #setUrl} with this value
46707 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
46708 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
46709 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
46710 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
46713 * Create a new ContentPanel.
46714 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
46715 * @param {String/Object} config A string to set only the title or a config object
46716 * @param {String} content (optional) Set the HTML content for this panel
46717 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
46719 Roo.ContentPanel = function(el, config, content){
46723 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
46727 if (config && config.parentLayout) {
46728 el = config.parentLayout.el.createChild();
46731 if(el.autoCreate){ // xtype is available if this is called from factory
46735 this.el = Roo.get(el);
46736 if(!this.el && config && config.autoCreate){
46737 if(typeof config.autoCreate == "object"){
46738 if(!config.autoCreate.id){
46739 config.autoCreate.id = config.id||el;
46741 this.el = Roo.DomHelper.append(document.body,
46742 config.autoCreate, true);
46744 this.el = Roo.DomHelper.append(document.body,
46745 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
46748 this.closable = false;
46749 this.loaded = false;
46750 this.active = false;
46751 if(typeof config == "string"){
46752 this.title = config;
46754 Roo.apply(this, config);
46757 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
46758 this.wrapEl = this.el.wrap();
46759 this.toolbar.container = this.el.insertSibling(false, 'before');
46760 this.toolbar = new Roo.Toolbar(this.toolbar);
46766 this.resizeEl = Roo.get(this.resizeEl, true);
46768 this.resizeEl = this.el;
46773 * Fires when this panel is activated.
46774 * @param {Roo.ContentPanel} this
46778 * @event deactivate
46779 * Fires when this panel is activated.
46780 * @param {Roo.ContentPanel} this
46782 "deactivate" : true,
46786 * Fires when this panel is resized if fitToFrame is true.
46787 * @param {Roo.ContentPanel} this
46788 * @param {Number} width The width after any component adjustments
46789 * @param {Number} height The height after any component adjustments
46795 * Fires when this tab is created
46796 * @param {Roo.ContentPanel} this
46803 if(this.autoScroll){
46804 this.resizeEl.setStyle("overflow", "auto");
46806 // fix randome scrolling
46807 this.el.on('scroll', function() {
46808 Roo.log('fix random scolling');
46809 this.scrollTo('top',0);
46812 content = content || this.content;
46814 this.setContent(content);
46816 if(config && config.url){
46817 this.setUrl(this.url, this.params, this.loadOnce);
46822 Roo.ContentPanel.superclass.constructor.call(this);
46824 this.fireEvent('render', this);
46827 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
46829 setRegion : function(region){
46830 this.region = region;
46832 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
46834 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
46839 * Returns the toolbar for this Panel if one was configured.
46840 * @return {Roo.Toolbar}
46842 getToolbar : function(){
46843 return this.toolbar;
46846 setActiveState : function(active){
46847 this.active = active;
46849 this.fireEvent("deactivate", this);
46851 this.fireEvent("activate", this);
46855 * Updates this panel's element
46856 * @param {String} content The new content
46857 * @param {Boolean} loadScripts (optional) true to look for and process scripts
46859 setContent : function(content, loadScripts){
46860 this.el.update(content, loadScripts);
46863 ignoreResize : function(w, h){
46864 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
46867 this.lastSize = {width: w, height: h};
46872 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
46873 * @return {Roo.UpdateManager} The UpdateManager
46875 getUpdateManager : function(){
46876 return this.el.getUpdateManager();
46879 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
46880 * @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:
46883 url: "your-url.php",
46884 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
46885 callback: yourFunction,
46886 scope: yourObject, //(optional scope)
46889 text: "Loading...",
46894 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
46895 * 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.
46896 * @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}
46897 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
46898 * @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.
46899 * @return {Roo.ContentPanel} this
46902 var um = this.el.getUpdateManager();
46903 um.update.apply(um, arguments);
46909 * 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.
46910 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
46911 * @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)
46912 * @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)
46913 * @return {Roo.UpdateManager} The UpdateManager
46915 setUrl : function(url, params, loadOnce){
46916 if(this.refreshDelegate){
46917 this.removeListener("activate", this.refreshDelegate);
46919 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
46920 this.on("activate", this.refreshDelegate);
46921 return this.el.getUpdateManager();
46924 _handleRefresh : function(url, params, loadOnce){
46925 if(!loadOnce || !this.loaded){
46926 var updater = this.el.getUpdateManager();
46927 updater.update(url, params, this._setLoaded.createDelegate(this));
46931 _setLoaded : function(){
46932 this.loaded = true;
46936 * Returns this panel's id
46939 getId : function(){
46944 * Returns this panel's element - used by regiosn to add.
46945 * @return {Roo.Element}
46947 getEl : function(){
46948 return this.wrapEl || this.el;
46951 adjustForComponents : function(width, height){
46952 if(this.resizeEl != this.el){
46953 width -= this.el.getFrameWidth('lr');
46954 height -= this.el.getFrameWidth('tb');
46957 var te = this.toolbar.getEl();
46958 height -= te.getHeight();
46959 te.setWidth(width);
46961 if(this.adjustments){
46962 width += this.adjustments[0];
46963 height += this.adjustments[1];
46965 return {"width": width, "height": height};
46968 setSize : function(width, height){
46969 if(this.fitToFrame && !this.ignoreResize(width, height)){
46970 if(this.fitContainer && this.resizeEl != this.el){
46971 this.el.setSize(width, height);
46973 var size = this.adjustForComponents(width, height);
46974 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
46975 this.fireEvent('resize', this, size.width, size.height);
46980 * Returns this panel's title
46983 getTitle : function(){
46988 * Set this panel's title
46989 * @param {String} title
46991 setTitle : function(title){
46992 this.title = title;
46994 this.region.updatePanelTitle(this, title);
46999 * Returns true is this panel was configured to be closable
47000 * @return {Boolean}
47002 isClosable : function(){
47003 return this.closable;
47006 beforeSlide : function(){
47008 this.resizeEl.clip();
47011 afterSlide : function(){
47013 this.resizeEl.unclip();
47017 * Force a content refresh from the URL specified in the {@link #setUrl} method.
47018 * Will fail silently if the {@link #setUrl} method has not been called.
47019 * This does not activate the panel, just updates its content.
47021 refresh : function(){
47022 if(this.refreshDelegate){
47023 this.loaded = false;
47024 this.refreshDelegate();
47029 * Destroys this panel
47031 destroy : function(){
47032 this.el.removeAllListeners();
47033 var tempEl = document.createElement("span");
47034 tempEl.appendChild(this.el.dom);
47035 tempEl.innerHTML = "";
47041 * form - if the content panel contains a form - this is a reference to it.
47042 * @type {Roo.form.Form}
47046 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
47047 * This contains a reference to it.
47053 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
47063 * @param {Object} cfg Xtype definition of item to add.
47066 addxtype : function(cfg) {
47068 if (cfg.xtype.match(/^Form$/)) {
47069 var el = this.el.createChild();
47071 this.form = new Roo.form.Form(cfg);
47074 if ( this.form.allItems.length) this.form.render(el.dom);
47077 // should only have one of theses..
47078 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
47080 cfg.el = this.el.appendChild(document.createElement("div"));
47083 var ret = new Roo.factory(cfg);
47084 ret.render && ret.render(false, ''); // render blank..
47093 * @class Roo.GridPanel
47094 * @extends Roo.ContentPanel
47096 * Create a new GridPanel.
47097 * @param {Roo.grid.Grid} grid The grid for this panel
47098 * @param {String/Object} config A string to set only the panel's title, or a config object
47100 Roo.GridPanel = function(grid, config){
47103 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
47104 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
47106 this.wrapper.dom.appendChild(grid.getGridEl().dom);
47108 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
47111 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
47113 // xtype created footer. - not sure if will work as we normally have to render first..
47114 if (this.footer && !this.footer.el && this.footer.xtype) {
47116 this.footer.container = this.grid.getView().getFooterPanel(true);
47117 this.footer.dataSource = this.grid.dataSource;
47118 this.footer = Roo.factory(this.footer, Roo);
47122 grid.monitorWindowResize = false; // turn off autosizing
47123 grid.autoHeight = false;
47124 grid.autoWidth = false;
47126 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
47129 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
47130 getId : function(){
47131 return this.grid.id;
47135 * Returns the grid for this panel
47136 * @return {Roo.grid.Grid}
47138 getGrid : function(){
47142 setSize : function(width, height){
47143 if(!this.ignoreResize(width, height)){
47144 var grid = this.grid;
47145 var size = this.adjustForComponents(width, height);
47146 grid.getGridEl().setSize(size.width, size.height);
47151 beforeSlide : function(){
47152 this.grid.getView().scroller.clip();
47155 afterSlide : function(){
47156 this.grid.getView().scroller.unclip();
47159 destroy : function(){
47160 this.grid.destroy();
47162 Roo.GridPanel.superclass.destroy.call(this);
47168 * @class Roo.NestedLayoutPanel
47169 * @extends Roo.ContentPanel
47171 * Create a new NestedLayoutPanel.
47174 * @param {Roo.BorderLayout} layout The layout for this panel
47175 * @param {String/Object} config A string to set only the title or a config object
47177 Roo.NestedLayoutPanel = function(layout, config)
47179 // construct with only one argument..
47180 /* FIXME - implement nicer consturctors
47181 if (layout.layout) {
47183 layout = config.layout;
47184 delete config.layout;
47186 if (layout.xtype && !layout.getEl) {
47187 // then layout needs constructing..
47188 layout = Roo.factory(layout, Roo);
47193 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
47195 layout.monitorWindowResize = false; // turn off autosizing
47196 this.layout = layout;
47197 this.layout.getEl().addClass("x-layout-nested-layout");
47204 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
47206 setSize : function(width, height){
47207 if(!this.ignoreResize(width, height)){
47208 var size = this.adjustForComponents(width, height);
47209 var el = this.layout.getEl();
47210 el.setSize(size.width, size.height);
47211 var touch = el.dom.offsetWidth;
47212 this.layout.layout();
47213 // ie requires a double layout on the first pass
47214 if(Roo.isIE && !this.initialized){
47215 this.initialized = true;
47216 this.layout.layout();
47221 // activate all subpanels if not currently active..
47223 setActiveState : function(active){
47224 this.active = active;
47226 this.fireEvent("deactivate", this);
47230 this.fireEvent("activate", this);
47231 // not sure if this should happen before or after..
47232 if (!this.layout) {
47233 return; // should not happen..
47236 for (var r in this.layout.regions) {
47237 reg = this.layout.getRegion(r);
47238 if (reg.getActivePanel()) {
47239 //reg.showPanel(reg.getActivePanel()); // force it to activate..
47240 reg.setActivePanel(reg.getActivePanel());
47243 if (!reg.panels.length) {
47246 reg.showPanel(reg.getPanel(0));
47255 * Returns the nested BorderLayout for this panel
47256 * @return {Roo.BorderLayout}
47258 getLayout : function(){
47259 return this.layout;
47263 * Adds a xtype elements to the layout of the nested panel
47267 xtype : 'ContentPanel',
47274 xtype : 'NestedLayoutPanel',
47280 items : [ ... list of content panels or nested layout panels.. ]
47284 * @param {Object} cfg Xtype definition of item to add.
47286 addxtype : function(cfg) {
47287 return this.layout.addxtype(cfg);
47292 Roo.ScrollPanel = function(el, config, content){
47293 config = config || {};
47294 config.fitToFrame = true;
47295 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
47297 this.el.dom.style.overflow = "hidden";
47298 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
47299 this.el.removeClass("x-layout-inactive-content");
47300 this.el.on("mousewheel", this.onWheel, this);
47302 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
47303 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
47304 up.unselectable(); down.unselectable();
47305 up.on("click", this.scrollUp, this);
47306 down.on("click", this.scrollDown, this);
47307 up.addClassOnOver("x-scroller-btn-over");
47308 down.addClassOnOver("x-scroller-btn-over");
47309 up.addClassOnClick("x-scroller-btn-click");
47310 down.addClassOnClick("x-scroller-btn-click");
47311 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
47313 this.resizeEl = this.el;
47314 this.el = wrap; this.up = up; this.down = down;
47317 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
47319 wheelIncrement : 5,
47320 scrollUp : function(){
47321 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
47324 scrollDown : function(){
47325 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
47328 afterScroll : function(){
47329 var el = this.resizeEl;
47330 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
47331 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47332 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
47335 setSize : function(){
47336 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
47337 this.afterScroll();
47340 onWheel : function(e){
47341 var d = e.getWheelDelta();
47342 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
47343 this.afterScroll();
47347 setContent : function(content, loadScripts){
47348 this.resizeEl.update(content, loadScripts);
47362 * @class Roo.TreePanel
47363 * @extends Roo.ContentPanel
47365 * Create a new TreePanel. - defaults to fit/scoll contents.
47366 * @param {String/Object} config A string to set only the panel's title, or a config object
47367 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
47369 Roo.TreePanel = function(config){
47370 var el = config.el;
47371 var tree = config.tree;
47372 delete config.tree;
47373 delete config.el; // hopefull!
47375 // wrapper for IE7 strict & safari scroll issue
47377 var treeEl = el.createChild();
47378 config.resizeEl = treeEl;
47382 Roo.TreePanel.superclass.constructor.call(this, el, config);
47385 this.tree = new Roo.tree.TreePanel(treeEl , tree);
47386 //console.log(tree);
47387 this.on('activate', function()
47389 if (this.tree.rendered) {
47392 //console.log('render tree');
47393 this.tree.render();
47396 this.on('resize', function (cp, w, h) {
47397 this.tree.innerCt.setWidth(w);
47398 this.tree.innerCt.setHeight(h);
47399 this.tree.innerCt.setStyle('overflow-y', 'auto');
47406 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
47423 * Ext JS Library 1.1.1
47424 * Copyright(c) 2006-2007, Ext JS, LLC.
47426 * Originally Released Under LGPL - original licence link has changed is not relivant.
47429 * <script type="text/javascript">
47434 * @class Roo.ReaderLayout
47435 * @extends Roo.BorderLayout
47436 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
47437 * center region containing two nested regions (a top one for a list view and one for item preview below),
47438 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
47439 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
47440 * expedites the setup of the overall layout and regions for this common application style.
47443 var reader = new Roo.ReaderLayout();
47444 var CP = Roo.ContentPanel; // shortcut for adding
47446 reader.beginUpdate();
47447 reader.add("north", new CP("north", "North"));
47448 reader.add("west", new CP("west", {title: "West"}));
47449 reader.add("east", new CP("east", {title: "East"}));
47451 reader.regions.listView.add(new CP("listView", "List"));
47452 reader.regions.preview.add(new CP("preview", "Preview"));
47453 reader.endUpdate();
47456 * Create a new ReaderLayout
47457 * @param {Object} config Configuration options
47458 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
47459 * document.body if omitted)
47461 Roo.ReaderLayout = function(config, renderTo){
47462 var c = config || {size:{}};
47463 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
47464 north: c.north !== false ? Roo.apply({
47468 }, c.north) : false,
47469 west: c.west !== false ? Roo.apply({
47477 margins:{left:5,right:0,bottom:5,top:5},
47478 cmargins:{left:5,right:5,bottom:5,top:5}
47479 }, c.west) : false,
47480 east: c.east !== false ? Roo.apply({
47488 margins:{left:0,right:5,bottom:5,top:5},
47489 cmargins:{left:5,right:5,bottom:5,top:5}
47490 }, c.east) : false,
47491 center: Roo.apply({
47492 tabPosition: 'top',
47496 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
47500 this.el.addClass('x-reader');
47502 this.beginUpdate();
47504 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
47505 south: c.preview !== false ? Roo.apply({
47512 cmargins:{top:5,left:0, right:0, bottom:0}
47513 }, c.preview) : false,
47514 center: Roo.apply({
47520 this.add('center', new Roo.NestedLayoutPanel(inner,
47521 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
47525 this.regions.preview = inner.getRegion('south');
47526 this.regions.listView = inner.getRegion('center');
47529 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
47531 * Ext JS Library 1.1.1
47532 * Copyright(c) 2006-2007, Ext JS, LLC.
47534 * Originally Released Under LGPL - original licence link has changed is not relivant.
47537 * <script type="text/javascript">
47541 * @class Roo.grid.Grid
47542 * @extends Roo.util.Observable
47543 * This class represents the primary interface of a component based grid control.
47544 * <br><br>Usage:<pre><code>
47545 var grid = new Roo.grid.Grid("my-container-id", {
47548 selModel: mySelectionModel,
47549 autoSizeColumns: true,
47550 monitorWindowResize: false,
47551 trackMouseOver: true
47556 * <b>Common Problems:</b><br/>
47557 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
47558 * element will correct this<br/>
47559 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
47560 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
47561 * are unpredictable.<br/>
47562 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
47563 * grid to calculate dimensions/offsets.<br/>
47565 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
47566 * The container MUST have some type of size defined for the grid to fill. The container will be
47567 * automatically set to position relative if it isn't already.
47568 * @param {Object} config A config object that sets properties on this grid.
47570 Roo.grid.Grid = function(container, config){
47571 // initialize the container
47572 this.container = Roo.get(container);
47573 this.container.update("");
47574 this.container.setStyle("overflow", "hidden");
47575 this.container.addClass('x-grid-container');
47577 this.id = this.container.id;
47579 Roo.apply(this, config);
47580 // check and correct shorthanded configs
47582 this.dataSource = this.ds;
47586 this.colModel = this.cm;
47590 this.selModel = this.sm;
47594 if (this.selModel) {
47595 this.selModel = Roo.factory(this.selModel, Roo.grid);
47596 this.sm = this.selModel;
47597 this.sm.xmodule = this.xmodule || false;
47599 if (typeof(this.colModel.config) == 'undefined') {
47600 this.colModel = new Roo.grid.ColumnModel(this.colModel);
47601 this.cm = this.colModel;
47602 this.cm.xmodule = this.xmodule || false;
47604 if (this.dataSource) {
47605 this.dataSource= Roo.factory(this.dataSource, Roo.data);
47606 this.ds = this.dataSource;
47607 this.ds.xmodule = this.xmodule || false;
47614 this.container.setWidth(this.width);
47618 this.container.setHeight(this.height);
47625 * The raw click event for the entire grid.
47626 * @param {Roo.EventObject} e
47631 * The raw dblclick event for the entire grid.
47632 * @param {Roo.EventObject} e
47636 * @event contextmenu
47637 * The raw contextmenu event for the entire grid.
47638 * @param {Roo.EventObject} e
47640 "contextmenu" : true,
47643 * The raw mousedown event for the entire grid.
47644 * @param {Roo.EventObject} e
47646 "mousedown" : true,
47649 * The raw mouseup event for the entire grid.
47650 * @param {Roo.EventObject} e
47655 * The raw mouseover event for the entire grid.
47656 * @param {Roo.EventObject} e
47658 "mouseover" : true,
47661 * The raw mouseout event for the entire grid.
47662 * @param {Roo.EventObject} e
47667 * The raw keypress event for the entire grid.
47668 * @param {Roo.EventObject} e
47673 * The raw keydown event for the entire grid.
47674 * @param {Roo.EventObject} e
47682 * Fires when a cell is clicked
47683 * @param {Grid} this
47684 * @param {Number} rowIndex
47685 * @param {Number} columnIndex
47686 * @param {Roo.EventObject} e
47688 "cellclick" : true,
47690 * @event celldblclick
47691 * Fires when a cell is double clicked
47692 * @param {Grid} this
47693 * @param {Number} rowIndex
47694 * @param {Number} columnIndex
47695 * @param {Roo.EventObject} e
47697 "celldblclick" : true,
47700 * Fires when a row is clicked
47701 * @param {Grid} this
47702 * @param {Number} rowIndex
47703 * @param {Roo.EventObject} e
47707 * @event rowdblclick
47708 * Fires when a row is double clicked
47709 * @param {Grid} this
47710 * @param {Number} rowIndex
47711 * @param {Roo.EventObject} e
47713 "rowdblclick" : true,
47715 * @event headerclick
47716 * Fires when a header is clicked
47717 * @param {Grid} this
47718 * @param {Number} columnIndex
47719 * @param {Roo.EventObject} e
47721 "headerclick" : true,
47723 * @event headerdblclick
47724 * Fires when a header cell is double clicked
47725 * @param {Grid} this
47726 * @param {Number} columnIndex
47727 * @param {Roo.EventObject} e
47729 "headerdblclick" : true,
47731 * @event rowcontextmenu
47732 * Fires when a row is right clicked
47733 * @param {Grid} this
47734 * @param {Number} rowIndex
47735 * @param {Roo.EventObject} e
47737 "rowcontextmenu" : true,
47739 * @event cellcontextmenu
47740 * Fires when a cell is right clicked
47741 * @param {Grid} this
47742 * @param {Number} rowIndex
47743 * @param {Number} cellIndex
47744 * @param {Roo.EventObject} e
47746 "cellcontextmenu" : true,
47748 * @event headercontextmenu
47749 * Fires when a header is right clicked
47750 * @param {Grid} this
47751 * @param {Number} columnIndex
47752 * @param {Roo.EventObject} e
47754 "headercontextmenu" : true,
47756 * @event bodyscroll
47757 * Fires when the body element is scrolled
47758 * @param {Number} scrollLeft
47759 * @param {Number} scrollTop
47761 "bodyscroll" : true,
47763 * @event columnresize
47764 * Fires when the user resizes a column
47765 * @param {Number} columnIndex
47766 * @param {Number} newSize
47768 "columnresize" : true,
47770 * @event columnmove
47771 * Fires when the user moves a column
47772 * @param {Number} oldIndex
47773 * @param {Number} newIndex
47775 "columnmove" : true,
47778 * Fires when row(s) start being dragged
47779 * @param {Grid} this
47780 * @param {Roo.GridDD} dd The drag drop object
47781 * @param {event} e The raw browser event
47783 "startdrag" : true,
47786 * Fires when a drag operation is complete
47787 * @param {Grid} this
47788 * @param {Roo.GridDD} dd The drag drop object
47789 * @param {event} e The raw browser event
47794 * Fires when dragged row(s) are dropped on a valid DD target
47795 * @param {Grid} this
47796 * @param {Roo.GridDD} dd The drag drop object
47797 * @param {String} targetId The target drag drop object
47798 * @param {event} e The raw browser event
47803 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
47804 * @param {Grid} this
47805 * @param {Roo.GridDD} dd The drag drop object
47806 * @param {String} targetId The target drag drop object
47807 * @param {event} e The raw browser event
47812 * Fires when the dragged row(s) first cross another DD target while being dragged
47813 * @param {Grid} this
47814 * @param {Roo.GridDD} dd The drag drop object
47815 * @param {String} targetId The target drag drop object
47816 * @param {event} e The raw browser event
47818 "dragenter" : true,
47821 * Fires when the dragged row(s) leave another DD target while being dragged
47822 * @param {Grid} this
47823 * @param {Roo.GridDD} dd The drag drop object
47824 * @param {String} targetId The target drag drop object
47825 * @param {event} e The raw browser event
47830 * Fires when a row is rendered, so you can change add a style to it.
47831 * @param {GridView} gridview The grid view
47832 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
47838 * Fires when the grid is rendered
47839 * @param {Grid} grid
47844 Roo.grid.Grid.superclass.constructor.call(this);
47846 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
47849 * @cfg {String} ddGroup - drag drop group.
47853 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
47855 minColumnWidth : 25,
47858 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
47859 * <b>on initial render.</b> It is more efficient to explicitly size the columns
47860 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
47862 autoSizeColumns : false,
47865 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
47867 autoSizeHeaders : true,
47870 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
47872 monitorWindowResize : true,
47875 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
47876 * rows measured to get a columns size. Default is 0 (all rows).
47878 maxRowsToMeasure : 0,
47881 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
47883 trackMouseOver : true,
47886 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
47890 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
47892 enableDragDrop : false,
47895 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
47897 enableColumnMove : true,
47900 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
47902 enableColumnHide : true,
47905 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
47907 enableRowHeightSync : false,
47910 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
47915 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
47917 autoHeight : false,
47920 * @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.
47922 autoExpandColumn : false,
47925 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
47928 autoExpandMin : 50,
47931 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
47933 autoExpandMax : 1000,
47936 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
47941 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
47945 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
47955 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
47956 * of a fixed width. Default is false.
47959 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
47962 * Called once after all setup has been completed and the grid is ready to be rendered.
47963 * @return {Roo.grid.Grid} this
47965 render : function()
47967 var c = this.container;
47968 // try to detect autoHeight/width mode
47969 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
47970 this.autoHeight = true;
47972 var view = this.getView();
47975 c.on("click", this.onClick, this);
47976 c.on("dblclick", this.onDblClick, this);
47977 c.on("contextmenu", this.onContextMenu, this);
47978 c.on("keydown", this.onKeyDown, this);
47980 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
47982 this.getSelectionModel().init(this);
47987 this.loadMask = new Roo.LoadMask(this.container,
47988 Roo.apply({store:this.dataSource}, this.loadMask));
47992 if (this.toolbar && this.toolbar.xtype) {
47993 this.toolbar.container = this.getView().getHeaderPanel(true);
47994 this.toolbar = new Roo.Toolbar(this.toolbar);
47996 if (this.footer && this.footer.xtype) {
47997 this.footer.dataSource = this.getDataSource();
47998 this.footer.container = this.getView().getFooterPanel(true);
47999 this.footer = Roo.factory(this.footer, Roo);
48001 if (this.dropTarget && this.dropTarget.xtype) {
48002 delete this.dropTarget.xtype;
48003 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
48007 this.rendered = true;
48008 this.fireEvent('render', this);
48013 * Reconfigures the grid to use a different Store and Column Model.
48014 * The View will be bound to the new objects and refreshed.
48015 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
48016 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
48018 reconfigure : function(dataSource, colModel){
48020 this.loadMask.destroy();
48021 this.loadMask = new Roo.LoadMask(this.container,
48022 Roo.apply({store:dataSource}, this.loadMask));
48024 this.view.bind(dataSource, colModel);
48025 this.dataSource = dataSource;
48026 this.colModel = colModel;
48027 this.view.refresh(true);
48031 onKeyDown : function(e){
48032 this.fireEvent("keydown", e);
48036 * Destroy this grid.
48037 * @param {Boolean} removeEl True to remove the element
48039 destroy : function(removeEl, keepListeners){
48041 this.loadMask.destroy();
48043 var c = this.container;
48044 c.removeAllListeners();
48045 this.view.destroy();
48046 this.colModel.purgeListeners();
48047 if(!keepListeners){
48048 this.purgeListeners();
48051 if(removeEl === true){
48057 processEvent : function(name, e){
48058 this.fireEvent(name, e);
48059 var t = e.getTarget();
48061 var header = v.findHeaderIndex(t);
48062 if(header !== false){
48063 this.fireEvent("header" + name, this, header, e);
48065 var row = v.findRowIndex(t);
48066 var cell = v.findCellIndex(t);
48068 this.fireEvent("row" + name, this, row, e);
48069 if(cell !== false){
48070 this.fireEvent("cell" + name, this, row, cell, e);
48077 onClick : function(e){
48078 this.processEvent("click", e);
48082 onContextMenu : function(e, t){
48083 this.processEvent("contextmenu", e);
48087 onDblClick : function(e){
48088 this.processEvent("dblclick", e);
48092 walkCells : function(row, col, step, fn, scope){
48093 var cm = this.colModel, clen = cm.getColumnCount();
48094 var ds = this.dataSource, rlen = ds.getCount(), first = true;
48106 if(fn.call(scope || this, row, col, cm) === true){
48124 if(fn.call(scope || this, row, col, cm) === true){
48136 getSelections : function(){
48137 return this.selModel.getSelections();
48141 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
48142 * but if manual update is required this method will initiate it.
48144 autoSize : function(){
48146 this.view.layout();
48147 if(this.view.adjustForScroll){
48148 this.view.adjustForScroll();
48154 * Returns the grid's underlying element.
48155 * @return {Element} The element
48157 getGridEl : function(){
48158 return this.container;
48161 // private for compatibility, overridden by editor grid
48162 stopEditing : function(){},
48165 * Returns the grid's SelectionModel.
48166 * @return {SelectionModel}
48168 getSelectionModel : function(){
48169 if(!this.selModel){
48170 this.selModel = new Roo.grid.RowSelectionModel();
48172 return this.selModel;
48176 * Returns the grid's DataSource.
48177 * @return {DataSource}
48179 getDataSource : function(){
48180 return this.dataSource;
48184 * Returns the grid's ColumnModel.
48185 * @return {ColumnModel}
48187 getColumnModel : function(){
48188 return this.colModel;
48192 * Returns the grid's GridView object.
48193 * @return {GridView}
48195 getView : function(){
48197 this.view = new Roo.grid.GridView(this.viewConfig);
48202 * Called to get grid's drag proxy text, by default returns this.ddText.
48205 getDragDropText : function(){
48206 var count = this.selModel.getCount();
48207 return String.format(this.ddText, count, count == 1 ? '' : 's');
48211 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
48212 * %0 is replaced with the number of selected rows.
48215 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
48217 * Ext JS Library 1.1.1
48218 * Copyright(c) 2006-2007, Ext JS, LLC.
48220 * Originally Released Under LGPL - original licence link has changed is not relivant.
48223 * <script type="text/javascript">
48226 Roo.grid.AbstractGridView = function(){
48230 "beforerowremoved" : true,
48231 "beforerowsinserted" : true,
48232 "beforerefresh" : true,
48233 "rowremoved" : true,
48234 "rowsinserted" : true,
48235 "rowupdated" : true,
48238 Roo.grid.AbstractGridView.superclass.constructor.call(this);
48241 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
48242 rowClass : "x-grid-row",
48243 cellClass : "x-grid-cell",
48244 tdClass : "x-grid-td",
48245 hdClass : "x-grid-hd",
48246 splitClass : "x-grid-hd-split",
48248 init: function(grid){
48250 var cid = this.grid.getGridEl().id;
48251 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
48252 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
48253 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
48254 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
48257 getColumnRenderers : function(){
48258 var renderers = [];
48259 var cm = this.grid.colModel;
48260 var colCount = cm.getColumnCount();
48261 for(var i = 0; i < colCount; i++){
48262 renderers[i] = cm.getRenderer(i);
48267 getColumnIds : function(){
48269 var cm = this.grid.colModel;
48270 var colCount = cm.getColumnCount();
48271 for(var i = 0; i < colCount; i++){
48272 ids[i] = cm.getColumnId(i);
48277 getDataIndexes : function(){
48278 if(!this.indexMap){
48279 this.indexMap = this.buildIndexMap();
48281 return this.indexMap.colToData;
48284 getColumnIndexByDataIndex : function(dataIndex){
48285 if(!this.indexMap){
48286 this.indexMap = this.buildIndexMap();
48288 return this.indexMap.dataToCol[dataIndex];
48292 * Set a css style for a column dynamically.
48293 * @param {Number} colIndex The index of the column
48294 * @param {String} name The css property name
48295 * @param {String} value The css value
48297 setCSSStyle : function(colIndex, name, value){
48298 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
48299 Roo.util.CSS.updateRule(selector, name, value);
48302 generateRules : function(cm){
48303 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
48304 Roo.util.CSS.removeStyleSheet(rulesId);
48305 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
48306 var cid = cm.getColumnId(i);
48307 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
48308 this.tdSelector, cid, " {\n}\n",
48309 this.hdSelector, cid, " {\n}\n",
48310 this.splitSelector, cid, " {\n}\n");
48312 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
48316 * Ext JS Library 1.1.1
48317 * Copyright(c) 2006-2007, Ext JS, LLC.
48319 * Originally Released Under LGPL - original licence link has changed is not relivant.
48322 * <script type="text/javascript">
48326 // This is a support class used internally by the Grid components
48327 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
48329 this.view = grid.getView();
48330 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48331 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
48333 this.setHandleElId(Roo.id(hd));
48334 this.setOuterHandleElId(Roo.id(hd2));
48336 this.scroll = false;
48338 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
48340 getDragData : function(e){
48341 var t = Roo.lib.Event.getTarget(e);
48342 var h = this.view.findHeaderCell(t);
48344 return {ddel: h.firstChild, header:h};
48349 onInitDrag : function(e){
48350 this.view.headersDisabled = true;
48351 var clone = this.dragData.ddel.cloneNode(true);
48352 clone.id = Roo.id();
48353 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
48354 this.proxy.update(clone);
48358 afterValidDrop : function(){
48360 setTimeout(function(){
48361 v.headersDisabled = false;
48365 afterInvalidDrop : function(){
48367 setTimeout(function(){
48368 v.headersDisabled = false;
48374 * Ext JS Library 1.1.1
48375 * Copyright(c) 2006-2007, Ext JS, LLC.
48377 * Originally Released Under LGPL - original licence link has changed is not relivant.
48380 * <script type="text/javascript">
48383 // This is a support class used internally by the Grid components
48384 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
48386 this.view = grid.getView();
48387 // split the proxies so they don't interfere with mouse events
48388 this.proxyTop = Roo.DomHelper.append(document.body, {
48389 cls:"col-move-top", html:" "
48391 this.proxyBottom = Roo.DomHelper.append(document.body, {
48392 cls:"col-move-bottom", html:" "
48394 this.proxyTop.hide = this.proxyBottom.hide = function(){
48395 this.setLeftTop(-100,-100);
48396 this.setStyle("visibility", "hidden");
48398 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
48399 // temporarily disabled
48400 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
48401 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
48403 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
48404 proxyOffsets : [-4, -9],
48405 fly: Roo.Element.fly,
48407 getTargetFromEvent : function(e){
48408 var t = Roo.lib.Event.getTarget(e);
48409 var cindex = this.view.findCellIndex(t);
48410 if(cindex !== false){
48411 return this.view.getHeaderCell(cindex);
48416 nextVisible : function(h){
48417 var v = this.view, cm = this.grid.colModel;
48420 if(!cm.isHidden(v.getCellIndex(h))){
48428 prevVisible : function(h){
48429 var v = this.view, cm = this.grid.colModel;
48432 if(!cm.isHidden(v.getCellIndex(h))){
48440 positionIndicator : function(h, n, e){
48441 var x = Roo.lib.Event.getPageX(e);
48442 var r = Roo.lib.Dom.getRegion(n.firstChild);
48443 var px, pt, py = r.top + this.proxyOffsets[1];
48444 if((r.right - x) <= (r.right-r.left)/2){
48445 px = r.right+this.view.borderWidth;
48451 var oldIndex = this.view.getCellIndex(h);
48452 var newIndex = this.view.getCellIndex(n);
48454 if(this.grid.colModel.isFixed(newIndex)){
48458 var locked = this.grid.colModel.isLocked(newIndex);
48463 if(oldIndex < newIndex){
48466 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
48469 px += this.proxyOffsets[0];
48470 this.proxyTop.setLeftTop(px, py);
48471 this.proxyTop.show();
48472 if(!this.bottomOffset){
48473 this.bottomOffset = this.view.mainHd.getHeight();
48475 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
48476 this.proxyBottom.show();
48480 onNodeEnter : function(n, dd, e, data){
48481 if(data.header != n){
48482 this.positionIndicator(data.header, n, e);
48486 onNodeOver : function(n, dd, e, data){
48487 var result = false;
48488 if(data.header != n){
48489 result = this.positionIndicator(data.header, n, e);
48492 this.proxyTop.hide();
48493 this.proxyBottom.hide();
48495 return result ? this.dropAllowed : this.dropNotAllowed;
48498 onNodeOut : function(n, dd, e, data){
48499 this.proxyTop.hide();
48500 this.proxyBottom.hide();
48503 onNodeDrop : function(n, dd, e, data){
48504 var h = data.header;
48506 var cm = this.grid.colModel;
48507 var x = Roo.lib.Event.getPageX(e);
48508 var r = Roo.lib.Dom.getRegion(n.firstChild);
48509 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
48510 var oldIndex = this.view.getCellIndex(h);
48511 var newIndex = this.view.getCellIndex(n);
48512 var locked = cm.isLocked(newIndex);
48516 if(oldIndex < newIndex){
48519 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
48522 cm.setLocked(oldIndex, locked, true);
48523 cm.moveColumn(oldIndex, newIndex);
48524 this.grid.fireEvent("columnmove", oldIndex, newIndex);
48532 * Ext JS Library 1.1.1
48533 * Copyright(c) 2006-2007, Ext JS, LLC.
48535 * Originally Released Under LGPL - original licence link has changed is not relivant.
48538 * <script type="text/javascript">
48542 * @class Roo.grid.GridView
48543 * @extends Roo.util.Observable
48546 * @param {Object} config
48548 Roo.grid.GridView = function(config){
48549 Roo.grid.GridView.superclass.constructor.call(this);
48552 Roo.apply(this, config);
48555 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
48558 rowClass : "x-grid-row",
48560 cellClass : "x-grid-col",
48562 tdClass : "x-grid-td",
48564 hdClass : "x-grid-hd",
48566 splitClass : "x-grid-split",
48568 sortClasses : ["sort-asc", "sort-desc"],
48570 enableMoveAnim : false,
48574 dh : Roo.DomHelper,
48576 fly : Roo.Element.fly,
48578 css : Roo.util.CSS,
48584 scrollIncrement : 22,
48586 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
48588 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
48590 bind : function(ds, cm){
48592 this.ds.un("load", this.onLoad, this);
48593 this.ds.un("datachanged", this.onDataChange, this);
48594 this.ds.un("add", this.onAdd, this);
48595 this.ds.un("remove", this.onRemove, this);
48596 this.ds.un("update", this.onUpdate, this);
48597 this.ds.un("clear", this.onClear, this);
48600 ds.on("load", this.onLoad, this);
48601 ds.on("datachanged", this.onDataChange, this);
48602 ds.on("add", this.onAdd, this);
48603 ds.on("remove", this.onRemove, this);
48604 ds.on("update", this.onUpdate, this);
48605 ds.on("clear", this.onClear, this);
48610 this.cm.un("widthchange", this.onColWidthChange, this);
48611 this.cm.un("headerchange", this.onHeaderChange, this);
48612 this.cm.un("hiddenchange", this.onHiddenChange, this);
48613 this.cm.un("columnmoved", this.onColumnMove, this);
48614 this.cm.un("columnlockchange", this.onColumnLock, this);
48617 this.generateRules(cm);
48618 cm.on("widthchange", this.onColWidthChange, this);
48619 cm.on("headerchange", this.onHeaderChange, this);
48620 cm.on("hiddenchange", this.onHiddenChange, this);
48621 cm.on("columnmoved", this.onColumnMove, this);
48622 cm.on("columnlockchange", this.onColumnLock, this);
48627 init: function(grid){
48628 Roo.grid.GridView.superclass.init.call(this, grid);
48630 this.bind(grid.dataSource, grid.colModel);
48632 grid.on("headerclick", this.handleHeaderClick, this);
48634 if(grid.trackMouseOver){
48635 grid.on("mouseover", this.onRowOver, this);
48636 grid.on("mouseout", this.onRowOut, this);
48638 grid.cancelTextSelection = function(){};
48639 this.gridId = grid.id;
48641 var tpls = this.templates || {};
48644 tpls.master = new Roo.Template(
48645 '<div class="x-grid" hidefocus="true">',
48646 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
48647 '<div class="x-grid-topbar"></div>',
48648 '<div class="x-grid-scroller"><div></div></div>',
48649 '<div class="x-grid-locked">',
48650 '<div class="x-grid-header">{lockedHeader}</div>',
48651 '<div class="x-grid-body">{lockedBody}</div>',
48653 '<div class="x-grid-viewport">',
48654 '<div class="x-grid-header">{header}</div>',
48655 '<div class="x-grid-body">{body}</div>',
48657 '<div class="x-grid-bottombar"></div>',
48659 '<div class="x-grid-resize-proxy"> </div>',
48662 tpls.master.disableformats = true;
48666 tpls.header = new Roo.Template(
48667 '<table border="0" cellspacing="0" cellpadding="0">',
48668 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
48671 tpls.header.disableformats = true;
48673 tpls.header.compile();
48676 tpls.hcell = new Roo.Template(
48677 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
48678 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
48681 tpls.hcell.disableFormats = true;
48683 tpls.hcell.compile();
48686 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
48687 tpls.hsplit.disableFormats = true;
48689 tpls.hsplit.compile();
48692 tpls.body = new Roo.Template(
48693 '<table border="0" cellspacing="0" cellpadding="0">',
48694 "<tbody>{rows}</tbody>",
48697 tpls.body.disableFormats = true;
48699 tpls.body.compile();
48702 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
48703 tpls.row.disableFormats = true;
48705 tpls.row.compile();
48708 tpls.cell = new Roo.Template(
48709 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
48710 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
48713 tpls.cell.disableFormats = true;
48715 tpls.cell.compile();
48717 this.templates = tpls;
48720 // remap these for backwards compat
48721 onColWidthChange : function(){
48722 this.updateColumns.apply(this, arguments);
48724 onHeaderChange : function(){
48725 this.updateHeaders.apply(this, arguments);
48727 onHiddenChange : function(){
48728 this.handleHiddenChange.apply(this, arguments);
48730 onColumnMove : function(){
48731 this.handleColumnMove.apply(this, arguments);
48733 onColumnLock : function(){
48734 this.handleLockChange.apply(this, arguments);
48737 onDataChange : function(){
48739 this.updateHeaderSortState();
48742 onClear : function(){
48746 onUpdate : function(ds, record){
48747 this.refreshRow(record);
48750 refreshRow : function(record){
48751 var ds = this.ds, index;
48752 if(typeof record == 'number'){
48754 record = ds.getAt(index);
48756 index = ds.indexOf(record);
48758 this.insertRows(ds, index, index, true);
48759 this.onRemove(ds, record, index+1, true);
48760 this.syncRowHeights(index, index);
48762 this.fireEvent("rowupdated", this, index, record);
48765 onAdd : function(ds, records, index){
48766 this.insertRows(ds, index, index + (records.length-1));
48769 onRemove : function(ds, record, index, isUpdate){
48770 if(isUpdate !== true){
48771 this.fireEvent("beforerowremoved", this, index, record);
48773 var bt = this.getBodyTable(), lt = this.getLockedTable();
48774 if(bt.rows[index]){
48775 bt.firstChild.removeChild(bt.rows[index]);
48777 if(lt.rows[index]){
48778 lt.firstChild.removeChild(lt.rows[index]);
48780 if(isUpdate !== true){
48781 this.stripeRows(index);
48782 this.syncRowHeights(index, index);
48784 this.fireEvent("rowremoved", this, index, record);
48788 onLoad : function(){
48789 this.scrollToTop();
48793 * Scrolls the grid to the top
48795 scrollToTop : function(){
48797 this.scroller.dom.scrollTop = 0;
48803 * Gets a panel in the header of the grid that can be used for toolbars etc.
48804 * After modifying the contents of this panel a call to grid.autoSize() may be
48805 * required to register any changes in size.
48806 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
48807 * @return Roo.Element
48809 getHeaderPanel : function(doShow){
48811 this.headerPanel.show();
48813 return this.headerPanel;
48817 * Gets a panel in the footer of the grid that can be used for toolbars etc.
48818 * After modifying the contents of this panel a call to grid.autoSize() may be
48819 * required to register any changes in size.
48820 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
48821 * @return Roo.Element
48823 getFooterPanel : function(doShow){
48825 this.footerPanel.show();
48827 return this.footerPanel;
48830 initElements : function(){
48831 var E = Roo.Element;
48832 var el = this.grid.getGridEl().dom.firstChild;
48833 var cs = el.childNodes;
48835 this.el = new E(el);
48837 this.focusEl = new E(el.firstChild);
48838 this.focusEl.swallowEvent("click", true);
48840 this.headerPanel = new E(cs[1]);
48841 this.headerPanel.enableDisplayMode("block");
48843 this.scroller = new E(cs[2]);
48844 this.scrollSizer = new E(this.scroller.dom.firstChild);
48846 this.lockedWrap = new E(cs[3]);
48847 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
48848 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
48850 this.mainWrap = new E(cs[4]);
48851 this.mainHd = new E(this.mainWrap.dom.firstChild);
48852 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
48854 this.footerPanel = new E(cs[5]);
48855 this.footerPanel.enableDisplayMode("block");
48857 this.resizeProxy = new E(cs[6]);
48859 this.headerSelector = String.format(
48860 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
48861 this.lockedHd.id, this.mainHd.id
48864 this.splitterSelector = String.format(
48865 '#{0} div.x-grid-split, #{1} div.x-grid-split',
48866 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
48869 idToCssName : function(s)
48871 return s.replace(/[^a-z0-9]+/ig, '-');
48874 getHeaderCell : function(index){
48875 return Roo.DomQuery.select(this.headerSelector)[index];
48878 getHeaderCellMeasure : function(index){
48879 return this.getHeaderCell(index).firstChild;
48882 getHeaderCellText : function(index){
48883 return this.getHeaderCell(index).firstChild.firstChild;
48886 getLockedTable : function(){
48887 return this.lockedBody.dom.firstChild;
48890 getBodyTable : function(){
48891 return this.mainBody.dom.firstChild;
48894 getLockedRow : function(index){
48895 return this.getLockedTable().rows[index];
48898 getRow : function(index){
48899 return this.getBodyTable().rows[index];
48902 getRowComposite : function(index){
48904 this.rowEl = new Roo.CompositeElementLite();
48906 var els = [], lrow, mrow;
48907 if(lrow = this.getLockedRow(index)){
48910 if(mrow = this.getRow(index)){
48913 this.rowEl.elements = els;
48917 * Gets the 'td' of the cell
48919 * @param {Integer} rowIndex row to select
48920 * @param {Integer} colIndex column to select
48924 getCell : function(rowIndex, colIndex){
48925 var locked = this.cm.getLockedCount();
48927 if(colIndex < locked){
48928 source = this.lockedBody.dom.firstChild;
48930 source = this.mainBody.dom.firstChild;
48931 colIndex -= locked;
48933 return source.rows[rowIndex].childNodes[colIndex];
48936 getCellText : function(rowIndex, colIndex){
48937 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
48940 getCellBox : function(cell){
48941 var b = this.fly(cell).getBox();
48942 if(Roo.isOpera){ // opera fails to report the Y
48943 b.y = cell.offsetTop + this.mainBody.getY();
48948 getCellIndex : function(cell){
48949 var id = String(cell.className).match(this.cellRE);
48951 return parseInt(id[1], 10);
48956 findHeaderIndex : function(n){
48957 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48958 return r ? this.getCellIndex(r) : false;
48961 findHeaderCell : function(n){
48962 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
48963 return r ? r : false;
48966 findRowIndex : function(n){
48970 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
48971 return r ? r.rowIndex : false;
48974 findCellIndex : function(node){
48975 var stop = this.el.dom;
48976 while(node && node != stop){
48977 if(this.findRE.test(node.className)){
48978 return this.getCellIndex(node);
48980 node = node.parentNode;
48985 getColumnId : function(index){
48986 return this.cm.getColumnId(index);
48989 getSplitters : function()
48991 if(this.splitterSelector){
48992 return Roo.DomQuery.select(this.splitterSelector);
48998 getSplitter : function(index){
48999 return this.getSplitters()[index];
49002 onRowOver : function(e, t){
49004 if((row = this.findRowIndex(t)) !== false){
49005 this.getRowComposite(row).addClass("x-grid-row-over");
49009 onRowOut : function(e, t){
49011 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
49012 this.getRowComposite(row).removeClass("x-grid-row-over");
49016 renderHeaders : function(){
49018 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
49019 var cb = [], lb = [], sb = [], lsb = [], p = {};
49020 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49021 p.cellId = "x-grid-hd-0-" + i;
49022 p.splitId = "x-grid-csplit-0-" + i;
49023 p.id = cm.getColumnId(i);
49024 p.title = cm.getColumnTooltip(i) || "";
49025 p.value = cm.getColumnHeader(i) || "";
49026 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
49027 if(!cm.isLocked(i)){
49028 cb[cb.length] = ct.apply(p);
49029 sb[sb.length] = st.apply(p);
49031 lb[lb.length] = ct.apply(p);
49032 lsb[lsb.length] = st.apply(p);
49035 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
49036 ht.apply({cells: cb.join(""), splits:sb.join("")})];
49039 updateHeaders : function(){
49040 var html = this.renderHeaders();
49041 this.lockedHd.update(html[0]);
49042 this.mainHd.update(html[1]);
49046 * Focuses the specified row.
49047 * @param {Number} row The row index
49049 focusRow : function(row)
49051 //Roo.log('GridView.focusRow');
49052 var x = this.scroller.dom.scrollLeft;
49053 this.focusCell(row, 0, false);
49054 this.scroller.dom.scrollLeft = x;
49058 * Focuses the specified cell.
49059 * @param {Number} row The row index
49060 * @param {Number} col The column index
49061 * @param {Boolean} hscroll false to disable horizontal scrolling
49063 focusCell : function(row, col, hscroll)
49065 //Roo.log('GridView.focusCell');
49066 var el = this.ensureVisible(row, col, hscroll);
49067 this.focusEl.alignTo(el, "tl-tl");
49069 this.focusEl.focus();
49071 this.focusEl.focus.defer(1, this.focusEl);
49076 * Scrolls the specified cell into view
49077 * @param {Number} row The row index
49078 * @param {Number} col The column index
49079 * @param {Boolean} hscroll false to disable horizontal scrolling
49081 ensureVisible : function(row, col, hscroll)
49083 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
49084 //return null; //disable for testing.
49085 if(typeof row != "number"){
49086 row = row.rowIndex;
49088 if(row < 0 && row >= this.ds.getCount()){
49091 col = (col !== undefined ? col : 0);
49092 var cm = this.grid.colModel;
49093 while(cm.isHidden(col)){
49097 var el = this.getCell(row, col);
49101 var c = this.scroller.dom;
49103 var ctop = parseInt(el.offsetTop, 10);
49104 var cleft = parseInt(el.offsetLeft, 10);
49105 var cbot = ctop + el.offsetHeight;
49106 var cright = cleft + el.offsetWidth;
49108 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
49109 var stop = parseInt(c.scrollTop, 10);
49110 var sleft = parseInt(c.scrollLeft, 10);
49111 var sbot = stop + ch;
49112 var sright = sleft + c.clientWidth;
49114 Roo.log('GridView.ensureVisible:' +
49116 ' c.clientHeight:' + c.clientHeight +
49117 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
49125 c.scrollTop = ctop;
49126 //Roo.log("set scrolltop to ctop DISABLE?");
49127 }else if(cbot > sbot){
49128 //Roo.log("set scrolltop to cbot-ch");
49129 c.scrollTop = cbot-ch;
49132 if(hscroll !== false){
49134 c.scrollLeft = cleft;
49135 }else if(cright > sright){
49136 c.scrollLeft = cright-c.clientWidth;
49143 updateColumns : function(){
49144 this.grid.stopEditing();
49145 var cm = this.grid.colModel, colIds = this.getColumnIds();
49146 //var totalWidth = cm.getTotalWidth();
49148 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49149 //if(cm.isHidden(i)) continue;
49150 var w = cm.getColumnWidth(i);
49151 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
49152 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
49154 this.updateSplitters();
49157 generateRules : function(cm){
49158 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
49159 Roo.util.CSS.removeStyleSheet(rulesId);
49160 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49161 var cid = cm.getColumnId(i);
49163 if(cm.config[i].align){
49164 align = 'text-align:'+cm.config[i].align+';';
49167 if(cm.isHidden(i)){
49168 hidden = 'display:none;';
49170 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
49172 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
49173 this.hdSelector, cid, " {\n", align, width, "}\n",
49174 this.tdSelector, cid, " {\n",hidden,"\n}\n",
49175 this.splitSelector, cid, " {\n", hidden , "\n}\n");
49177 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
49180 updateSplitters : function(){
49181 var cm = this.cm, s = this.getSplitters();
49182 if(s){ // splitters not created yet
49183 var pos = 0, locked = true;
49184 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
49185 if(cm.isHidden(i)) continue;
49186 var w = cm.getColumnWidth(i); // make sure it's a number
49187 if(!cm.isLocked(i) && locked){
49192 s[i].style.left = (pos-this.splitOffset) + "px";
49197 handleHiddenChange : function(colModel, colIndex, hidden){
49199 this.hideColumn(colIndex);
49201 this.unhideColumn(colIndex);
49205 hideColumn : function(colIndex){
49206 var cid = this.getColumnId(colIndex);
49207 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
49208 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
49210 this.updateHeaders();
49212 this.updateSplitters();
49216 unhideColumn : function(colIndex){
49217 var cid = this.getColumnId(colIndex);
49218 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
49219 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
49222 this.updateHeaders();
49224 this.updateSplitters();
49228 insertRows : function(dm, firstRow, lastRow, isUpdate){
49229 if(firstRow == 0 && lastRow == dm.getCount()-1){
49233 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
49235 var s = this.getScrollState();
49236 var markup = this.renderRows(firstRow, lastRow);
49237 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
49238 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
49239 this.restoreScroll(s);
49241 this.fireEvent("rowsinserted", this, firstRow, lastRow);
49242 this.syncRowHeights(firstRow, lastRow);
49243 this.stripeRows(firstRow);
49249 bufferRows : function(markup, target, index){
49250 var before = null, trows = target.rows, tbody = target.tBodies[0];
49251 if(index < trows.length){
49252 before = trows[index];
49254 var b = document.createElement("div");
49255 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
49256 var rows = b.firstChild.rows;
49257 for(var i = 0, len = rows.length; i < len; i++){
49259 tbody.insertBefore(rows[0], before);
49261 tbody.appendChild(rows[0]);
49268 deleteRows : function(dm, firstRow, lastRow){
49269 if(dm.getRowCount()<1){
49270 this.fireEvent("beforerefresh", this);
49271 this.mainBody.update("");
49272 this.lockedBody.update("");
49273 this.fireEvent("refresh", this);
49275 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
49276 var bt = this.getBodyTable();
49277 var tbody = bt.firstChild;
49278 var rows = bt.rows;
49279 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
49280 tbody.removeChild(rows[firstRow]);
49282 this.stripeRows(firstRow);
49283 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
49287 updateRows : function(dataSource, firstRow, lastRow){
49288 var s = this.getScrollState();
49290 this.restoreScroll(s);
49293 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
49297 this.updateHeaderSortState();
49300 getScrollState : function(){
49302 var sb = this.scroller.dom;
49303 return {left: sb.scrollLeft, top: sb.scrollTop};
49306 stripeRows : function(startRow){
49307 if(!this.grid.stripeRows || this.ds.getCount() < 1){
49310 startRow = startRow || 0;
49311 var rows = this.getBodyTable().rows;
49312 var lrows = this.getLockedTable().rows;
49313 var cls = ' x-grid-row-alt ';
49314 for(var i = startRow, len = rows.length; i < len; i++){
49315 var row = rows[i], lrow = lrows[i];
49316 var isAlt = ((i+1) % 2 == 0);
49317 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
49318 if(isAlt == hasAlt){
49322 row.className += " x-grid-row-alt";
49324 row.className = row.className.replace("x-grid-row-alt", "");
49327 lrow.className = row.className;
49332 restoreScroll : function(state){
49333 //Roo.log('GridView.restoreScroll');
49334 var sb = this.scroller.dom;
49335 sb.scrollLeft = state.left;
49336 sb.scrollTop = state.top;
49340 syncScroll : function(){
49341 //Roo.log('GridView.syncScroll');
49342 var sb = this.scroller.dom;
49343 var sh = this.mainHd.dom;
49344 var bs = this.mainBody.dom;
49345 var lv = this.lockedBody.dom;
49346 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
49347 lv.scrollTop = bs.scrollTop = sb.scrollTop;
49350 handleScroll : function(e){
49352 var sb = this.scroller.dom;
49353 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
49357 handleWheel : function(e){
49358 var d = e.getWheelDelta();
49359 this.scroller.dom.scrollTop -= d*22;
49360 // set this here to prevent jumpy scrolling on large tables
49361 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
49365 renderRows : function(startRow, endRow){
49366 // pull in all the crap needed to render rows
49367 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
49368 var colCount = cm.getColumnCount();
49370 if(ds.getCount() < 1){
49374 // build a map for all the columns
49376 for(var i = 0; i < colCount; i++){
49377 var name = cm.getDataIndex(i);
49379 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
49380 renderer : cm.getRenderer(i),
49381 id : cm.getColumnId(i),
49382 locked : cm.isLocked(i)
49386 startRow = startRow || 0;
49387 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
49389 // records to render
49390 var rs = ds.getRange(startRow, endRow);
49392 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
49395 // As much as I hate to duplicate code, this was branched because FireFox really hates
49396 // [].join("") on strings. The performance difference was substantial enough to
49397 // branch this function
49398 doRender : Roo.isGecko ?
49399 function(cs, rs, ds, startRow, colCount, stripe){
49400 var ts = this.templates, ct = ts.cell, rt = ts.row;
49402 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49404 var hasListener = this.grid.hasListener('rowclass');
49406 for(var j = 0, len = rs.length; j < len; j++){
49407 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
49408 for(var i = 0; i < colCount; i++){
49410 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49412 p.css = p.attr = "";
49413 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49414 if(p.value == undefined || p.value === "") p.value = " ";
49415 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49416 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49418 var markup = ct.apply(p);
49426 if(stripe && ((rowIndex+1) % 2 == 0)){
49427 alt.push("x-grid-row-alt")
49430 alt.push( " x-grid-dirty-row");
49433 if(this.getRowClass){
49434 alt.push(this.getRowClass(r, rowIndex));
49440 rowIndex : rowIndex,
49443 this.grid.fireEvent('rowclass', this, rowcfg);
49444 alt.push(rowcfg.rowClass);
49446 rp.alt = alt.join(" ");
49447 lbuf+= rt.apply(rp);
49449 buf+= rt.apply(rp);
49451 return [lbuf, buf];
49453 function(cs, rs, ds, startRow, colCount, stripe){
49454 var ts = this.templates, ct = ts.cell, rt = ts.row;
49456 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
49457 var hasListener = this.grid.hasListener('rowclass');
49460 for(var j = 0, len = rs.length; j < len; j++){
49461 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
49462 for(var i = 0; i < colCount; i++){
49464 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
49466 p.css = p.attr = "";
49467 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
49468 if(p.value == undefined || p.value === "") p.value = " ";
49469 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
49470 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
49473 var markup = ct.apply(p);
49475 cb[cb.length] = markup;
49477 lcb[lcb.length] = markup;
49481 if(stripe && ((rowIndex+1) % 2 == 0)){
49482 alt.push( "x-grid-row-alt");
49485 alt.push(" x-grid-dirty-row");
49488 if(this.getRowClass){
49489 alt.push( this.getRowClass(r, rowIndex));
49495 rowIndex : rowIndex,
49498 this.grid.fireEvent('rowclass', this, rowcfg);
49499 alt.push(rowcfg.rowClass);
49501 rp.alt = alt.join(" ");
49502 rp.cells = lcb.join("");
49503 lbuf[lbuf.length] = rt.apply(rp);
49504 rp.cells = cb.join("");
49505 buf[buf.length] = rt.apply(rp);
49507 return [lbuf.join(""), buf.join("")];
49510 renderBody : function(){
49511 var markup = this.renderRows();
49512 var bt = this.templates.body;
49513 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
49517 * Refreshes the grid
49518 * @param {Boolean} headersToo
49520 refresh : function(headersToo){
49521 this.fireEvent("beforerefresh", this);
49522 this.grid.stopEditing();
49523 var result = this.renderBody();
49524 this.lockedBody.update(result[0]);
49525 this.mainBody.update(result[1]);
49526 if(headersToo === true){
49527 this.updateHeaders();
49528 this.updateColumns();
49529 this.updateSplitters();
49530 this.updateHeaderSortState();
49532 this.syncRowHeights();
49534 this.fireEvent("refresh", this);
49537 handleColumnMove : function(cm, oldIndex, newIndex){
49538 this.indexMap = null;
49539 var s = this.getScrollState();
49540 this.refresh(true);
49541 this.restoreScroll(s);
49542 this.afterMove(newIndex);
49545 afterMove : function(colIndex){
49546 if(this.enableMoveAnim && Roo.enableFx){
49547 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
49549 // if multisort - fix sortOrder, and reload..
49550 if (this.grid.dataSource.multiSort) {
49551 // the we can call sort again..
49552 var dm = this.grid.dataSource;
49553 var cm = this.grid.colModel;
49555 for(var i = 0; i < cm.config.length; i++ ) {
49557 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
49558 continue; // dont' bother, it's not in sort list or being set.
49561 so.push(cm.config[i].dataIndex);
49564 dm.load(dm.lastOptions);
49571 updateCell : function(dm, rowIndex, dataIndex){
49572 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
49573 if(typeof colIndex == "undefined"){ // not present in grid
49576 var cm = this.grid.colModel;
49577 var cell = this.getCell(rowIndex, colIndex);
49578 var cellText = this.getCellText(rowIndex, colIndex);
49581 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
49582 id : cm.getColumnId(colIndex),
49583 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
49585 var renderer = cm.getRenderer(colIndex);
49586 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
49587 if(typeof val == "undefined" || val === "") val = " ";
49588 cellText.innerHTML = val;
49589 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
49590 this.syncRowHeights(rowIndex, rowIndex);
49593 calcColumnWidth : function(colIndex, maxRowsToMeasure){
49595 if(this.grid.autoSizeHeaders){
49596 var h = this.getHeaderCellMeasure(colIndex);
49597 maxWidth = Math.max(maxWidth, h.scrollWidth);
49600 if(this.cm.isLocked(colIndex)){
49601 tb = this.getLockedTable();
49604 tb = this.getBodyTable();
49605 index = colIndex - this.cm.getLockedCount();
49608 var rows = tb.rows;
49609 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
49610 for(var i = 0; i < stopIndex; i++){
49611 var cell = rows[i].childNodes[index].firstChild;
49612 maxWidth = Math.max(maxWidth, cell.scrollWidth);
49615 return maxWidth + /*margin for error in IE*/ 5;
49618 * Autofit a column to its content.
49619 * @param {Number} colIndex
49620 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
49622 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
49623 if(this.cm.isHidden(colIndex)){
49624 return; // can't calc a hidden column
49627 var cid = this.cm.getColumnId(colIndex);
49628 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
49629 if(this.grid.autoSizeHeaders){
49630 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
49633 var newWidth = this.calcColumnWidth(colIndex);
49634 this.cm.setColumnWidth(colIndex,
49635 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
49636 if(!suppressEvent){
49637 this.grid.fireEvent("columnresize", colIndex, newWidth);
49642 * Autofits all columns to their content and then expands to fit any extra space in the grid
49644 autoSizeColumns : function(){
49645 var cm = this.grid.colModel;
49646 var colCount = cm.getColumnCount();
49647 for(var i = 0; i < colCount; i++){
49648 this.autoSizeColumn(i, true, true);
49650 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
49653 this.updateColumns();
49659 * Autofits all columns to the grid's width proportionate with their current size
49660 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
49662 fitColumns : function(reserveScrollSpace){
49663 var cm = this.grid.colModel;
49664 var colCount = cm.getColumnCount();
49668 for (i = 0; i < colCount; i++){
49669 if(!cm.isHidden(i) && !cm.isFixed(i)){
49670 w = cm.getColumnWidth(i);
49676 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
49677 if(reserveScrollSpace){
49680 var frac = (avail - cm.getTotalWidth())/width;
49681 while (cols.length){
49684 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
49686 this.updateColumns();
49690 onRowSelect : function(rowIndex){
49691 var row = this.getRowComposite(rowIndex);
49692 row.addClass("x-grid-row-selected");
49695 onRowDeselect : function(rowIndex){
49696 var row = this.getRowComposite(rowIndex);
49697 row.removeClass("x-grid-row-selected");
49700 onCellSelect : function(row, col){
49701 var cell = this.getCell(row, col);
49703 Roo.fly(cell).addClass("x-grid-cell-selected");
49707 onCellDeselect : function(row, col){
49708 var cell = this.getCell(row, col);
49710 Roo.fly(cell).removeClass("x-grid-cell-selected");
49714 updateHeaderSortState : function(){
49716 // sort state can be single { field: xxx, direction : yyy}
49717 // or { xxx=>ASC , yyy : DESC ..... }
49720 if (!this.ds.multiSort) {
49721 var state = this.ds.getSortState();
49725 mstate[state.field] = state.direction;
49726 // FIXME... - this is not used here.. but might be elsewhere..
49727 this.sortState = state;
49730 mstate = this.ds.sortToggle;
49732 //remove existing sort classes..
49734 var sc = this.sortClasses;
49735 var hds = this.el.select(this.headerSelector).removeClass(sc);
49737 for(var f in mstate) {
49739 var sortColumn = this.cm.findColumnIndex(f);
49741 if(sortColumn != -1){
49742 var sortDir = mstate[f];
49743 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
49752 handleHeaderClick : function(g, index){
49753 if(this.headersDisabled){
49756 var dm = g.dataSource, cm = g.colModel;
49757 if(!cm.isSortable(index)){
49762 if (dm.multiSort) {
49763 // update the sortOrder
49765 for(var i = 0; i < cm.config.length; i++ ) {
49767 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
49768 continue; // dont' bother, it's not in sort list or being set.
49771 so.push(cm.config[i].dataIndex);
49777 dm.sort(cm.getDataIndex(index));
49781 destroy : function(){
49783 this.colMenu.removeAll();
49784 Roo.menu.MenuMgr.unregister(this.colMenu);
49785 this.colMenu.getEl().remove();
49786 delete this.colMenu;
49789 this.hmenu.removeAll();
49790 Roo.menu.MenuMgr.unregister(this.hmenu);
49791 this.hmenu.getEl().remove();
49794 if(this.grid.enableColumnMove){
49795 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49797 for(var dd in dds){
49798 if(!dds[dd].config.isTarget && dds[dd].dragElId){
49799 var elid = dds[dd].dragElId;
49801 Roo.get(elid).remove();
49802 } else if(dds[dd].config.isTarget){
49803 dds[dd].proxyTop.remove();
49804 dds[dd].proxyBottom.remove();
49807 if(Roo.dd.DDM.locationCache[dd]){
49808 delete Roo.dd.DDM.locationCache[dd];
49811 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
49814 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
49815 this.bind(null, null);
49816 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
49819 handleLockChange : function(){
49820 this.refresh(true);
49823 onDenyColumnLock : function(){
49827 onDenyColumnHide : function(){
49831 handleHdMenuClick : function(item){
49832 var index = this.hdCtxIndex;
49833 var cm = this.cm, ds = this.ds;
49836 ds.sort(cm.getDataIndex(index), "ASC");
49839 ds.sort(cm.getDataIndex(index), "DESC");
49842 var lc = cm.getLockedCount();
49843 if(cm.getColumnCount(true) <= lc+1){
49844 this.onDenyColumnLock();
49848 cm.setLocked(index, true, true);
49849 cm.moveColumn(index, lc);
49850 this.grid.fireEvent("columnmove", index, lc);
49852 cm.setLocked(index, true);
49856 var lc = cm.getLockedCount();
49857 if((lc-1) != index){
49858 cm.setLocked(index, false, true);
49859 cm.moveColumn(index, lc-1);
49860 this.grid.fireEvent("columnmove", index, lc-1);
49862 cm.setLocked(index, false);
49866 index = cm.getIndexById(item.id.substr(4));
49868 if(item.checked && cm.getColumnCount(true) <= 1){
49869 this.onDenyColumnHide();
49872 cm.setHidden(index, item.checked);
49878 beforeColMenuShow : function(){
49879 var cm = this.cm, colCount = cm.getColumnCount();
49880 this.colMenu.removeAll();
49881 for(var i = 0; i < colCount; i++){
49882 this.colMenu.add(new Roo.menu.CheckItem({
49883 id: "col-"+cm.getColumnId(i),
49884 text: cm.getColumnHeader(i),
49885 checked: !cm.isHidden(i),
49891 handleHdCtx : function(g, index, e){
49893 var hd = this.getHeaderCell(index);
49894 this.hdCtxIndex = index;
49895 var ms = this.hmenu.items, cm = this.cm;
49896 ms.get("asc").setDisabled(!cm.isSortable(index));
49897 ms.get("desc").setDisabled(!cm.isSortable(index));
49898 if(this.grid.enableColLock !== false){
49899 ms.get("lock").setDisabled(cm.isLocked(index));
49900 ms.get("unlock").setDisabled(!cm.isLocked(index));
49902 this.hmenu.show(hd, "tl-bl");
49905 handleHdOver : function(e){
49906 var hd = this.findHeaderCell(e.getTarget());
49907 if(hd && !this.headersDisabled){
49908 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
49909 this.fly(hd).addClass("x-grid-hd-over");
49914 handleHdOut : function(e){
49915 var hd = this.findHeaderCell(e.getTarget());
49917 this.fly(hd).removeClass("x-grid-hd-over");
49921 handleSplitDblClick : function(e, t){
49922 var i = this.getCellIndex(t);
49923 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
49924 this.autoSizeColumn(i, true);
49929 render : function(){
49932 var colCount = cm.getColumnCount();
49934 if(this.grid.monitorWindowResize === true){
49935 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49937 var header = this.renderHeaders();
49938 var body = this.templates.body.apply({rows:""});
49939 var html = this.templates.master.apply({
49942 lockedHeader: header[0],
49946 //this.updateColumns();
49948 this.grid.getGridEl().dom.innerHTML = html;
49950 this.initElements();
49952 // a kludge to fix the random scolling effect in webkit
49953 this.el.on("scroll", function() {
49954 this.el.dom.scrollTop=0; // hopefully not recursive..
49957 this.scroller.on("scroll", this.handleScroll, this);
49958 this.lockedBody.on("mousewheel", this.handleWheel, this);
49959 this.mainBody.on("mousewheel", this.handleWheel, this);
49961 this.mainHd.on("mouseover", this.handleHdOver, this);
49962 this.mainHd.on("mouseout", this.handleHdOut, this);
49963 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
49964 {delegate: "."+this.splitClass});
49966 this.lockedHd.on("mouseover", this.handleHdOver, this);
49967 this.lockedHd.on("mouseout", this.handleHdOut, this);
49968 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
49969 {delegate: "."+this.splitClass});
49971 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
49972 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49975 this.updateSplitters();
49977 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
49978 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49979 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
49982 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
49983 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
49985 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
49986 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
49988 if(this.grid.enableColLock !== false){
49989 this.hmenu.add('-',
49990 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
49991 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
49994 if(this.grid.enableColumnHide !== false){
49996 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
49997 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
49998 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
50000 this.hmenu.add('-',
50001 {id:"columns", text: this.columnsText, menu: this.colMenu}
50004 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
50006 this.grid.on("headercontextmenu", this.handleHdCtx, this);
50009 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
50010 this.dd = new Roo.grid.GridDragZone(this.grid, {
50011 ddGroup : this.grid.ddGroup || 'GridDD'
50016 for(var i = 0; i < colCount; i++){
50017 if(cm.isHidden(i)){
50018 this.hideColumn(i);
50020 if(cm.config[i].align){
50021 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
50022 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
50026 this.updateHeaderSortState();
50028 this.beforeInitialResize();
50031 // two part rendering gives faster view to the user
50032 this.renderPhase2.defer(1, this);
50035 renderPhase2 : function(){
50036 // render the rows now
50038 if(this.grid.autoSizeColumns){
50039 this.autoSizeColumns();
50043 beforeInitialResize : function(){
50047 onColumnSplitterMoved : function(i, w){
50048 this.userResized = true;
50049 var cm = this.grid.colModel;
50050 cm.setColumnWidth(i, w, true);
50051 var cid = cm.getColumnId(i);
50052 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
50053 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
50054 this.updateSplitters();
50056 this.grid.fireEvent("columnresize", i, w);
50059 syncRowHeights : function(startIndex, endIndex){
50060 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
50061 startIndex = startIndex || 0;
50062 var mrows = this.getBodyTable().rows;
50063 var lrows = this.getLockedTable().rows;
50064 var len = mrows.length-1;
50065 endIndex = Math.min(endIndex || len, len);
50066 for(var i = startIndex; i <= endIndex; i++){
50067 var m = mrows[i], l = lrows[i];
50068 var h = Math.max(m.offsetHeight, l.offsetHeight);
50069 m.style.height = l.style.height = h + "px";
50074 layout : function(initialRender, is2ndPass){
50076 var auto = g.autoHeight;
50077 var scrollOffset = 16;
50078 var c = g.getGridEl(), cm = this.cm,
50079 expandCol = g.autoExpandColumn,
50081 //c.beginMeasure();
50083 if(!c.dom.offsetWidth){ // display:none?
50085 this.lockedWrap.show();
50086 this.mainWrap.show();
50091 var hasLock = this.cm.isLocked(0);
50093 var tbh = this.headerPanel.getHeight();
50094 var bbh = this.footerPanel.getHeight();
50097 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
50098 var newHeight = ch + c.getBorderWidth("tb");
50100 newHeight = Math.min(g.maxHeight, newHeight);
50102 c.setHeight(newHeight);
50106 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
50109 var s = this.scroller;
50111 var csize = c.getSize(true);
50113 this.el.setSize(csize.width, csize.height);
50115 this.headerPanel.setWidth(csize.width);
50116 this.footerPanel.setWidth(csize.width);
50118 var hdHeight = this.mainHd.getHeight();
50119 var vw = csize.width;
50120 var vh = csize.height - (tbh + bbh);
50124 var bt = this.getBodyTable();
50125 var ltWidth = hasLock ?
50126 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
50128 var scrollHeight = bt.offsetHeight;
50129 var scrollWidth = ltWidth + bt.offsetWidth;
50130 var vscroll = false, hscroll = false;
50132 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
50134 var lw = this.lockedWrap, mw = this.mainWrap;
50135 var lb = this.lockedBody, mb = this.mainBody;
50137 setTimeout(function(){
50138 var t = s.dom.offsetTop;
50139 var w = s.dom.clientWidth,
50140 h = s.dom.clientHeight;
50143 lw.setSize(ltWidth, h);
50145 mw.setLeftTop(ltWidth, t);
50146 mw.setSize(w-ltWidth, h);
50148 lb.setHeight(h-hdHeight);
50149 mb.setHeight(h-hdHeight);
50151 if(is2ndPass !== true && !gv.userResized && expandCol){
50152 // high speed resize without full column calculation
50154 var ci = cm.getIndexById(expandCol);
50156 ci = cm.findColumnIndex(expandCol);
50158 ci = Math.max(0, ci); // make sure it's got at least the first col.
50159 var expandId = cm.getColumnId(ci);
50160 var tw = cm.getTotalWidth(false);
50161 var currentWidth = cm.getColumnWidth(ci);
50162 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
50163 if(currentWidth != cw){
50164 cm.setColumnWidth(ci, cw, true);
50165 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50166 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
50167 gv.updateSplitters();
50168 gv.layout(false, true);
50180 onWindowResize : function(){
50181 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
50187 appendFooter : function(parentEl){
50191 sortAscText : "Sort Ascending",
50192 sortDescText : "Sort Descending",
50193 lockText : "Lock Column",
50194 unlockText : "Unlock Column",
50195 columnsText : "Columns"
50199 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
50200 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
50201 this.proxy.el.addClass('x-grid3-col-dd');
50204 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
50205 handleMouseDown : function(e){
50209 callHandleMouseDown : function(e){
50210 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
50215 * Ext JS Library 1.1.1
50216 * Copyright(c) 2006-2007, Ext JS, LLC.
50218 * Originally Released Under LGPL - original licence link has changed is not relivant.
50221 * <script type="text/javascript">
50225 // This is a support class used internally by the Grid components
50226 Roo.grid.SplitDragZone = function(grid, hd, hd2){
50228 this.view = grid.getView();
50229 this.proxy = this.view.resizeProxy;
50230 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
50231 "gridSplitters" + this.grid.getGridEl().id, {
50232 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
50234 this.setHandleElId(Roo.id(hd));
50235 this.setOuterHandleElId(Roo.id(hd2));
50236 this.scroll = false;
50238 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
50239 fly: Roo.Element.fly,
50241 b4StartDrag : function(x, y){
50242 this.view.headersDisabled = true;
50243 this.proxy.setHeight(this.view.mainWrap.getHeight());
50244 var w = this.cm.getColumnWidth(this.cellIndex);
50245 var minw = Math.max(w-this.grid.minColumnWidth, 0);
50246 this.resetConstraints();
50247 this.setXConstraint(minw, 1000);
50248 this.setYConstraint(0, 0);
50249 this.minX = x - minw;
50250 this.maxX = x + 1000;
50252 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
50256 handleMouseDown : function(e){
50257 ev = Roo.EventObject.setEvent(e);
50258 var t = this.fly(ev.getTarget());
50259 if(t.hasClass("x-grid-split")){
50260 this.cellIndex = this.view.getCellIndex(t.dom);
50261 this.split = t.dom;
50262 this.cm = this.grid.colModel;
50263 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
50264 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
50269 endDrag : function(e){
50270 this.view.headersDisabled = false;
50271 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
50272 var diff = endX - this.startPos;
50273 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
50276 autoOffset : function(){
50277 this.setDelta(0,0);
50281 * Ext JS Library 1.1.1
50282 * Copyright(c) 2006-2007, Ext JS, LLC.
50284 * Originally Released Under LGPL - original licence link has changed is not relivant.
50287 * <script type="text/javascript">
50291 // This is a support class used internally by the Grid components
50292 Roo.grid.GridDragZone = function(grid, config){
50293 this.view = grid.getView();
50294 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
50295 if(this.view.lockedBody){
50296 this.setHandleElId(Roo.id(this.view.mainBody.dom));
50297 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
50299 this.scroll = false;
50301 this.ddel = document.createElement('div');
50302 this.ddel.className = 'x-grid-dd-wrap';
50305 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
50306 ddGroup : "GridDD",
50308 getDragData : function(e){
50309 var t = Roo.lib.Event.getTarget(e);
50310 var rowIndex = this.view.findRowIndex(t);
50311 if(rowIndex !== false){
50312 var sm = this.grid.selModel;
50313 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
50314 // sm.mouseDown(e, t);
50316 if (e.hasModifier()){
50317 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
50319 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
50324 onInitDrag : function(e){
50325 var data = this.dragData;
50326 this.ddel.innerHTML = this.grid.getDragDropText();
50327 this.proxy.update(this.ddel);
50328 // fire start drag?
50331 afterRepair : function(){
50332 this.dragging = false;
50335 getRepairXY : function(e, data){
50339 onEndDrag : function(data, e){
50343 onValidDrop : function(dd, e, id){
50348 beforeInvalidDrop : function(e, id){
50353 * Ext JS Library 1.1.1
50354 * Copyright(c) 2006-2007, Ext JS, LLC.
50356 * Originally Released Under LGPL - original licence link has changed is not relivant.
50359 * <script type="text/javascript">
50364 * @class Roo.grid.ColumnModel
50365 * @extends Roo.util.Observable
50366 * This is the default implementation of a ColumnModel used by the Grid. It defines
50367 * the columns in the grid.
50370 var colModel = new Roo.grid.ColumnModel([
50371 {header: "Ticker", width: 60, sortable: true, locked: true},
50372 {header: "Company Name", width: 150, sortable: true},
50373 {header: "Market Cap.", width: 100, sortable: true},
50374 {header: "$ Sales", width: 100, sortable: true, renderer: money},
50375 {header: "Employees", width: 100, sortable: true, resizable: false}
50380 * The config options listed for this class are options which may appear in each
50381 * individual column definition.
50382 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
50384 * @param {Object} config An Array of column config objects. See this class's
50385 * config objects for details.
50387 Roo.grid.ColumnModel = function(config){
50389 * The config passed into the constructor
50391 this.config = config;
50394 // if no id, create one
50395 // if the column does not have a dataIndex mapping,
50396 // map it to the order it is in the config
50397 for(var i = 0, len = config.length; i < len; i++){
50399 if(typeof c.dataIndex == "undefined"){
50402 if(typeof c.renderer == "string"){
50403 c.renderer = Roo.util.Format[c.renderer];
50405 if(typeof c.id == "undefined"){
50408 if(c.editor && c.editor.xtype){
50409 c.editor = Roo.factory(c.editor, Roo.grid);
50411 if(c.editor && c.editor.isFormField){
50412 c.editor = new Roo.grid.GridEditor(c.editor);
50414 this.lookup[c.id] = c;
50418 * The width of columns which have no width specified (defaults to 100)
50421 this.defaultWidth = 100;
50424 * Default sortable of columns which have no sortable specified (defaults to false)
50427 this.defaultSortable = false;
50431 * @event widthchange
50432 * Fires when the width of a column changes.
50433 * @param {ColumnModel} this
50434 * @param {Number} columnIndex The column index
50435 * @param {Number} newWidth The new width
50437 "widthchange": true,
50439 * @event headerchange
50440 * Fires when the text of a header changes.
50441 * @param {ColumnModel} this
50442 * @param {Number} columnIndex The column index
50443 * @param {Number} newText The new header text
50445 "headerchange": true,
50447 * @event hiddenchange
50448 * Fires when a column is hidden or "unhidden".
50449 * @param {ColumnModel} this
50450 * @param {Number} columnIndex The column index
50451 * @param {Boolean} hidden true if hidden, false otherwise
50453 "hiddenchange": true,
50455 * @event columnmoved
50456 * Fires when a column is moved.
50457 * @param {ColumnModel} this
50458 * @param {Number} oldIndex
50459 * @param {Number} newIndex
50461 "columnmoved" : true,
50463 * @event columlockchange
50464 * Fires when a column's locked state is changed
50465 * @param {ColumnModel} this
50466 * @param {Number} colIndex
50467 * @param {Boolean} locked true if locked
50469 "columnlockchange" : true
50471 Roo.grid.ColumnModel.superclass.constructor.call(this);
50473 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
50475 * @cfg {String} header The header text to display in the Grid view.
50478 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
50479 * {@link Roo.data.Record} definition from which to draw the column's value. If not
50480 * specified, the column's index is used as an index into the Record's data Array.
50483 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
50484 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
50487 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
50488 * Defaults to the value of the {@link #defaultSortable} property.
50489 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
50492 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
50495 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
50498 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
50501 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
50504 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
50505 * given the cell's data value. See {@link #setRenderer}. If not specified, the
50506 * default renderer uses the raw data value.
50509 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
50512 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
50516 * Returns the id of the column at the specified index.
50517 * @param {Number} index The column index
50518 * @return {String} the id
50520 getColumnId : function(index){
50521 return this.config[index].id;
50525 * Returns the column for a specified id.
50526 * @param {String} id The column id
50527 * @return {Object} the column
50529 getColumnById : function(id){
50530 return this.lookup[id];
50535 * Returns the column for a specified dataIndex.
50536 * @param {String} dataIndex The column dataIndex
50537 * @return {Object|Boolean} the column or false if not found
50539 getColumnByDataIndex: function(dataIndex){
50540 var index = this.findColumnIndex(dataIndex);
50541 return index > -1 ? this.config[index] : false;
50545 * Returns the index for a specified column id.
50546 * @param {String} id The column id
50547 * @return {Number} the index, or -1 if not found
50549 getIndexById : function(id){
50550 for(var i = 0, len = this.config.length; i < len; i++){
50551 if(this.config[i].id == id){
50559 * Returns the index for a specified column dataIndex.
50560 * @param {String} dataIndex The column dataIndex
50561 * @return {Number} the index, or -1 if not found
50564 findColumnIndex : function(dataIndex){
50565 for(var i = 0, len = this.config.length; i < len; i++){
50566 if(this.config[i].dataIndex == dataIndex){
50574 moveColumn : function(oldIndex, newIndex){
50575 var c = this.config[oldIndex];
50576 this.config.splice(oldIndex, 1);
50577 this.config.splice(newIndex, 0, c);
50578 this.dataMap = null;
50579 this.fireEvent("columnmoved", this, oldIndex, newIndex);
50582 isLocked : function(colIndex){
50583 return this.config[colIndex].locked === true;
50586 setLocked : function(colIndex, value, suppressEvent){
50587 if(this.isLocked(colIndex) == value){
50590 this.config[colIndex].locked = value;
50591 if(!suppressEvent){
50592 this.fireEvent("columnlockchange", this, colIndex, value);
50596 getTotalLockedWidth : function(){
50597 var totalWidth = 0;
50598 for(var i = 0; i < this.config.length; i++){
50599 if(this.isLocked(i) && !this.isHidden(i)){
50600 this.totalWidth += this.getColumnWidth(i);
50606 getLockedCount : function(){
50607 for(var i = 0, len = this.config.length; i < len; i++){
50608 if(!this.isLocked(i)){
50615 * Returns the number of columns.
50618 getColumnCount : function(visibleOnly){
50619 if(visibleOnly === true){
50621 for(var i = 0, len = this.config.length; i < len; i++){
50622 if(!this.isHidden(i)){
50628 return this.config.length;
50632 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
50633 * @param {Function} fn
50634 * @param {Object} scope (optional)
50635 * @return {Array} result
50637 getColumnsBy : function(fn, scope){
50639 for(var i = 0, len = this.config.length; i < len; i++){
50640 var c = this.config[i];
50641 if(fn.call(scope||this, c, i) === true){
50649 * Returns true if the specified column is sortable.
50650 * @param {Number} col The column index
50651 * @return {Boolean}
50653 isSortable : function(col){
50654 if(typeof this.config[col].sortable == "undefined"){
50655 return this.defaultSortable;
50657 return this.config[col].sortable;
50661 * Returns the rendering (formatting) function defined for the column.
50662 * @param {Number} col The column index.
50663 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
50665 getRenderer : function(col){
50666 if(!this.config[col].renderer){
50667 return Roo.grid.ColumnModel.defaultRenderer;
50669 return this.config[col].renderer;
50673 * Sets the rendering (formatting) function for a column.
50674 * @param {Number} col The column index
50675 * @param {Function} fn The function to use to process the cell's raw data
50676 * to return HTML markup for the grid view. The render function is called with
50677 * the following parameters:<ul>
50678 * <li>Data value.</li>
50679 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
50680 * <li>css A CSS style string to apply to the table cell.</li>
50681 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
50682 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
50683 * <li>Row index</li>
50684 * <li>Column index</li>
50685 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
50687 setRenderer : function(col, fn){
50688 this.config[col].renderer = fn;
50692 * Returns the width for the specified column.
50693 * @param {Number} col The column index
50696 getColumnWidth : function(col){
50697 return this.config[col].width * 1 || this.defaultWidth;
50701 * Sets the width for a column.
50702 * @param {Number} col The column index
50703 * @param {Number} width The new width
50705 setColumnWidth : function(col, width, suppressEvent){
50706 this.config[col].width = width;
50707 this.totalWidth = null;
50708 if(!suppressEvent){
50709 this.fireEvent("widthchange", this, col, width);
50714 * Returns the total width of all columns.
50715 * @param {Boolean} includeHidden True to include hidden column widths
50718 getTotalWidth : function(includeHidden){
50719 if(!this.totalWidth){
50720 this.totalWidth = 0;
50721 for(var i = 0, len = this.config.length; i < len; i++){
50722 if(includeHidden || !this.isHidden(i)){
50723 this.totalWidth += this.getColumnWidth(i);
50727 return this.totalWidth;
50731 * Returns the header for the specified column.
50732 * @param {Number} col The column index
50735 getColumnHeader : function(col){
50736 return this.config[col].header;
50740 * Sets the header for a column.
50741 * @param {Number} col The column index
50742 * @param {String} header The new header
50744 setColumnHeader : function(col, header){
50745 this.config[col].header = header;
50746 this.fireEvent("headerchange", this, col, header);
50750 * Returns the tooltip for the specified column.
50751 * @param {Number} col The column index
50754 getColumnTooltip : function(col){
50755 return this.config[col].tooltip;
50758 * Sets the tooltip for a column.
50759 * @param {Number} col The column index
50760 * @param {String} tooltip The new tooltip
50762 setColumnTooltip : function(col, tooltip){
50763 this.config[col].tooltip = tooltip;
50767 * Returns the dataIndex for the specified column.
50768 * @param {Number} col The column index
50771 getDataIndex : function(col){
50772 return this.config[col].dataIndex;
50776 * Sets the dataIndex for a column.
50777 * @param {Number} col The column index
50778 * @param {Number} dataIndex The new dataIndex
50780 setDataIndex : function(col, dataIndex){
50781 this.config[col].dataIndex = dataIndex;
50787 * Returns true if the cell is editable.
50788 * @param {Number} colIndex The column index
50789 * @param {Number} rowIndex The row index
50790 * @return {Boolean}
50792 isCellEditable : function(colIndex, rowIndex){
50793 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
50797 * Returns the editor defined for the cell/column.
50798 * return false or null to disable editing.
50799 * @param {Number} colIndex The column index
50800 * @param {Number} rowIndex The row index
50803 getCellEditor : function(colIndex, rowIndex){
50804 return this.config[colIndex].editor;
50808 * Sets if a column is editable.
50809 * @param {Number} col The column index
50810 * @param {Boolean} editable True if the column is editable
50812 setEditable : function(col, editable){
50813 this.config[col].editable = editable;
50818 * Returns true if the column is hidden.
50819 * @param {Number} colIndex The column index
50820 * @return {Boolean}
50822 isHidden : function(colIndex){
50823 return this.config[colIndex].hidden;
50828 * Returns true if the column width cannot be changed
50830 isFixed : function(colIndex){
50831 return this.config[colIndex].fixed;
50835 * Returns true if the column can be resized
50836 * @return {Boolean}
50838 isResizable : function(colIndex){
50839 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
50842 * Sets if a column is hidden.
50843 * @param {Number} colIndex The column index
50844 * @param {Boolean} hidden True if the column is hidden
50846 setHidden : function(colIndex, hidden){
50847 this.config[colIndex].hidden = hidden;
50848 this.totalWidth = null;
50849 this.fireEvent("hiddenchange", this, colIndex, hidden);
50853 * Sets the editor for a column.
50854 * @param {Number} col The column index
50855 * @param {Object} editor The editor object
50857 setEditor : function(col, editor){
50858 this.config[col].editor = editor;
50862 Roo.grid.ColumnModel.defaultRenderer = function(value){
50863 if(typeof value == "string" && value.length < 1){
50869 // Alias for backwards compatibility
50870 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
50873 * Ext JS Library 1.1.1
50874 * Copyright(c) 2006-2007, Ext JS, LLC.
50876 * Originally Released Under LGPL - original licence link has changed is not relivant.
50879 * <script type="text/javascript">
50883 * @class Roo.grid.AbstractSelectionModel
50884 * @extends Roo.util.Observable
50885 * Abstract base class for grid SelectionModels. It provides the interface that should be
50886 * implemented by descendant classes. This class should not be directly instantiated.
50889 Roo.grid.AbstractSelectionModel = function(){
50890 this.locked = false;
50891 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
50894 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
50895 /** @ignore Called by the grid automatically. Do not call directly. */
50896 init : function(grid){
50902 * Locks the selections.
50905 this.locked = true;
50909 * Unlocks the selections.
50911 unlock : function(){
50912 this.locked = false;
50916 * Returns true if the selections are locked.
50917 * @return {Boolean}
50919 isLocked : function(){
50920 return this.locked;
50924 * Ext JS Library 1.1.1
50925 * Copyright(c) 2006-2007, Ext JS, LLC.
50927 * Originally Released Under LGPL - original licence link has changed is not relivant.
50930 * <script type="text/javascript">
50933 * @extends Roo.grid.AbstractSelectionModel
50934 * @class Roo.grid.RowSelectionModel
50935 * The default SelectionModel used by {@link Roo.grid.Grid}.
50936 * It supports multiple selections and keyboard selection/navigation.
50938 * @param {Object} config
50940 Roo.grid.RowSelectionModel = function(config){
50941 Roo.apply(this, config);
50942 this.selections = new Roo.util.MixedCollection(false, function(o){
50947 this.lastActive = false;
50951 * @event selectionchange
50952 * Fires when the selection changes
50953 * @param {SelectionModel} this
50955 "selectionchange" : true,
50957 * @event afterselectionchange
50958 * Fires after the selection changes (eg. by key press or clicking)
50959 * @param {SelectionModel} this
50961 "afterselectionchange" : true,
50963 * @event beforerowselect
50964 * Fires when a row is selected being selected, return false to cancel.
50965 * @param {SelectionModel} this
50966 * @param {Number} rowIndex The selected index
50967 * @param {Boolean} keepExisting False if other selections will be cleared
50969 "beforerowselect" : true,
50972 * Fires when a row is selected.
50973 * @param {SelectionModel} this
50974 * @param {Number} rowIndex The selected index
50975 * @param {Roo.data.Record} r The record
50977 "rowselect" : true,
50979 * @event rowdeselect
50980 * Fires when a row is deselected.
50981 * @param {SelectionModel} this
50982 * @param {Number} rowIndex The selected index
50984 "rowdeselect" : true
50986 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
50987 this.locked = false;
50990 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
50992 * @cfg {Boolean} singleSelect
50993 * True to allow selection of only one row at a time (defaults to false)
50995 singleSelect : false,
50998 initEvents : function(){
51000 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
51001 this.grid.on("mousedown", this.handleMouseDown, this);
51002 }else{ // allow click to work like normal
51003 this.grid.on("rowclick", this.handleDragableRowClick, this);
51006 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
51007 "up" : function(e){
51009 this.selectPrevious(e.shiftKey);
51010 }else if(this.last !== false && this.lastActive !== false){
51011 var last = this.last;
51012 this.selectRange(this.last, this.lastActive-1);
51013 this.grid.getView().focusRow(this.lastActive);
51014 if(last !== false){
51018 this.selectFirstRow();
51020 this.fireEvent("afterselectionchange", this);
51022 "down" : function(e){
51024 this.selectNext(e.shiftKey);
51025 }else if(this.last !== false && this.lastActive !== false){
51026 var last = this.last;
51027 this.selectRange(this.last, this.lastActive+1);
51028 this.grid.getView().focusRow(this.lastActive);
51029 if(last !== false){
51033 this.selectFirstRow();
51035 this.fireEvent("afterselectionchange", this);
51040 var view = this.grid.view;
51041 view.on("refresh", this.onRefresh, this);
51042 view.on("rowupdated", this.onRowUpdated, this);
51043 view.on("rowremoved", this.onRemove, this);
51047 onRefresh : function(){
51048 var ds = this.grid.dataSource, i, v = this.grid.view;
51049 var s = this.selections;
51050 s.each(function(r){
51051 if((i = ds.indexOfId(r.id)) != -1){
51060 onRemove : function(v, index, r){
51061 this.selections.remove(r);
51065 onRowUpdated : function(v, index, r){
51066 if(this.isSelected(r)){
51067 v.onRowSelect(index);
51073 * @param {Array} records The records to select
51074 * @param {Boolean} keepExisting (optional) True to keep existing selections
51076 selectRecords : function(records, keepExisting){
51078 this.clearSelections();
51080 var ds = this.grid.dataSource;
51081 for(var i = 0, len = records.length; i < len; i++){
51082 this.selectRow(ds.indexOf(records[i]), true);
51087 * Gets the number of selected rows.
51090 getCount : function(){
51091 return this.selections.length;
51095 * Selects the first row in the grid.
51097 selectFirstRow : function(){
51102 * Select the last row.
51103 * @param {Boolean} keepExisting (optional) True to keep existing selections
51105 selectLastRow : function(keepExisting){
51106 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
51110 * Selects the row immediately following the last selected row.
51111 * @param {Boolean} keepExisting (optional) True to keep existing selections
51113 selectNext : function(keepExisting){
51114 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
51115 this.selectRow(this.last+1, keepExisting);
51116 this.grid.getView().focusRow(this.last);
51121 * Selects the row that precedes the last selected row.
51122 * @param {Boolean} keepExisting (optional) True to keep existing selections
51124 selectPrevious : function(keepExisting){
51126 this.selectRow(this.last-1, keepExisting);
51127 this.grid.getView().focusRow(this.last);
51132 * Returns the selected records
51133 * @return {Array} Array of selected records
51135 getSelections : function(){
51136 return [].concat(this.selections.items);
51140 * Returns the first selected record.
51143 getSelected : function(){
51144 return this.selections.itemAt(0);
51149 * Clears all selections.
51151 clearSelections : function(fast){
51152 if(this.locked) return;
51154 var ds = this.grid.dataSource;
51155 var s = this.selections;
51156 s.each(function(r){
51157 this.deselectRow(ds.indexOfId(r.id));
51161 this.selections.clear();
51168 * Selects all rows.
51170 selectAll : function(){
51171 if(this.locked) return;
51172 this.selections.clear();
51173 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
51174 this.selectRow(i, true);
51179 * Returns True if there is a selection.
51180 * @return {Boolean}
51182 hasSelection : function(){
51183 return this.selections.length > 0;
51187 * Returns True if the specified row is selected.
51188 * @param {Number/Record} record The record or index of the record to check
51189 * @return {Boolean}
51191 isSelected : function(index){
51192 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
51193 return (r && this.selections.key(r.id) ? true : false);
51197 * Returns True if the specified record id is selected.
51198 * @param {String} id The id of record to check
51199 * @return {Boolean}
51201 isIdSelected : function(id){
51202 return (this.selections.key(id) ? true : false);
51206 handleMouseDown : function(e, t){
51207 var view = this.grid.getView(), rowIndex;
51208 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
51211 if(e.shiftKey && this.last !== false){
51212 var last = this.last;
51213 this.selectRange(last, rowIndex, e.ctrlKey);
51214 this.last = last; // reset the last
51215 view.focusRow(rowIndex);
51217 var isSelected = this.isSelected(rowIndex);
51218 if(e.button !== 0 && isSelected){
51219 view.focusRow(rowIndex);
51220 }else if(e.ctrlKey && isSelected){
51221 this.deselectRow(rowIndex);
51222 }else if(!isSelected){
51223 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
51224 view.focusRow(rowIndex);
51227 this.fireEvent("afterselectionchange", this);
51230 handleDragableRowClick : function(grid, rowIndex, e)
51232 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
51233 this.selectRow(rowIndex, false);
51234 grid.view.focusRow(rowIndex);
51235 this.fireEvent("afterselectionchange", this);
51240 * Selects multiple rows.
51241 * @param {Array} rows Array of the indexes of the row to select
51242 * @param {Boolean} keepExisting (optional) True to keep existing selections
51244 selectRows : function(rows, keepExisting){
51246 this.clearSelections();
51248 for(var i = 0, len = rows.length; i < len; i++){
51249 this.selectRow(rows[i], true);
51254 * Selects a range of rows. All rows in between startRow and endRow are also selected.
51255 * @param {Number} startRow The index of the first row in the range
51256 * @param {Number} endRow The index of the last row in the range
51257 * @param {Boolean} keepExisting (optional) True to retain existing selections
51259 selectRange : function(startRow, endRow, keepExisting){
51260 if(this.locked) return;
51262 this.clearSelections();
51264 if(startRow <= endRow){
51265 for(var i = startRow; i <= endRow; i++){
51266 this.selectRow(i, true);
51269 for(var i = startRow; i >= endRow; i--){
51270 this.selectRow(i, true);
51276 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
51277 * @param {Number} startRow The index of the first row in the range
51278 * @param {Number} endRow The index of the last row in the range
51280 deselectRange : function(startRow, endRow, preventViewNotify){
51281 if(this.locked) return;
51282 for(var i = startRow; i <= endRow; i++){
51283 this.deselectRow(i, preventViewNotify);
51289 * @param {Number} row The index of the row to select
51290 * @param {Boolean} keepExisting (optional) True to keep existing selections
51292 selectRow : function(index, keepExisting, preventViewNotify){
51293 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
51294 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
51295 if(!keepExisting || this.singleSelect){
51296 this.clearSelections();
51298 var r = this.grid.dataSource.getAt(index);
51299 this.selections.add(r);
51300 this.last = this.lastActive = index;
51301 if(!preventViewNotify){
51302 this.grid.getView().onRowSelect(index);
51304 this.fireEvent("rowselect", this, index, r);
51305 this.fireEvent("selectionchange", this);
51311 * @param {Number} row The index of the row to deselect
51313 deselectRow : function(index, preventViewNotify){
51314 if(this.locked) return;
51315 if(this.last == index){
51318 if(this.lastActive == index){
51319 this.lastActive = false;
51321 var r = this.grid.dataSource.getAt(index);
51322 this.selections.remove(r);
51323 if(!preventViewNotify){
51324 this.grid.getView().onRowDeselect(index);
51326 this.fireEvent("rowdeselect", this, index);
51327 this.fireEvent("selectionchange", this);
51331 restoreLast : function(){
51333 this.last = this._last;
51338 acceptsNav : function(row, col, cm){
51339 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51343 onEditorKey : function(field, e){
51344 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
51349 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51351 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51353 }else if(k == e.ENTER && !e.ctrlKey){
51357 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
51359 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
51361 }else if(k == e.ESC){
51365 g.startEditing(newCell[0], newCell[1]);
51370 * Ext JS Library 1.1.1
51371 * Copyright(c) 2006-2007, Ext JS, LLC.
51373 * Originally Released Under LGPL - original licence link has changed is not relivant.
51376 * <script type="text/javascript">
51379 * @class Roo.grid.CellSelectionModel
51380 * @extends Roo.grid.AbstractSelectionModel
51381 * This class provides the basic implementation for cell selection in a grid.
51383 * @param {Object} config The object containing the configuration of this model.
51384 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
51386 Roo.grid.CellSelectionModel = function(config){
51387 Roo.apply(this, config);
51389 this.selection = null;
51393 * @event beforerowselect
51394 * Fires before a cell is selected.
51395 * @param {SelectionModel} this
51396 * @param {Number} rowIndex The selected row index
51397 * @param {Number} colIndex The selected cell index
51399 "beforecellselect" : true,
51401 * @event cellselect
51402 * Fires when a cell is selected.
51403 * @param {SelectionModel} this
51404 * @param {Number} rowIndex The selected row index
51405 * @param {Number} colIndex The selected cell index
51407 "cellselect" : true,
51409 * @event selectionchange
51410 * Fires when the active selection changes.
51411 * @param {SelectionModel} this
51412 * @param {Object} selection null for no selection or an object (o) with two properties
51414 <li>o.record: the record object for the row the selection is in</li>
51415 <li>o.cell: An array of [rowIndex, columnIndex]</li>
51418 "selectionchange" : true,
51421 * Fires when the tab (or enter) was pressed on the last editable cell
51422 * You can use this to trigger add new row.
51423 * @param {SelectionModel} this
51427 * @event beforeeditnext
51428 * Fires before the next editable sell is made active
51429 * You can use this to skip to another cell or fire the tabend
51430 * if you set cell to false
51431 * @param {Object} eventdata object : { cell : [ row, col ] }
51433 "beforeeditnext" : true
51435 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
51438 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
51440 enter_is_tab: false,
51443 initEvents : function(){
51444 this.grid.on("mousedown", this.handleMouseDown, this);
51445 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
51446 var view = this.grid.view;
51447 view.on("refresh", this.onViewChange, this);
51448 view.on("rowupdated", this.onRowUpdated, this);
51449 view.on("beforerowremoved", this.clearSelections, this);
51450 view.on("beforerowsinserted", this.clearSelections, this);
51451 if(this.grid.isEditor){
51452 this.grid.on("beforeedit", this.beforeEdit, this);
51457 beforeEdit : function(e){
51458 this.select(e.row, e.column, false, true, e.record);
51462 onRowUpdated : function(v, index, r){
51463 if(this.selection && this.selection.record == r){
51464 v.onCellSelect(index, this.selection.cell[1]);
51469 onViewChange : function(){
51470 this.clearSelections(true);
51474 * Returns the currently selected cell,.
51475 * @return {Array} The selected cell (row, column) or null if none selected.
51477 getSelectedCell : function(){
51478 return this.selection ? this.selection.cell : null;
51482 * Clears all selections.
51483 * @param {Boolean} true to prevent the gridview from being notified about the change.
51485 clearSelections : function(preventNotify){
51486 var s = this.selection;
51488 if(preventNotify !== true){
51489 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
51491 this.selection = null;
51492 this.fireEvent("selectionchange", this, null);
51497 * Returns true if there is a selection.
51498 * @return {Boolean}
51500 hasSelection : function(){
51501 return this.selection ? true : false;
51505 handleMouseDown : function(e, t){
51506 var v = this.grid.getView();
51507 if(this.isLocked()){
51510 var row = v.findRowIndex(t);
51511 var cell = v.findCellIndex(t);
51512 if(row !== false && cell !== false){
51513 this.select(row, cell);
51519 * @param {Number} rowIndex
51520 * @param {Number} collIndex
51522 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
51523 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
51524 this.clearSelections();
51525 r = r || this.grid.dataSource.getAt(rowIndex);
51528 cell : [rowIndex, colIndex]
51530 if(!preventViewNotify){
51531 var v = this.grid.getView();
51532 v.onCellSelect(rowIndex, colIndex);
51533 if(preventFocus !== true){
51534 v.focusCell(rowIndex, colIndex);
51537 this.fireEvent("cellselect", this, rowIndex, colIndex);
51538 this.fireEvent("selectionchange", this, this.selection);
51543 isSelectable : function(rowIndex, colIndex, cm){
51544 return !cm.isHidden(colIndex);
51548 handleKeyDown : function(e){
51549 //Roo.log('Cell Sel Model handleKeyDown');
51550 if(!e.isNavKeyPress()){
51553 var g = this.grid, s = this.selection;
51556 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
51558 this.select(cell[0], cell[1]);
51563 var walk = function(row, col, step){
51564 return g.walkCells(row, col, step, sm.isSelectable, sm);
51566 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
51573 // handled by onEditorKey
51574 if (g.isEditor && g.editing) {
51578 newCell = walk(r, c-1, -1);
51580 newCell = walk(r, c+1, 1);
51585 newCell = walk(r+1, c, 1);
51589 newCell = walk(r-1, c, -1);
51593 newCell = walk(r, c+1, 1);
51597 newCell = walk(r, c-1, -1);
51602 if(g.isEditor && !g.editing){
51603 g.startEditing(r, c);
51612 this.select(newCell[0], newCell[1]);
51618 acceptsNav : function(row, col, cm){
51619 return !cm.isHidden(col) && cm.isCellEditable(col, row);
51623 * @param {Number} field (not used) - as it's normally used as a listener
51624 * @param {Number} e - event - fake it by using
51626 * var e = Roo.EventObjectImpl.prototype;
51627 * e.keyCode = e.TAB
51631 onEditorKey : function(field, e){
51633 var k = e.getKey(),
51636 ed = g.activeEditor,
51638 ///Roo.log('onEditorKey' + k);
51641 if (this.enter_is_tab && k == e.ENTER) {
51647 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
51649 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51655 } else if(k == e.ENTER && !e.ctrlKey){
51658 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
51660 } else if(k == e.ESC){
51665 var ecall = { cell : newCell, forward : forward };
51666 this.fireEvent('beforeeditnext', ecall );
51667 newCell = ecall.cell;
51668 forward = ecall.forward;
51672 //Roo.log('next cell after edit');
51673 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
51674 } else if (forward) {
51675 // tabbed past last
51676 this.fireEvent.defer(100, this, ['tabend',this]);
51681 * Ext JS Library 1.1.1
51682 * Copyright(c) 2006-2007, Ext JS, LLC.
51684 * Originally Released Under LGPL - original licence link has changed is not relivant.
51687 * <script type="text/javascript">
51691 * @class Roo.grid.EditorGrid
51692 * @extends Roo.grid.Grid
51693 * Class for creating and editable grid.
51694 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51695 * The container MUST have some type of size defined for the grid to fill. The container will be
51696 * automatically set to position relative if it isn't already.
51697 * @param {Object} dataSource The data model to bind to
51698 * @param {Object} colModel The column model with info about this grid's columns
51700 Roo.grid.EditorGrid = function(container, config){
51701 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
51702 this.getGridEl().addClass("xedit-grid");
51704 if(!this.selModel){
51705 this.selModel = new Roo.grid.CellSelectionModel();
51708 this.activeEditor = null;
51712 * @event beforeedit
51713 * Fires before cell editing is triggered. The edit event object has the following properties <br />
51714 * <ul style="padding:5px;padding-left:16px;">
51715 * <li>grid - This grid</li>
51716 * <li>record - The record being edited</li>
51717 * <li>field - The field name being edited</li>
51718 * <li>value - The value for the field being edited.</li>
51719 * <li>row - The grid row index</li>
51720 * <li>column - The grid column index</li>
51721 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51723 * @param {Object} e An edit event (see above for description)
51725 "beforeedit" : true,
51728 * Fires after a cell is edited. <br />
51729 * <ul style="padding:5px;padding-left:16px;">
51730 * <li>grid - This grid</li>
51731 * <li>record - The record being edited</li>
51732 * <li>field - The field name being edited</li>
51733 * <li>value - The value being set</li>
51734 * <li>originalValue - The original value for the field, before the edit.</li>
51735 * <li>row - The grid row index</li>
51736 * <li>column - The grid column index</li>
51738 * @param {Object} e An edit event (see above for description)
51740 "afteredit" : true,
51742 * @event validateedit
51743 * Fires after a cell is edited, but before the value is set in the record.
51744 * You can use this to modify the value being set in the field, Return false
51745 * to cancel the change. The edit event object has the following properties <br />
51746 * <ul style="padding:5px;padding-left:16px;">
51747 * <li>editor - This editor</li>
51748 * <li>grid - This grid</li>
51749 * <li>record - The record being edited</li>
51750 * <li>field - The field name being edited</li>
51751 * <li>value - The value being set</li>
51752 * <li>originalValue - The original value for the field, before the edit.</li>
51753 * <li>row - The grid row index</li>
51754 * <li>column - The grid column index</li>
51755 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
51757 * @param {Object} e An edit event (see above for description)
51759 "validateedit" : true
51761 this.on("bodyscroll", this.stopEditing, this);
51762 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
51765 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
51767 * @cfg {Number} clicksToEdit
51768 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
51775 trackMouseOver: false, // causes very odd FF errors
51777 onCellDblClick : function(g, row, col){
51778 this.startEditing(row, col);
51781 onEditComplete : function(ed, value, startValue){
51782 this.editing = false;
51783 this.activeEditor = null;
51784 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
51786 var field = this.colModel.getDataIndex(ed.col);
51791 originalValue: startValue,
51798 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
51801 if(String(value) !== String(startValue)){
51803 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
51804 r.set(field, e.value);
51805 // if we are dealing with a combo box..
51806 // then we also set the 'name' colum to be the displayField
51807 if (ed.field.displayField && ed.field.name) {
51808 r.set(ed.field.name, ed.field.el.dom.value);
51811 delete e.cancel; //?? why!!!
51812 this.fireEvent("afteredit", e);
51815 this.fireEvent("afteredit", e); // always fire it!
51817 this.view.focusCell(ed.row, ed.col);
51821 * Starts editing the specified for the specified row/column
51822 * @param {Number} rowIndex
51823 * @param {Number} colIndex
51825 startEditing : function(row, col){
51826 this.stopEditing();
51827 if(this.colModel.isCellEditable(col, row)){
51828 this.view.ensureVisible(row, col, true);
51830 var r = this.dataSource.getAt(row);
51831 var field = this.colModel.getDataIndex(col);
51832 var cell = Roo.get(this.view.getCell(row,col));
51837 value: r.data[field],
51842 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
51843 this.editing = true;
51844 var ed = this.colModel.getCellEditor(col, row);
51850 ed.render(ed.parentEl || document.body);
51856 (function(){ // complex but required for focus issues in safari, ie and opera
51860 ed.on("complete", this.onEditComplete, this, {single: true});
51861 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
51862 this.activeEditor = ed;
51863 var v = r.data[field];
51864 ed.startEdit(this.view.getCell(row, col), v);
51865 // combo's with 'displayField and name set
51866 if (ed.field.displayField && ed.field.name) {
51867 ed.field.el.dom.value = r.data[ed.field.name];
51871 }).defer(50, this);
51877 * Stops any active editing
51879 stopEditing : function(){
51880 if(this.activeEditor){
51881 this.activeEditor.completeEdit();
51883 this.activeEditor = null;
51887 * Ext JS Library 1.1.1
51888 * Copyright(c) 2006-2007, Ext JS, LLC.
51890 * Originally Released Under LGPL - original licence link has changed is not relivant.
51893 * <script type="text/javascript">
51896 // private - not really -- you end up using it !
51897 // This is a support class used internally by the Grid components
51900 * @class Roo.grid.GridEditor
51901 * @extends Roo.Editor
51902 * Class for creating and editable grid elements.
51903 * @param {Object} config any settings (must include field)
51905 Roo.grid.GridEditor = function(field, config){
51906 if (!config && field.field) {
51908 field = Roo.factory(config.field, Roo.form);
51910 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
51911 field.monitorTab = false;
51914 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
51917 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
51920 alignment: "tl-tl",
51923 cls: "x-small-editor x-grid-editor",
51928 * Ext JS Library 1.1.1
51929 * Copyright(c) 2006-2007, Ext JS, LLC.
51931 * Originally Released Under LGPL - original licence link has changed is not relivant.
51934 * <script type="text/javascript">
51939 Roo.grid.PropertyRecord = Roo.data.Record.create([
51940 {name:'name',type:'string'}, 'value'
51944 Roo.grid.PropertyStore = function(grid, source){
51946 this.store = new Roo.data.Store({
51947 recordType : Roo.grid.PropertyRecord
51949 this.store.on('update', this.onUpdate, this);
51951 this.setSource(source);
51953 Roo.grid.PropertyStore.superclass.constructor.call(this);
51958 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
51959 setSource : function(o){
51961 this.store.removeAll();
51964 if(this.isEditableValue(o[k])){
51965 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
51968 this.store.loadRecords({records: data}, {}, true);
51971 onUpdate : function(ds, record, type){
51972 if(type == Roo.data.Record.EDIT){
51973 var v = record.data['value'];
51974 var oldValue = record.modified['value'];
51975 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
51976 this.source[record.id] = v;
51978 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
51985 getProperty : function(row){
51986 return this.store.getAt(row);
51989 isEditableValue: function(val){
51990 if(val && val instanceof Date){
51992 }else if(typeof val == 'object' || typeof val == 'function'){
51998 setValue : function(prop, value){
51999 this.source[prop] = value;
52000 this.store.getById(prop).set('value', value);
52003 getSource : function(){
52004 return this.source;
52008 Roo.grid.PropertyColumnModel = function(grid, store){
52011 g.PropertyColumnModel.superclass.constructor.call(this, [
52012 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
52013 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
52015 this.store = store;
52016 this.bselect = Roo.DomHelper.append(document.body, {
52017 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
52018 {tag: 'option', value: 'true', html: 'true'},
52019 {tag: 'option', value: 'false', html: 'false'}
52022 Roo.id(this.bselect);
52025 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
52026 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
52027 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
52028 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
52029 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
52031 this.renderCellDelegate = this.renderCell.createDelegate(this);
52032 this.renderPropDelegate = this.renderProp.createDelegate(this);
52035 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
52039 valueText : 'Value',
52041 dateFormat : 'm/j/Y',
52044 renderDate : function(dateVal){
52045 return dateVal.dateFormat(this.dateFormat);
52048 renderBool : function(bVal){
52049 return bVal ? 'true' : 'false';
52052 isCellEditable : function(colIndex, rowIndex){
52053 return colIndex == 1;
52056 getRenderer : function(col){
52058 this.renderCellDelegate : this.renderPropDelegate;
52061 renderProp : function(v){
52062 return this.getPropertyName(v);
52065 renderCell : function(val){
52067 if(val instanceof Date){
52068 rv = this.renderDate(val);
52069 }else if(typeof val == 'boolean'){
52070 rv = this.renderBool(val);
52072 return Roo.util.Format.htmlEncode(rv);
52075 getPropertyName : function(name){
52076 var pn = this.grid.propertyNames;
52077 return pn && pn[name] ? pn[name] : name;
52080 getCellEditor : function(colIndex, rowIndex){
52081 var p = this.store.getProperty(rowIndex);
52082 var n = p.data['name'], val = p.data['value'];
52084 if(typeof(this.grid.customEditors[n]) == 'string'){
52085 return this.editors[this.grid.customEditors[n]];
52087 if(typeof(this.grid.customEditors[n]) != 'undefined'){
52088 return this.grid.customEditors[n];
52090 if(val instanceof Date){
52091 return this.editors['date'];
52092 }else if(typeof val == 'number'){
52093 return this.editors['number'];
52094 }else if(typeof val == 'boolean'){
52095 return this.editors['boolean'];
52097 return this.editors['string'];
52103 * @class Roo.grid.PropertyGrid
52104 * @extends Roo.grid.EditorGrid
52105 * This class represents the interface of a component based property grid control.
52106 * <br><br>Usage:<pre><code>
52107 var grid = new Roo.grid.PropertyGrid("my-container-id", {
52115 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52116 * The container MUST have some type of size defined for the grid to fill. The container will be
52117 * automatically set to position relative if it isn't already.
52118 * @param {Object} config A config object that sets properties on this grid.
52120 Roo.grid.PropertyGrid = function(container, config){
52121 config = config || {};
52122 var store = new Roo.grid.PropertyStore(this);
52123 this.store = store;
52124 var cm = new Roo.grid.PropertyColumnModel(this, store);
52125 store.store.sort('name', 'ASC');
52126 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
52129 enableColLock:false,
52130 enableColumnMove:false,
52132 trackMouseOver: false,
52135 this.getGridEl().addClass('x-props-grid');
52136 this.lastEditRow = null;
52137 this.on('columnresize', this.onColumnResize, this);
52140 * @event beforepropertychange
52141 * Fires before a property changes (return false to stop?)
52142 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
52143 * @param {String} id Record Id
52144 * @param {String} newval New Value
52145 * @param {String} oldval Old Value
52147 "beforepropertychange": true,
52149 * @event propertychange
52150 * Fires after a property changes
52151 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
52152 * @param {String} id Record Id
52153 * @param {String} newval New Value
52154 * @param {String} oldval Old Value
52156 "propertychange": true
52158 this.customEditors = this.customEditors || {};
52160 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
52163 * @cfg {Object} customEditors map of colnames=> custom editors.
52164 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
52165 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
52166 * false disables editing of the field.
52170 * @cfg {Object} propertyNames map of property Names to their displayed value
52173 render : function(){
52174 Roo.grid.PropertyGrid.superclass.render.call(this);
52175 this.autoSize.defer(100, this);
52178 autoSize : function(){
52179 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
52181 this.view.fitColumns();
52185 onColumnResize : function(){
52186 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
52190 * Sets the data for the Grid
52191 * accepts a Key => Value object of all the elements avaiable.
52192 * @param {Object} data to appear in grid.
52194 setSource : function(source){
52195 this.store.setSource(source);
52199 * Gets all the data from the grid.
52200 * @return {Object} data data stored in grid
52202 getSource : function(){
52203 return this.store.getSource();
52207 * Ext JS Library 1.1.1
52208 * Copyright(c) 2006-2007, Ext JS, LLC.
52210 * Originally Released Under LGPL - original licence link has changed is not relivant.
52213 * <script type="text/javascript">
52217 * @class Roo.LoadMask
52218 * A simple utility class for generically masking elements while loading data. If the element being masked has
52219 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
52220 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
52221 * element's UpdateManager load indicator and will be destroyed after the initial load.
52223 * Create a new LoadMask
52224 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
52225 * @param {Object} config The config object
52227 Roo.LoadMask = function(el, config){
52228 this.el = Roo.get(el);
52229 Roo.apply(this, config);
52231 this.store.on('beforeload', this.onBeforeLoad, this);
52232 this.store.on('load', this.onLoad, this);
52233 this.store.on('loadexception', this.onLoadException, this);
52234 this.removeMask = false;
52236 var um = this.el.getUpdateManager();
52237 um.showLoadIndicator = false; // disable the default indicator
52238 um.on('beforeupdate', this.onBeforeLoad, this);
52239 um.on('update', this.onLoad, this);
52240 um.on('failure', this.onLoad, this);
52241 this.removeMask = true;
52245 Roo.LoadMask.prototype = {
52247 * @cfg {Boolean} removeMask
52248 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
52249 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
52252 * @cfg {String} msg
52253 * The text to display in a centered loading message box (defaults to 'Loading...')
52255 msg : 'Loading...',
52257 * @cfg {String} msgCls
52258 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
52260 msgCls : 'x-mask-loading',
52263 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
52269 * Disables the mask to prevent it from being displayed
52271 disable : function(){
52272 this.disabled = true;
52276 * Enables the mask so that it can be displayed
52278 enable : function(){
52279 this.disabled = false;
52282 onLoadException : function()
52284 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52285 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52287 this.el.unmask(this.removeMask);
52290 onLoad : function()
52292 this.el.unmask(this.removeMask);
52296 onBeforeLoad : function(){
52297 if(!this.disabled){
52298 this.el.mask(this.msg, this.msgCls);
52303 destroy : function(){
52305 this.store.un('beforeload', this.onBeforeLoad, this);
52306 this.store.un('load', this.onLoad, this);
52307 this.store.un('loadexception', this.onLoadException, this);
52309 var um = this.el.getUpdateManager();
52310 um.un('beforeupdate', this.onBeforeLoad, this);
52311 um.un('update', this.onLoad, this);
52312 um.un('failure', this.onLoad, this);
52317 * Ext JS Library 1.1.1
52318 * Copyright(c) 2006-2007, Ext JS, LLC.
52320 * Originally Released Under LGPL - original licence link has changed is not relivant.
52323 * <script type="text/javascript">
52328 * @class Roo.XTemplate
52329 * @extends Roo.Template
52330 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
52332 var t = new Roo.MasterTemplate(
52333 '<select name="{name}">',
52334 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
52338 // then append, applying the master template values
52341 * Supported features:
52344 * {a_variable} - output encoded.
52345 * {a_variable.format:("Y-m-d")} - call a method on the variable
52346 * {a_variable:raw} - unencoded output
52347 * {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
52348 * {a_variable:this.method_on_template(...)} - call a method on the template object.
52351 * <tpl for="a_variable or condition.."></tpl>
52352 * <tpl if="a_variable or condition"></tpl>
52353 * <tpl exec="some javascript"></tpl>
52355 * <tpl for="."></tpl> - just iterate the property..
52356 * <tpl for=".."></tpl> - iterates witht the parent (probably the template)
52360 Roo.XTemplate = function()
52362 Roo.XTemplate.superclass.constructor.apply(this, arguments);
52369 Roo.extend(Roo.XTemplate, Roo.Template, {
52373 * basic tag replacing syntax
52376 * // you can fake an object call by doing this
52380 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
52383 compile: function()
52387 s = ['<tpl>', s, '</tpl>'].join('');
52389 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
52390 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
52391 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
52392 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
52397 while(true == !!(m = s.match(re))){
52398 var m2 = m[0].match(nameRe),
52399 m3 = m[0].match(ifRe),
52400 m4 = m[0].match(execRe),
52404 name = m2 && m2[1] ? m2[1] : '';
52407 // if - puts fn into test..
52408 exp = m3 && m3[1] ? m3[1] : null;
52410 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
52414 // exec - calls a function... returns empty if true is returned.
52415 exp = m4 && m4[1] ? m4[1] : null;
52417 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
52423 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
52424 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
52425 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
52435 s = s.replace(m[0], '{xtpl'+ id + '}');
52438 for(var i = tpls.length-1; i >= 0; --i){
52439 this.compileTpl(tpls[i]);
52441 this.master = tpls[tpls.length-1];
52446 applySubTemplate : function(id, values, parent)
52448 var t = this.tpls[id];
52449 if(t.test && !t.test.call(this, values, parent)){
52452 if(t.exec && t.exec.call(this, values, parent)){
52455 var vs = t.target ? t.target.call(this, values, parent) : values;
52456 parent = t.target ? values : parent;
52457 if(t.target && vs instanceof Array){
52459 for(var i = 0, len = vs.length; i < len; i++){
52460 buf[buf.length] = t.compiled.call(this, vs[i], parent);
52462 return buf.join('');
52464 return t.compiled.call(this, vs, parent);
52467 compileTpl : function(tpl)
52469 var fm = Roo.util.Format;
52470 var useF = this.disableFormats !== true;
52471 var sep = Roo.isGecko ? "+" : ",";
52472 var fn = function(m, name, format, args){
52473 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
52474 if (typeof(format) == 'undefined') {
52475 format= 'htmlEncode';
52477 if (format == 'raw' ) {
52481 if(name.substr(0, 4) == 'xtpl'){
52482 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
52486 //if(name.indexOf('.') != -1){
52489 // v = "values['" + name + "']";
52491 if(format && useF){
52493 args = args ? ',' + args : "";
52495 if(format.substr(0, 5) != "this."){
52496 format = "fm." + format + '(';
52498 format = 'this.call("'+ format.substr(5) + '", ';
52501 return "'"+ sep + format + v + args + ")"+sep+"'";
52505 // called with xxyx.yuu:(test,test)
52507 return "'"+ sep + "("+v+" === undefined ? '' : " + v + '(' + args + "))"+sep+"'";
52509 // raw.. - :raw modifier..
52510 return "'"+ sep + "("+v+" === undefined ? '' : " + v + ")"+sep+"'";
52514 // branched to use + in gecko and [].join() in others
52516 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
52517 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
52520 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
52521 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
52522 body.push("'].join('');};};");
52523 body = body.join('');
52526 /** eval:var:zzzzzzz */
52528 Roo.log(body.replace(/\\n/,'\n'));
52533 applyTemplate : function(values){
52534 return this.master.compiled.call(this, values, {});
52535 //var s = this.subs;
52538 apply : function(){
52539 return this.applyTemplate.apply(this, arguments);
52544 Roo.XTemplate.from = function(el){
52545 el = Roo.getDom(el);
52546 return new Roo.XTemplate(el.value || el.innerHTML);
52548 * Original code for Roojs - LGPL
52549 * <script type="text/javascript">
52553 * @class Roo.XComponent
52554 * A delayed Element creator...
52555 * Or a way to group chunks of interface together.
52557 * Mypart.xyx = new Roo.XComponent({
52559 parent : 'Mypart.xyz', // empty == document.element.!!
52563 disabled : function() {}
52565 tree : function() { // return an tree of xtype declared components
52569 xtype : 'NestedLayoutPanel',
52576 * It can be used to build a big heiracy, with parent etc.
52577 * or you can just use this to render a single compoent to a dom element
52578 * MYPART.render(Roo.Element | String(id) | dom_element )
52580 * @extends Roo.util.Observable
52582 * @param cfg {Object} configuration of component
52585 Roo.XComponent = function(cfg) {
52586 Roo.apply(this, cfg);
52590 * Fires when this the componnt is built
52591 * @param {Roo.XComponent} c the component
52596 this.region = this.region || 'center'; // default..
52597 Roo.XComponent.register(this);
52598 this.modules = false;
52599 this.el = false; // where the layout goes..
52603 Roo.extend(Roo.XComponent, Roo.util.Observable, {
52606 * The created element (with Roo.factory())
52607 * @type {Roo.Layout}
52613 * for BC - use el in new code
52614 * @type {Roo.Layout}
52620 * for BC - use el in new code
52621 * @type {Roo.Layout}
52626 * @cfg {Function|boolean} disabled
52627 * If this module is disabled by some rule, return true from the funtion
52632 * @cfg {String} parent
52633 * Name of parent element which it get xtype added to..
52638 * @cfg {String} order
52639 * Used to set the order in which elements are created (usefull for multiple tabs)
52644 * @cfg {String} name
52645 * String to display while loading.
52649 * @cfg {String} region
52650 * Region to render component to (defaults to center)
52655 * @cfg {Array} items
52656 * A single item array - the first element is the root of the tree..
52657 * It's done this way to stay compatible with the Xtype system...
52663 * The method that retuns the tree of parts that make up this compoennt
52670 * render element to dom or tree
52671 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
52674 render : function(el)
52678 var hp = this.parent ? 1 : 0;
52680 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
52681 // if parent is a '#.....' string, then let's use that..
52682 var ename = this.parent.substr(1)
52683 this.parent = false;
52684 el = Roo.get(ename);
52686 Roo.log("Warning - element can not be found :#" + ename );
52692 if (!this.parent) {
52694 el = el ? Roo.get(el) : false;
52696 // it's a top level one..
52698 el : new Roo.BorderLayout(el || document.body, {
52704 tabPosition: 'top',
52705 //resizeTabs: true,
52706 alwaysShowTabs: el && hp? false : true,
52707 hideTabs: el || !hp ? true : false,
52715 // The 'tree' method is '_tree now'
52717 var tree = this._tree ? this._tree() : this.tree();
52718 tree.region = tree.region || this.region;
52719 this.el = this.parent.el.addxtype(tree);
52720 this.fireEvent('built', this);
52722 this.panel = this.el;
52723 this.layout = this.panel.layout;
52724 this.parentLayout = this.parent.layout || false;
52730 Roo.apply(Roo.XComponent, {
52733 * @property buildCompleted
52734 * True when the builder has completed building the interface.
52737 buildCompleted : false,
52740 * @property topModule
52741 * the upper most module - uses document.element as it's constructor.
52748 * @property modules
52749 * array of modules to be created by registration system.
52750 * @type {Array} of Roo.XComponent
52755 * @property elmodules
52756 * array of modules to be created by which use #ID
52757 * @type {Array} of Roo.XComponent
52764 * Register components to be built later.
52766 * This solves the following issues
52767 * - Building is not done on page load, but after an authentication process has occured.
52768 * - Interface elements are registered on page load
52769 * - Parent Interface elements may not be loaded before child, so this handles that..
52776 module : 'Pman.Tab.projectMgr',
52778 parent : 'Pman.layout',
52779 disabled : false, // or use a function..
52782 * * @param {Object} details about module
52784 register : function(obj) {
52786 Roo.XComponent.event.fireEvent('register', obj);
52787 switch(typeof(obj.disabled) ) {
52793 if ( obj.disabled() ) {
52798 if (obj.disabled) {
52804 this.modules.push(obj);
52808 * convert a string to an object..
52809 * eg. 'AAA.BBB' -> finds AAA.BBB
52813 toObject : function(str)
52815 if (!str || typeof(str) == 'object') {
52818 if (str.substring(0,1) == '#') {
52822 var ar = str.split('.');
52827 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
52829 throw "Module not found : " + str;
52833 throw "Module not found : " + str;
52835 Roo.each(ar, function(e) {
52836 if (typeof(o[e]) == 'undefined') {
52837 throw "Module not found : " + str;
52848 * move modules into their correct place in the tree..
52851 preBuild : function ()
52854 Roo.each(this.modules , function (obj)
52856 var opar = obj.parent;
52858 obj.parent = this.toObject(opar);
52860 Roo.log("parent:toObject failed: " + e.toString());
52865 Roo.debug && Roo.log("GOT top level module");
52866 Roo.debug && Roo.log(obj);
52867 obj.modules = new Roo.util.MixedCollection(false,
52868 function(o) { return o.order + '' }
52870 this.topModule = obj;
52873 // parent is a string (usually a dom element name..)
52874 if (typeof(obj.parent) == 'string') {
52875 this.elmodules.push(obj);
52878 if (obj.parent.constructor != Roo.XComponent) {
52879 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
52881 if (!obj.parent.modules) {
52882 obj.parent.modules = new Roo.util.MixedCollection(false,
52883 function(o) { return o.order + '' }
52887 obj.parent.modules.add(obj);
52892 * make a list of modules to build.
52893 * @return {Array} list of modules.
52896 buildOrder : function()
52899 var cmp = function(a,b) {
52900 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
52902 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
52903 throw "No top level modules to build";
52906 // make a flat list in order of modules to build.
52907 var mods = this.topModule ? [ this.topModule ] : [];
52909 // elmodules (is a list of DOM based modules )
52910 Roo.each(this.elmodules,function(e) { mods.push(e) });
52913 // add modules to their parents..
52914 var addMod = function(m) {
52915 Roo.debug && Roo.log("build Order: add: " + m.name);
52919 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
52920 m.modules.keySort('ASC', cmp );
52921 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
52923 m.modules.each(addMod);
52925 Roo.debug && Roo.log("build Order: no child modules");
52927 // not sure if this is used any more..
52929 m.finalize.name = m.name + " (clean up) ";
52930 mods.push(m.finalize);
52934 if (this.topModule) {
52935 this.topModule.modules.keySort('ASC', cmp );
52936 this.topModule.modules.each(addMod);
52942 * Build the registered modules.
52943 * @param {Object} parent element.
52944 * @param {Function} optional method to call after module has been added.
52952 var mods = this.buildOrder();
52954 //this.allmods = mods;
52955 //Roo.debug && Roo.log(mods);
52957 if (!mods.length) { // should not happen
52958 throw "NO modules!!!";
52962 var msg = "Building Interface...";
52963 // flash it up as modal - so we store the mask!?
52964 Roo.MessageBox.show({ title: 'loading' });
52965 Roo.MessageBox.show({
52966 title: "Please wait...",
52974 var total = mods.length;
52977 var progressRun = function() {
52978 if (!mods.length) {
52979 Roo.debug && Roo.log('hide?');
52980 Roo.MessageBox.hide();
52981 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
52987 var m = mods.shift();
52990 Roo.debug && Roo.log(m);
52991 // not sure if this is supported any more.. - modules that are are just function
52992 if (typeof(m) == 'function') {
52994 return progressRun.defer(10, _this);
52998 msg = "Building Interface " + (total - mods.length) +
53000 (m.name ? (' - ' + m.name) : '');
53001 Roo.debug && Roo.log(msg);
53002 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
53005 // is the module disabled?
53006 var disabled = (typeof(m.disabled) == 'function') ?
53007 m.disabled.call(m.module.disabled) : m.disabled;
53011 return progressRun(); // we do not update the display!
53019 // it's 10 on top level, and 1 on others??? why...
53020 return progressRun.defer(10, _this);
53023 progressRun.defer(1, _this);
53037 * wrapper for event.on - aliased later..
53038 * Typically use to register a event handler for register:
53040 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
53049 Roo.XComponent.event = new Roo.util.Observable({
53053 * Fires when an Component is registered,
53054 * set the disable property on the Component to stop registration.
53055 * @param {Roo.XComponent} c the component being registerd.
53060 * @event buildcomplete
53061 * Fires on the top level element when all elements have been built
53062 * @param {Roo.XComponent} the top level component.
53064 'buildcomplete' : true
53069 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
53070 //<script type="text/javascript">
53075 * @extends Roo.LayoutDialog
53076 * A generic Login Dialog..... - only one needed in theory!?!?
53078 * Fires XComponent builder on success...
53081 * username,password, lang = for login actions.
53082 * check = 1 for periodic checking that sesion is valid.
53083 * passwordRequest = email request password
53084 * logout = 1 = to logout
53086 * Affects: (this id="????" elements)
53087 * loading (removed) (used to indicate application is loading)
53088 * loading-mask (hides) (used to hide application when it's building loading)
53094 * Myapp.login = Roo.Login({
53110 Roo.Login = function(cfg)
53116 Roo.apply(this,cfg);
53118 Roo.onReady(function() {
53124 Roo.Login.superclass.constructor.call(this, this);
53125 //this.addxtype(this.items[0]);
53131 Roo.extend(Roo.Login, Roo.LayoutDialog, {
53134 * @cfg {String} method
53135 * Method used to query for login details.
53140 * @cfg {String} url
53141 * URL to query login data. - eg. baseURL + '/Login.php'
53147 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
53152 * @property checkFails
53153 * Number of times we have attempted to get authentication check, and failed.
53158 * @property intervalID
53159 * The window interval that does the constant login checking.
53165 onLoad : function() // called on page load...
53169 if (Roo.get('loading')) { // clear any loading indicator..
53170 Roo.get('loading').remove();
53173 //this.switchLang('en'); // set the language to english..
53176 success: function(response, opts) { // check successfull...
53178 var res = this.processResponse(response);
53179 this.checkFails =0;
53180 if (!res.success) { // error!
53181 this.checkFails = 5;
53182 //console.log('call failure');
53183 return this.failure(response,opts);
53186 if (!res.data.id) { // id=0 == login failure.
53187 return this.show();
53191 //console.log(success);
53192 this.fillAuth(res.data);
53193 this.checkFails =0;
53194 Roo.XComponent.build();
53196 failure : this.show
53202 check: function(cfg) // called every so often to refresh cookie etc..
53204 if (cfg.again) { // could be undefined..
53207 this.checkFails = 0;
53210 if (this.sending) {
53211 if ( this.checkFails > 4) {
53212 Roo.MessageBox.alert("Error",
53213 "Error getting authentication status. - try reloading, or wait a while", function() {
53214 _this.sending = false;
53219 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
53222 this.sending = true;
53229 method: this.method,
53230 success: cfg.success || this.success,
53231 failure : cfg.failure || this.failure,
53241 window.onbeforeunload = function() { }; // false does not work for IE..
53251 failure : function() {
53252 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
53253 document.location = document.location.toString() + '?ts=' + Math.random();
53257 success : function() {
53258 _this.user = false;
53259 this.checkFails =0;
53261 document.location = document.location.toString() + '?ts=' + Math.random();
53268 processResponse : function (response)
53272 res = Roo.decode(response.responseText);
53274 if (typeof(res) != 'object') {
53275 res = { success : false, errorMsg : res, errors : true };
53277 if (typeof(res.success) == 'undefined') {
53278 res.success = false;
53282 res = { success : false, errorMsg : response.responseText, errors : true };
53287 success : function(response, opts) // check successfull...
53289 this.sending = false;
53290 var res = this.processResponse(response);
53291 if (!res.success) {
53292 return this.failure(response, opts);
53294 if (!res.data || !res.data.id) {
53295 return this.failure(response,opts);
53297 //console.log(res);
53298 this.fillAuth(res.data);
53300 this.checkFails =0;
53305 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
53307 this.authUser = -1;
53308 this.sending = false;
53309 var res = this.processResponse(response);
53310 //console.log(res);
53311 if ( this.checkFails > 2) {
53313 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
53314 "Error getting authentication status. - try reloading");
53317 opts.callCfg.again = true;
53318 this.check.defer(1000, this, [ opts.callCfg ]);
53324 fillAuth: function(au) {
53325 this.startAuthCheck();
53326 this.authUserId = au.id;
53327 this.authUser = au;
53328 this.lastChecked = new Date();
53329 this.fireEvent('refreshed', au);
53330 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
53331 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
53332 au.lang = au.lang || 'en';
53333 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
53334 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
53335 this.switchLang(au.lang );
53338 // open system... - -on setyp..
53339 if (this.authUserId < 0) {
53340 Roo.MessageBox.alert("Warning",
53341 "This is an open system - please set up a admin user with a password.");
53344 //Pman.onload(); // which should do nothing if it's a re-auth result...
53349 startAuthCheck : function() // starter for timeout checking..
53351 if (this.intervalID) { // timer already in place...
53355 this.intervalID = window.setInterval(function() {
53356 _this.check(false);
53357 }, 120000); // every 120 secs = 2mins..
53363 switchLang : function (lang)
53365 _T = typeof(_T) == 'undefined' ? false : _T;
53366 if (!_T || !lang.length) {
53370 if (!_T && lang != 'en') {
53371 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53375 if (typeof(_T.en) == 'undefined') {
53377 Roo.apply(_T.en, _T);
53380 if (typeof(_T[lang]) == 'undefined') {
53381 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
53386 Roo.apply(_T, _T[lang]);
53387 // just need to set the text values for everything...
53389 /* this will not work ...
53393 function formLabel(name, val) {
53394 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
53397 formLabel('password', "Password"+':');
53398 formLabel('username', "Email Address"+':');
53399 formLabel('lang', "Language"+':');
53400 this.dialog.setTitle("Login");
53401 this.dialog.buttons[0].setText("Forgot Password");
53402 this.dialog.buttons[1].setText("Login");
53421 collapsible: false,
53423 center: { // needed??
53426 // tabPosition: 'top',
53429 alwaysShowTabs: false
53433 show : function(dlg)
53435 //console.log(this);
53436 this.form = this.layout.getRegion('center').activePanel.form;
53437 this.form.dialog = dlg;
53438 this.buttons[0].form = this.form;
53439 this.buttons[0].dialog = dlg;
53440 this.buttons[1].form = this.form;
53441 this.buttons[1].dialog = dlg;
53443 //this.resizeToLogo.defer(1000,this);
53444 // this is all related to resizing for logos..
53445 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
53447 // this.resizeToLogo.defer(1000,this);
53450 //var w = Ext.lib.Dom.getViewWidth() - 100;
53451 //var h = Ext.lib.Dom.getViewHeight() - 100;
53452 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
53454 if (this.disabled) {
53459 if (this.user.id < 0) { // used for inital setup situations.
53463 if (this.intervalID) {
53464 // remove the timer
53465 window.clearInterval(this.intervalID);
53466 this.intervalID = false;
53470 if (Roo.get('loading')) {
53471 Roo.get('loading').remove();
53473 if (Roo.get('loading-mask')) {
53474 Roo.get('loading-mask').hide();
53477 //incomming._node = tnode;
53479 //this.dialog.modal = !modal;
53480 //this.dialog.show();
53484 this.form.setValues({
53485 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
53486 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
53489 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
53490 if (this.form.findField('username').getValue().length > 0 ){
53491 this.form.findField('password').focus();
53493 this.form.findField('username').focus();
53501 xtype : 'ContentPanel',
53513 style : 'margin: 10px;',
53516 actionfailed : function(f, act) {
53517 // form can return { errors: .... }
53519 //act.result.errors // invalid form element list...
53520 //act.result.errorMsg// invalid form element list...
53522 this.dialog.el.unmask();
53523 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
53524 "Login failed - communication error - try again.");
53527 actioncomplete: function(re, act) {
53529 Roo.state.Manager.set(
53530 this.dialog.realm + '.username',
53531 this.findField('username').getValue()
53533 Roo.state.Manager.set(
53534 this.dialog.realm + '.lang',
53535 this.findField('lang').getValue()
53538 this.dialog.fillAuth(act.result.data);
53540 this.dialog.hide();
53542 if (Roo.get('loading-mask')) {
53543 Roo.get('loading-mask').show();
53545 Roo.XComponent.build();
53553 xtype : 'TextField',
53555 fieldLabel: "Email Address",
53558 autoCreate : {tag: "input", type: "text", size: "20"}
53561 xtype : 'TextField',
53563 fieldLabel: "Password",
53564 inputType: 'password',
53567 autoCreate : {tag: "input", type: "text", size: "20"},
53569 specialkey : function(e,ev) {
53570 if (ev.keyCode == 13) {
53571 this.form.dialog.el.mask("Logging in");
53572 this.form.doAction('submit', {
53573 url: this.form.dialog.url,
53574 method: this.form.dialog.method
53581 xtype : 'ComboBox',
53583 fieldLabel: "Language",
53586 xtype : 'SimpleStore',
53587 fields: ['lang', 'ldisp'],
53589 [ 'en', 'English' ],
53590 [ 'zh_HK' , '\u7E41\u4E2D' ],
53591 [ 'zh_CN', '\u7C21\u4E2D' ]
53595 valueField : 'lang',
53596 hiddenName: 'lang',
53598 displayField:'ldisp',
53602 triggerAction: 'all',
53603 emptyText:'Select a Language...',
53604 selectOnFocus:true,
53606 select : function(cb, rec, ix) {
53607 this.form.switchLang(rec.data.lang);
53623 text : "Forgot Password",
53625 click : function() {
53626 //console.log(this);
53627 var n = this.form.findField('username').getValue();
53629 Roo.MessageBox.alert("Error", "Fill in your email address");
53633 url: this.dialog.url,
53637 method: this.dialog.method,
53638 success: function(response, opts) { // check successfull...
53640 var res = this.dialog.processResponse(response);
53641 if (!res.success) { // error!
53642 Roo.MessageBox.alert("Error" ,
53643 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
53646 Roo.MessageBox.alert("Notice" ,
53647 "Please check you email for the Password Reset message");
53649 failure : function() {
53650 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
53663 click : function () {
53665 this.dialog.el.mask("Logging in");
53666 this.form.doAction('submit', {
53667 url: this.dialog.url,
53668 method: this.dialog.method